这里用c++11的stingstream实现一个
用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微秒左右;
打完收功! 以上为个人经验,希望能给大家一个参考,也希望大家多多支持易知道(ezd.cc)。