關於c++11與c風格路徑拼接的速度對比
c++11的std庫中沒有提供路徑拼接的功能
比如我需要將 "d:\\temp\\robin" 和 "..\\config.ini" 路徑拼接,
這裡用c++11的stingstream實現一個
string& replace_str(string& str, const string& to_replaced, const string& newchars) { for (string::size_type pos(0); pos != string::npos; pos += newchars.length()) { pos = str.find(to_replaced, pos); if (pos != string::npos) str.replace(pos, to_replaced.length(), newchars); else break; } return str; } // windows std::string combinePath(const char *dir, const char* name) { //printf("%s + %s\n", dir, name); if (dir == nullptr || name == nullptr) return ""; string temp = dir; replace_str(temp, "/", "\\"); std::stringstream oss(temp); std::deque<std::string> vecDir; std::deque<std::string> vecName; string part; while (std::getline(oss, part, '\\')) { if (part.length() == 0) continue; vecDir.emplace_back(part); } temp = name; replace_str(temp, "/", "\\"); oss.clear(); oss.str(temp); while (std::getline(oss, part, '\\')) { if (part.length() == 0) continue; vecName.emplace_back(part); } int index = 0; while (index < vecName.size()) { if (vecName[0] == ".") { vecName.pop_front(); } //else if (vecName[0].find("..") != vecName[0].npos) else if (vecName[0] == "..") { vecName.pop_front(); if (vecDir.size() > 1) vecDir.pop_back(); } else { vecDir.emplace_back(vecName[0]); vecName.pop_front(); } } oss.clear(); oss.str(""); for (int i=0; i<vecDir.size(); i++) { oss << vecDir[i]; if (vecDir.size() == 1 || i < (vecDir.size() - 1)) { oss << "\\"; } } return oss.str(); }
測試方法:
void test1() { cout << combinePath("d:\\temp\\robin\\", "..\\demo\\config.ini") << endl; cout << endl; cout << combinePath("d:", "..\\demo\\config.ini") << endl; cout << endl; cout << combinePath("d:\\temp\\robin", "../demo/config.ini") << endl; cout << endl; cout << combinePath("d:\\temp\\robin", "./config.ini") << endl; cout << endl; cout << combinePath("d:\\temp\\robin", "config.ini") << endl; cout << endl; cout << combinePath("d:\\temp\\robin\\", "\\config.ini") << endl; cout << endl; }
測試發現,release使用O2優化,能平均在2~4微秒左右,還是不夠快啊,
用c重新實現一遍
// 字符串范圍內,逆向查找 const char * strrfind(const char *begin, const char *end, const char c) { const char * buf = end; while (buf >= begin) { if (*buf == c) return buf; buf--; } return nullptr; } size_t combinePathC(char ** buffer, const char * dir, const char *name) { int n1 = strlen(dir); int n2 = strlen(name); size_t len = n1 + n2 + 2; char *buf = new char[len]; *buffer = buf; memcpy(buf, dir, n1); size_t len1 = n1; // 末尾保證有一個"\" if (buf[n1-1] == '\\') { len1 = n1; } else { buf[n1] = '\\'; len1 = n1+1; } buf[len1] = '\0'; // len1++示當前拼接的長度 size_t index = 0; char * rPart = (char *)name; size_t len2 = n2; while (index < n2) // 使用index向後滑動,直到末尾 { // 滑動後當前位置 rPart = (char *)name + index; char * tmp = (char *)strchr(rPart, '\\'); if (tmp == nullptr) // end here { // 拼接剩下的 len2 = n2 - index; memcpy(buf + len1, rPart, len2); len1 += len2; buf[len1] = '\0'; len1++; break; } // 當前找到的長度 len2 = tmp - rPart; if (len2 == 0) // 遇到 "\config.ini",去掉1個字符 { index += 1; } else if (len2 == 1 && rPart[0] == '.') // 遇到 ".\config.ini",去掉2個字符 { index += 2; } else if (len2 >= 2 && rPart[0] == '.') // 遇到 "..\config.ini", "..x\config.ini"去掉3個字符,末尾去掉一個目錄 { index += len2 + 1; const char * back = strrfind(buf, buf + len1 - 2 , '\\'); // 從末尾的"\"前一個字符開始找 if (back == nullptr) { // dir 當前是這樣的情況,"d:\” } else if ((back - dir) == 2) // dir 當前是這樣的情況,"d:\temp\” { len1 = 3; buf[3] = '\0'; } else // dir 當前是這樣的情況,"d:\temp\test1\” { len1 = back - buf + 1; buf[len1] = '\0'; } } else // 遇到首字符不為點 "x\config.ini", { index += len2 + 1; memcpy(buf + len1, name + index, len2 + 1); len1 += len2 + 1; } } return len1; }
測試一下:
char * buf = nullptr; size_t len; len = combinePathC(&buf, "d:\\temp\\robin\\", "config.ini"); cout << buf << endl; len = combinePathC(&buf, "d:\\temp\\robin", "config.ini"); cout << buf << endl;*/ len = combinePathC(&buf, "d:\\temp\\robin", ".\\config.ini"); cout << buf << endl; len = combinePathC(&buf, "d:\\temp\\robin", "..\\config.ini"); cout << buf << endl; len = combinePathC(&buf, "d:\\temp\\robin", "...\\config.ini"); cout << buf << endl;
測試發現,平均在0.2微秒左右;
打完收功! 以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- C++ stringstream格式化輸出輸入詳情
- 詳解如何利用C++實現Mystring類
- C++字符數組、字符數組指針和string類
- C++算法學習之貪心算法的應用
- C++右值引用與移動構造函數基礎與應用詳解