关于c++11与c风格路径拼接的速度对比
作者:飞鸟真人
这篇文章主要介绍了关于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微秒左右;
打完收功! 以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。