Linux中的fopen(Lubuntu)在文件存在时返回NULL

时间:2013-07-26 01:12:57

标签: c++ c ubuntu fopen

我在使用Oracle Lubuntu的虚拟机中VirtualBox上运行此功能。我认为这不会影响任何事情,但我认为值得一提。

看来错误是从附加到以下函数返回的字符串末尾的奇怪符号出现的:

inline std::string f_settings_get(std::string val){
    int index=0;
    while(strcmp(val.c_str(),f_settings[0][index].c_str())!=0){
        index++;
    };
    // For debugging purposes - printf("\n%s\t%s",f_settings[0][index].c_str(),f_settings[1][index].c_str());
    return f_settings[1][index];
}

我看不出这个函数的问题,因此认为它可能是由存储在变量中的数据引起的。

我一直在尝试使用fopen在我的程序中打开一个文件,并且遇到了标题中声明的错误。该代码在Windows中完美运行(我已经为每个操作系统考虑了/\;但是,当在Linux上运行时,尽管编译完美,但我得到的错误是该文件不存在。我在网上查了一下,发现了其他几个问题,如:

  1. The filename is not REALLY the right filename

  2. Permission to access file was not there

  3. Accessing the file was done by just calling "file.txt" instead of the whole directory

  4. 我使用提供的Python脚本检查了第一个,然后使用新名称重新创建文件。这不起作用(Python脚本显示文件名很好)。

    我使用chmod -R 777 clesis将所有权限设置为777并且不起作用(尽管我不认为它是权限问题,因为它说该文件不存在)。

    我已经调用了完整路径并仔细检查了路径。这是对的。

    最后,我在代码中运行以下内容以仔细检查:(a)文件是否存在以及(b)我试图打开正确的文件。

        tmp_s="";
        tmp_s = homeDir+binP+f_settings_get("xxxxx"); // Note, you can easily get whatever variable you want using either f_settings_get or num_settings_get
        tmp_file = fopen(tmp_s.c_str(), "r+");
        printf("\n Running the following command: /home/xxxxx/programming/xxxxx/bin\n");
        std::system("ls -l /home/xxxxx/programming/xxxxx/bin");
        getWait();
        printf("\n Tried to open: %s", tmp_s.c_str());
        if (tmp_file == NULL){
            printf("\n");
            perror("Error loading dimensions.sim");
            printf("Press enter to exit...");
            getWait();
            exit(1);
        }
    

    以下是输出的外观(抱歉审查事情。我向你保证用户名和文件夹拼写相同):

    输出显示以下内容:

    Filenames Loaded...
    
    Loading Settings from sim file...
    ++++++++++++++++++++++++++++++++++++++++++++++++++ Settings Loaded...
    
    Loading System Dimensions from sys file...
    --------------------------------------------------
     Running the following command: /home/xxxxx/programming/xxxxx/bin
    total 636
    -rwxrwxrwx 1 xxxxx xxxxx    958 Jul 25 20:59 dimensions.sim
    
    Tried to open: /home/xxxxx/programming/xxxxx/bin/dimensions.sim
    
    Error loading dimensions.sim: No such file or directory
    Press enter to exit...
    

    如果文件路径直接指定为“bin / dimensions.sim”或“/home/xxxxx/programming/xxxxx/bin/dimensions.sim”,那么它可以正常工作。这让我得出一个混乱的结论。在将tmp_sstd::string转换为c_str的某个位置存在导致错误目录路径的问题。但是,我使用的任何其他文件都不会出现这种情况,我在Windows机器上从未遇到此问题。因此,我对可能导致它的原因感到困惑。

    最后一次观察 - 无论如何使用printf("tmps = %s",tmp_s.c_str());打印出转换。可以清楚地看出这并不“奇怪”。

1 个答案:

答案 0 :(得分:4)

您的问题很可能来自杂散回车(十六进制0D,通常在C中写为\r),这在使用unix-y库读取windows-y文件时很常见。 Windows文件的行以CR-LF(十六进制0D0A)终止,而unix只使用单个LF,十六进制0A。对于未以二进制模式打开的文件,Windows C stdio会将CRLF映射到单个LF(\n)。在Unix中,无论文件是以二进制还是ASCII模式打开都没关系,因为不会发生重映射。

结果是在Windows程序上编译的同一程序可以读取Windows文件,在Unix上编译可以读取Unix文件;在这两种情况下,行终止符看起来都像一个\n。 Windows程序通常也可以读取Unix文件。但是读取Windows文件的Unix程序会在每一行的末尾看到一个流浪的CR,\r,十六进制0D

这特别困扰配置实用程序。假设您有一个以下形式的配置文件:

some_setting=27
some_file=dimensions.sim

现在,配置阅读器读取每一行,在=处将其拆分,并将第一部分用作键,第二部分用作值。它甚至可能将一些值转换为数字。

现在,如果文件是在Windows上创建的(无论它当前是在Windows上还是在笔记本电脑上),Unix配置阅读器会将some_setting的值视为{{1} } 27\r的值为some_file。第一个不会导致任何问题,除非配置系统是偏执的,因为dimensions.sim\ratoi转换为第一个非数字字符,并且只要至少存在就不会抱怨一位数。但是字符串不能用作文件名,因为文件名最后不可能有strtod

这个问题特别阴险的原因在于,当你试图打印出违规的字符串时,\r实际上就像回车一样;也就是说,它将光标返回到行的开头。如果下一个输出字符为\r,则\n完全不可见。如果下一个输出是某个消息,它将被覆盖在线上,这非常令人困惑。