我正在处理涉及从路径加载文件的代码,该路径构造为从另一个文件加载的给定“基本”路径和辅助相对路径的连接。例如(在我遇到问题的地方),基本路径是“ assets / models /”,辅助路径是“ maps \ map.png”。 这两个字符串的直接串联给出“ assets / models / maps \ map.png”。在POSIX系统上运行时,此加载失败。到目前为止,我一直在通过将反斜杠替换为正斜杠
std::replace( path.begin(), path.end(), '\\', '/' );
但是我想使用C ++ 17的std::filesystem::path
来代替。
std::filesystem::path::make_preferred()
的说明建议应替换分隔符:
“将路径的通用格式视图中的所有目录分隔符转换为首选目录分隔符。 例如,在Windows上,\是首选的分隔符,路径foo / bar将被转换为foo \ bar“
但是在代码中实现时,它不会转换任何内容。我还验证了std :: filesystem :: path :: preferred_separator符合预期-'/'。
我误解了make_preferred()
的目的吗?还是我使用错了?
这是无法使用的简化代码版本(这不是已实现的代码,但足够接近):
const char * loadedPath = "maps\\map.png"
std::string loadedPathStr = std::string( loadedPath );
auto wPath = std::filesystem::path( loadedPathStr );
wPath = wPath.make_preferred();
basePath = std::filesystem::path( "./a/b/" );
auto totalPath = basePath / wPath;
auto wStr = totalPath.generic_string();
std::cout << wStr << std::endl;
这将输出“ ./a/b/maps\\map.png”
在调试实现的代码时,似乎wPath
已被优化;无法对其进行检查。
奇怪的是,当我编译并运行此独立测试程序时,它可以按预期工作:
int main(){
assert( std::filesystem::path::preferred_separator == '/' );
const char * cPath = "maps\\map.png";
std::string path = std::string( cPath );
auto wPath = std::filesystem::path( path );
wPath = wPath.make_preferred();
std::string wStr = wPath.generic_string();
std::cout << wStr << std::endl;
}
这将输出“ maps / map.png”。我看不懂。这也会输出不正确的值。
有人知道这是怎么回事吗?
编辑:
尝试使用clang进行编译(之前使用gcc),并且按预期方式工作(转换了分隔符)。忽略这一点,在重新编译时出错。
我正在Linux上运行它,并且路径存在。
答案 0 :(得分:3)
我误解了
make_preferred()
的目的吗?
不完全是,但巧妙地是。目录分隔符(通用格式)是首选分隔符,还是后备分隔符:/
。在首选分隔符为/
(例如POSIX)的系统上,目录分隔符仅为/
。在这样的系统上,make_preferred
不会修改路径,这说明了为什么会对其进行完全优化。
用正斜杠替换反斜杠的最简单方法是std::replace
。但是,请注意,反斜杠是POSIX文件名中的有效字符,因此这种转换可能会中断使用它的文件名的使用。
答案 1 :(得分:1)
如果要使用filesystem
编写跨平台代码,则应尝试使用通用格式。所有其他格式的文件系统字符串的行为都取决于实现。
允许替代目录分隔符的实现会将其视为目录分隔符。但是其他无法识别分隔符的完全有效的实现将无法识别它们。 “ /”始终是目录分隔符; “ \”是否为分隔符取决于实现。
make_preferred
从实现的路径格式转换为通用格式。因此,它的行为取决于实现。
处理非通用格式的主要原因是从本机OS API获取路径字符串时。这样的路径字符串可能采用实现的格式,因此path
需要能够识别它们并使用它们。对于程序中内置的字符串文字,您应该始终喜欢通用格式(除非您的应用程序是特定于操作系统的,或者您要根据使用代码的操作系统来选择不同的字符串)。