【问题标题】:Difference between files written in binary and text mode以二进制和文本模式编写的文件之间的区别
【发布时间】:2021-12-20 12:30:17
【问题描述】:

当写入以文本模式打开但不以二进制模式发生的文件时,会发生什么转换?特别是在 MS Visual C 中。

unsigned char buffer[256];
for (int i = 0; i < 256; i++) buffer[i]=i;
int size  = 1;
int count = 256;

二进制模式:

FILE *fp_binary = fopen(filename, "wb");
fwrite(buffer, size, count, fp_binary);

与文本模式:

FILE *fp_text = fopen(filename, "wt");
fwrite(buffer, size, count, fp_text);

【问题讨论】:

标签: c++ c file-io


【解决方案1】:

尽管这个问题已经得到解答并得到了清楚的解释,但我认为用一个简单的代码示例来展示主要问题(\n 和 \r\n 之间的翻译)会很有趣。请注意,我没有解决文件末尾的 Crtl-Z 字符的问题。

#include <stdio.h>
#include <string.h>

int main() {
    FILE *f;
    char string[] = "A\nB";
    int len;
    
    len = strlen(string);
    printf("As you'd expect string has %d characters... ", len); /* prints 3*/
    f = fopen("test.txt", "w"); /* Text mode */
    fwrite(string, 1, len, f);  /* On windows "A\r\nB" is writen */
    printf ("but %ld bytes were writen to file", ftell(f)); /* prints 4 on Windows, 3 on Linux*/ 
    fclose(f);
    return 0;
}

如果您在 Windows 上执行该程序,您将看到打印以下消息:

As you'd expect string has 3 characters... but 4 bytes were writen to file

当然,您也可以使用 Notepad++ 等文本编辑器打开文件,然后查看字符:

在 Windows 上以文本模式读取文件时执行逆变换。

【讨论】:

    【解决方案2】:

    在'w'模式下,文件以写模式打开,基本编码是'utf-8' 在'wb'模式下,文件以write -binary模式打开,它可以写入其他特殊字符,编码可能是'utf-16le'或其他

    【讨论】:

      【解决方案3】:

      另一个区别是使用fseek

      如果流以二进制模式打开,如果 origin 是 SEEK_SET,则新位置正好是从文件开头测量的偏移字节,如果 origin 是 SEEK_CUR,则从当前文件位置测量,如果 origin 从文件末尾测量是 SEEK_END。某些二进制流可能不支持 SEEK_END。

      如果流以文本模式打开,唯一支持的 offset 值是零(适用于任何来源)和先前对与同一文件关联的流上的 std::ftell 调用返回的值(仅适用于 SEEK_SET 的来源。

      【讨论】:

        【解决方案4】:

        我相信大多数平台在处理流时都会忽略“t”选项或“text-mode”选项。但是,在 Windows 上,情况并非如此。如果您查看MSDN 处对 fopen() 函数的描述,您会发现指定“t”选项将具有以下效果:

        • 换行符 ('\n') 将在输出时转换为 '\r\n" 序列
        • 回车/换行序列将在输入时转换为换行。
        • 如果文件以追加模式打开,将检查文件末尾是否有 ctrl-z 字符(字符 26),如果可能,删除该字符。它还将将该字符的存在解释为文件的结尾。这是 CPM 时代的不幸遗留物(关于父母的罪孽被探视到他们的孩子直到第三或第四代)。与之前的观点相反,不会附加 ctrl-z 字符。

        【讨论】:

        • 回车实际上是'\r','\n'是换行。
        • 对各种文件操作都有这种行为吗?例如。 fread 和 fwrite(主要用于二进制文件)?
        • 翻译是在文件句柄打开时指定的,并且发生在低级别。无论您使用什么函数来读取(或写入)文件,它都会发生。
        • @Cheersandhth.-Alf -1 重复了 4 年前已经说过的话。
        • @Prakhar Agrawal:我记得,CR 和 LF 代码可以追溯到电传打字机时代。将发送回车(“\r”)代码使机器将打印头返回到行上的起始位置,并发送换行(“\n”)以将压板向前推进一行。这些概念在终端仿真器中得到了继承,即使它们在很大程度上失去了作为物理等价物的意义。
        【解决方案5】:

        我们在以文本模式打开文件时遇到了一个有趣的问题,其中文件混合了行尾字符:

        1\n\r
        2\n\r
        3\n
        4\n\r
        5\n\r
        

        我们的要求是我们可以将当前位置存储在文件中(我们使用 fgetpos),关闭文件,然后再重新打开文件并寻找该位置(我们使用 fsetpos)。

        但是,如果文件混合了行尾,则此过程无法找到实际的相同位置。在我们的例子中(我们的工具解析 C++),我们正在重新读取我们已经看过的部分文件。

        使用二进制文件 - 然后您可以准确控制从文件中读取和写入的内容。

        【讨论】:

          【解决方案6】:

          此外,当您使用“rt”打开文件时,输入将在 Crtl-Z 字符处终止。

          【讨论】:

          • True - 我让我自己的文件格式以“my-file-type^Z”之类的开头,然后如果你从命令行“输入”/“cat”它,它只会给你文件的“幻数”并停止而不是向您的终端发送二进制文件。
          【解决方案7】:

          在文本模式下,换行符“\n”可以转换为回车+换行符“\r\n”

          通常您会希望以二进制模式打开。试图以文本模式读取任何二进制数据都行不通,它会被损坏。您可以在二进制模式下正常阅读文本 - 它只是不会自动将“\n”翻译成“\r\n”。

          fopen

          【讨论】:

          • 对于阅读,翻译的工作与您描述的相反 - 将“\r\n”转换为“\n”。
          • techtonik:所有平台都允许您指定文本模式,但在 unix/linux 上与二进制模式没有什么不同。只有在 Windows 上才会有所作为。 (可能还有一些更晦涩的平台——你必须检查你的平台文档才能确定)
          猜你喜欢
          • 1970-01-01
          • 2014-09-27
          • 1970-01-01
          • 2011-08-27
          • 1970-01-01
          • 2014-03-01
          • 2013-08-02
          • 1970-01-01
          相关资源
          最近更新 更多