c++ - Windows和Linux之间的相对路径分辨率差异?

标签 c++ linux windows fopen relative-path

给定CWD中的text.txt文件,我从fopen()到“此文件是否存在?”这个问题得到了两个不同的答案。对于a/b/../../test.txt(减少为test.txt):

  • Windows:文件存在
  • Linux:文件不存在(!)

  • 但是,如果我随后使用mkdir -p a/b,Linux会更改其音调并说a/b/../../test.txt现在存在。

    好像Linux在处理相对路径时检查每个目录是否存在(如果没有,则检查早期目录),而不是先折叠../的所有目录,然后像Windows一样进行文件存在检查。

    两个问题:
  • 在这种情况下,如何使Linux表现得像Windows?像某种环境变量来修改glibc/syscall行为。
  • fopen()在这样的相对路径下应该如何表现?我可以找到的有关fopen()的文档/说明只是表明它接受了相对路径(也许有一些示例),而不是在中间路径../的情况下应如何解析这些路径。

  • 测试程序:

    #include <filesystem>
    #include <fstream>
    #include <iostream>
    #include <cstdio>
    
    void file_exists( const char* filename )
    {
        FILE* file = fopen( filename, "r" );
        std::cout << ( file ? "Y" : "N" ) << ": " << filename << std::endl;
        if( file )
        {
            fclose( file );
        }
    }
    
    int main( int, char** )
    {
        // initial tests
        std::filesystem::remove( "test.txt" );
        std::filesystem::remove( "doesnt-exist.txt" );
        file_exists( "test.txt" );
        file_exists( "doesnt-exist.txt" );
        std::cout << std::endl;
    
        // create file
        std::cout << "creating text.txt..." << std::endl;
        std::ofstream output( "test.txt", std::ios::trunc );
        output << "test" << std::endl;
        output.close();
    
        // more tests
        file_exists( "test.txt" );
        file_exists( "doesnt-exist.txt" );
        file_exists( "a/b/../../test.txt" );
        file_exists( "a/b/../../doesnt-exist.txt" );
        std::cout << std::endl;
    
        std::cout << "creating directory 'a/b'..." << std::endl;
        std::filesystem::create_directories( "a/b" );
        file_exists( "a/b/../../test.txt" );
        file_exists( "a/b/../../doesnt-exist.txt" );
        std::cout << std::endl;
    
        // cleanup
        std::filesystem::remove( "test.txt" );
        std::filesystem::remove_all( "a/b" );
    
        return 0;
    }
    

    结果:
  • Windows 10,VS2017:

    N: test.txt
    N: doesnt-exist.txt
    
    creating text.txt...
    Y: test.txt
    N: doesnt-exist.txt
    Y: a/b/../../test.txt          # file exists, expected behavior
    N: a/b/../../doesnt-exist.txt
    
    creating directory 'a/b'...
    Y: a/b/../../test.txt
    N: a/b/../../doesnt-exist.txt
    
  • Ubuntu 20.04,g++ (Ubuntu 9.3.0-10ubuntu2) 9.3.0
    N: test.txt
    N: doesnt-exist.txt
    
    creating text.txt...
    Y: test.txt
    N: doesnt-exist.txt
    N: a/b/../../test.txt          # file *doesn't* exist, unexpected behavior
    N: a/b/../../doesnt-exist.txt
    
    creating directory 'a/b'...
    Y: a/b/../../test.txt
    N: a/b/../../doesnt-exist.txt 
    
  • 最佳答案

    文件名和路径名是特定于实现的。当您意识到C:X在Linux和Windows中是完全有效的文件名,但含义却大不相同时,这显然很有意义。

    在Linux(如UNIX)上,..是真实目录条目。也就是说,a/b/../../涉及4个真实目录条目:显然是a和b,但是b中的..和a中的..fopen不需要做任何特殊的事情:操作系统只检查实际的目录条目。

    在Windows上,必须首先将路径a/b/../../转换为标准格式。也就是说,它应该以\??\开头。您可能以前没有看过这些路径,但是它们是Windows内部使用的路径。所有这些路径都是绝对路径,并且这些始终包含反斜杠。因此,从a/b/../../进行的转换涉及为当前工作的驱动器和目录添加前缀,用\替换/并删除..
    如您所见,这些是解决..的完全不同的方法。您的fopen调用通常遵循本地约定,通常只需将字符串传递给OS。 (但是,在Windows上,fopen可能也预先进行了/\转换,只是为了确定。)

    如果另一个操作系统选择^表示“父目录”,则您希望fopen("a/b/^/^")也遵循该约定,因此..并不是一个特殊的字符串。在这样的平台上,..甚至可能是子目录的有效名称。

    关于c++ - Windows和Linux之间的相对路径分辨率差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62327748/

    相关文章:

    c++ - 使用迭代而不是递归的拓扑排序

    c++ - 如何快速摆脱 std::cout

    c++ - ASCII 颜色到 HEX 颜色

    linux - Pam 配置文件条件执行语句

    linux - 使用 shell 脚本制作文件的多个副本

    windows - ffmpeg 如何将音频转换为 aac 但保持旧文件使用的比特率?

    ios - 使用 iFunbox、iTunes 在 iphone 上安装 IPA 文件

    c++ - 使用 Windows 内置的 MP3 解码器播放音频?

    python - 无法导入 python 扩展

    linux - 如何在 Linux 中查找所有以 .rb 结尾的文件?