问题

如何解决windows上用fwrite()向文件写入内容时末尾的 问题?

回答
在 Windows 系统上使用 C/C++ 语言中的 `fwrite()` 函数向文件写入内容时,遇到末尾自动添加 ` `(回车换行符)的问题,这通常是由于文件是以文本模式(text mode)打开导致的。Windows 系统在文本模式下,会将每个单独的换行符 ` ` 自动转换成 ` `(回车符 + 换行符)的组合,以此来兼容 DOS/Windows 的文件行结束符标准。

如果你希望写入的内容保持原样,不经过这种自动转换,特别是当你需要写入二进制数据,或者希望精确控制行结束符时,就需要采取一些措施。

下面我将详细讲解如何解决这个问题,并尽量避免 AI 写作的痕迹:

理解问题根源:文本模式 vs. 二进制模式

问题的核心在于你打开文件的方式。C/C++ 中的文件操作函数(如 `fopen()`)允许你指定文件的打开模式。

文本模式 (text mode):
当你使用 `"w"` (写入), `"r"` (读取), `"a"` (追加), `"w+"`, `"r+"`, `"a+"` 等模式打开文件时,如果没有明确指定为二进制,系统默认会将其视为文本模式。
在文本模式下,输入/输出操作会进行一些转换,最常见的就是 ` ` 到 ` ` 的转换(写入时)和 ` ` 到 ` ` 的转换(读取时)。这主要是为了让程序能在不同操作系统(如 Unixlike 系统使用 ` `,Windows 使用 ` `)之间更好地兼容。
缺点: 如果你写入的是纯粹的二进制数据,或者你希望精确控制行结束符,这种自动转换就会带来麻烦,可能导致数据损坏或格式错误。

二进制模式 (binary mode):
当你使用 `"wb"`, `"rb"`, `"ab"`, `"wb+"`, `"rb+"`, `"ab+"` 等模式打开文件时,文件就被视为二进制文件。
在二进制模式下,不会进行任何特殊的字符转换。你写入什么,文件就存储什么;文件读取什么,程序就得到什么。` ` 就是 ` `,` ` 就是 ` `,它们被当作普通的字节来处理。
优点: 保证数据的完整性,精确控制输出,适用于处理图片、音频、可执行文件或任何非文本数据。

解决方案:以二进制模式打开文件

解决 `fwrite()` 写入时末尾出现 ` ` 的最直接、最根本的方法,就是将文件以二进制模式打开。

步骤:

1. 修改 `fopen()` 调用:
将你原来用于打开文件的模式字符串,在末尾加上 `'b'`。

错误示例(文本模式):
```c
FILE fp = fopen("mydata.txt", "w"); // 默认是文本模式
if (fp == NULL) {
perror("Error opening file");
return 1;
}
```

正确示例(二进制模式):
```c
FILE fp = fopen("mydata.txt", "wb"); // 以二进制写入模式打开
if (fp == NULL) {
perror("Error opening file");
return 1;
}
```
如果你是追加内容,就用 `"ab"`;如果是读写,就用 `"wb+"`、`"rb+"`、`"ab+"` 等,始终加上 `'b'`。

2. 使用 `fwrite()` 写入数据:
`fwrite()` 函数本身不需要做任何改变。它的行为是按照文件当前的打开模式来工作的。

```c
const char data = "Hello, world! "; // 这是一个包含换行符的字符串
size_t bytes_written = fwrite(data, 1, strlen(data), fp);
if (bytes_written < strlen(data)) {
perror("Error writing to file");
}
```

3. 关闭文件:
最后别忘了关闭文件。

```c
fclose(fp);
```

为什么这能解决问题?

当文件以 `"wb"`(二进制写入)模式打开后,`fopen()` 函数会告诉操作系统:“我将要往这个文件里写数据,但请不要对数据做任何转换,就像处理原始字节一样。”

因此,当你 `fwrite()` 一个包含 ` ` 的字符串时,`fwrite()` 会直接将 ` ` 的ASCII码(十进制10,十六进制0x0A)写入文件。文件系统中,它就是 `0x0A`,而不是被 Windows 文本模式驱动程序截获并转换为 `0x0D0A`(` `)。

另一种情况:你确实想在文本模式下控制 ` `

偶尔,你可能确实需要以文本模式打开文件,但又想避免 `fwrite()` 自动添加 ` `。这比较少见,因为通常文本模式就是为了那种自动转换。但如果你必须这样做,可以考虑以下方式(注意:这通常不是推荐的做法,直接使用二进制模式更干净):

方法一:写入 ` ` 本身(如果你的源数据不是 ` `)

如果你想确保写入的是 ` `,并且你的源数据里只有 ` `,那么在文本模式下,你只需要写入 ` `,系统会自动帮你加上 ` `。
反之,如果你源数据里就包含了 ` `,然后你在文本模式下写入,那么 ` ` 可能会变成 ` `。

方法二:手动构建 ` `(不推荐,容易出错)

如果你在文本模式下,发现 `fwrite()` 写入 ` ` 时自动加了 ` `,但你又想写入单独的 ` ` 或者其他控制字符,并且不想被转换,这是非常困难的,因为文本模式的转换是底层的。
实际上,如果你想精确控制,你就不应该使用文本模式。

方法三:使用 `fputc` 或 `putc` 逐个字符写入(不推荐,效率低)

你可以尝试逐个字符地写入,但在文本模式下,` ` 依然会被转换。

```c
// 仍然在文本模式下,这并不能真正解决问题, 仍会被转换
FILE fp = fopen("mydata.txt", "w");
if (fp) {
const char str = "Hello World";
for (int i = 0; str[i] != ''; ++i) {
fputc(str[i], fp); // 依然可能被转换为
}
fclose(fp);
}
```

总结与最佳实践

核心原则: 如果你关心写入数据的精确字节表示,或者需要处理非文本数据,务必使用二进制模式 (`"wb"`, `"rb"`, `"ab"`) 打开文件。
`fwrite()` 的行为: `fwrite()` 本身是直接操作字节的。它是否会转换 ` ` 取决于文件是以何种模式打开的。
Windows 文本模式的特性: 了解 ` ` 会被转换为 ` ` 是关键。
避免不必要的复杂性: 不要试图在文本模式下“绕过”这种转换,直接使用二进制模式是最简单、最可靠的解决方案。

举个例子说明为什么有时候你会遇到这个问题,而有时候又不会:

如果你写一个简单的 C 程序,向一个 `.txt` 文件写入几行文字,然后你用记事本打开它,你会看到正常的换行。这说明文本模式的转换在这里起了作用。

```c
include
include

int main() {
FILE fp = fopen("sample.txt", "w"); // 文本模式
if (fp == NULL) {
perror("Error opening file");
return 1;
}

const char line1 = "First line.";
const char line2 = "Second line. "; // 注意这里有
const char line3 = "Third line.";

fwrite(line1, 1, strlen(line1), fp);
fputc(' ', fp); // 写入一个

fwrite(line2, 1, strlen(line2), fp); // 写入一个带 的字符串

fwrite(line3, 1, strlen(line3), fp);
fputc(' ', fp); // 再写入一个

fclose(fp);
printf("Data written to sample.txt in text mode. ");
return 0;
}
```
当你打开 `sample.txt` 时,你会看到:
```
First line.
Second line.
Third line.
```
记事本可能会正确显示,因为它知道如何处理 ` `。但如果你用十六进制编辑器查看 `sample.txt`,你会发现 `Second line.` 和 `Third line.` 后面跟着的 `0D 0A`(` `),而 `First line.` 后面虽然你只写了一个 ` ` (0A),但它也被变成了 `0D 0A`。

现在,如果我们改为二进制模式:

```c
include
include

int main() {
FILE fp = fopen("sample_binary.txt", "wb"); // 二进制模式
if (fp == NULL) {
perror("Error opening file");
return 1;
}

const char line1 = "First line.";
const char line2 = "Second line. "; // 注意这里有
const char line3 = "Third line.";

fwrite(line1, 1, strlen(line1), fp);
fputc(' ', fp); // 写入一个

fwrite(line2, 1, strlen(line2), fp); // 写入一个带 的字符串

fwrite(line3, 1, strlen(line3), fp);
fputc(' ', fp); // 再写入一个

fclose(fp);
printf("Data written to sample_binary.txt in binary mode. ");
return 0;
}
```
当你用十六进制编辑器查看 `sample_binary.txt` 时,你会发现 `First line.` 后面是 `0A`,`Second line.` 后面是 `0A`,`Third line.` 后面也是 `0A`。Windows 的文本编辑器(如记事本)在打开这个文件时,可能会将这些单独的 `0A` 显示为换行。

这就是核心的区别。所以,当你觉得 `fwrite` 多写了 ` ` 的时候,请检查你的文件打开模式,并切换到二进制模式。

网友意见

user avatar

这个问题思考方式和方向不太正常,题目问的不明所以,问题描述所展现的也和题目描述不一致。特别是问题描述中提到:

“打开test.txt文件,发现文件末尾有个空格”
“在windows上该如何正确使用fwrite()函数,才能让生成的文本文件在linux上打开读取也格式正确呢?”

过于武断的得出判断,以及过于不太正常的思考解决问题的方向。

问题一:

“打开test.txt文件,发现文件末尾有个空格”。那是不是空格,不能用鼠标划拉一下就武断得出结论。如果一个文件中出现特殊字符(不能常规显示),那么应该用稍微专业一点的工具来判断它是什么字符。这对于程序员调试问题很重要,比如:

       $ cat -A file.txt  This is test^@     

注意后面是没有换行的,因为写的程序就是:

       char str[] = "This is test"; fwrite(str, 1, sizeof(str), fp);     

写入的就是"This is test",fwrite不会帮你加 或 等,所以这是一个没有换行的内容,也就不涉及 的问题。

然后再说结尾的那个所谓的“空格”是什么。用稍微专业一点的工具把文件内容显示出来,如:

       $ od -c file.txt  0000000   T   h   i   s       i   s       t   e   s   t   0000015     

就会看到文件的结尾实际上多了一个''。所以所谓的“空格”其实是这个''。至于为什么会有这个'',请仔细想想sizeof(str)是多少吧,换成strlen(str)再试试。

问题二:

“在windows上该如何正确使用fwrite()函数,才能让生成的文本文件在linux上打开读取也格式正确呢?”

fwrite只是单纯的让它写什么字符,它就写什么字符。如果要让一行的结尾是 ,就是写"This is test ",如果想让结尾是 ,就写"This is test "。

比如:

       #include <stdio.h> #include <string.h>  int main() {         char str[] = "This is test
";         FILE* fp;          fp = fopen("file.txt", "wb");         fwrite(str, 1, strlen(str), fp);         fclose(fp);          return(0); }     

编译执行就会得到:

       $ od -c file.txt  0000000   T   h   i   s       i   s       t   e   s   t  
 0000015     

结尾是 。比如修改为:

       ...         char str[] = "This is test
"; ...     

编译执行后就会得到:

       $ od -c file.txt  0000000   T   h   i   s       i   s       t   e   s   t  
  
 0000016     

结尾就是 。根本没有什么在windows上“正确使用fwrite()函数”的特殊做法,也就不存在问题中的要“解决windows上用fwrite向文件写入内容时结尾的 问题”。因为本来问题中的程序也没写 ,其次fwrite写不写 完全看你自己写没写。

补充说明:

(感谢@恨铁不成钢琴 指出上面程序fopen时未使用"b"参数时的问题,为了表述明确些,我做了如下补充说明)

注意上面的程序在fopen的时候使用了"wb"的参数,"b"这个参数在Windows系统下是有意义的:

       b Open in binary (untranslated) mode; translations involving carriage-return and line feed characters are suppressed.     

表示不要以translated模式打开文件,translated模式(也叫text模式),是windows为了让fopen标准函数的行为和其它系统一致而实现的。在fopen的posix标准中对它的定义没有明确的限制,参考下面链接:

所以Windows系统用这个参数来表示Binary mode,也就是untranslated mode。那么translate的什么呢?translate就是 和 。说直白了就是windows为了兼容自己 结尾和其它 结尾的系统的差异,默认(不使用b参数)的情况下会将 转换为 。比如上述程序如果写成:

       char str[] = "This is test
";  fp = fopen("file.txt", "w");     

也就是fopen时不使用"b"参数,那么这个程序在Linux上编译执行会写入"This is test ",在Windows上编译执行会写入"This is test "。这样这个程序可以在不修改的情况下达到在 结尾和 结尾的系统上都能写入正确的换行符号。

而如果写成:

       fp = fopen("file.txt", "wb");     

则对Linux系统没有影响,对Windows系统则让其不做 到 的转换。这样做也可以在保证不修改程序的情况下,让不同的系统都有一致的行为。

也就是说不使用b参数保证了文本换行时在不同系统的兼容性,使用b参数保证了程序行为在不同系统的一致性,所以是否使用"b"参数,程序员要根据自己程序的需要决定。

关于 和 在两个系统上兼容的问题:

说完这个问题本身的问题。最后我们回到Windows和Linux不兼容的 问题上来。

我们不知道提问者所要写的软件面向的是怎样的需求,如果需求是“在windows上写一个纯文本文件,然后Linux能正常读取,反之也是”。这个需求可以看成三个部分:

  1. 软件在Windows系统运行,可以用于读写纯文本格式的文件。
  2. 需要一种功能,让上述纯文本文件的内容在Linux和Windows格式间转换(如解决 问题)。
  3. 软件在Linux系统也正常运行,可以打开并阅读文件内容。
         Windows                           Linux +--------------+                  +-------------+ |              |   trans2Linux    |             | |  Read/Write  | ---------------> | Read/Write  | |  pure text   | <--------------- | pure text   | |  file        |   trans2Windows  | file        | |              |                  |             | +--------------+                  +-------------+     

那么功能部分就可以包括:

  1. 可以打开编辑纯文本文件的功能。
  2. 自动去除Windows和Linux间不兼容(如 和 )问题的功能。

而这个问题原始可能就是想问第二个,关于Windows和Linux间文件内容转换的问题。结果非要把一个问题A变成问题C来问,问成了如何让fwrite解决 和 不兼容的问题。结果就是问的人不明白,听的人也不明白到底要干嘛,不知道的以为你要改标准实现。

关于怎么做到兼容Windows和Linux文本格式的问题,其实是有实现的,比如Linux下的dos2unix软件:

比如我得到一个Windows下的文件:

       $ od -c dosfile  0000000   T   h   i   s   '   s       a       t   e   s   t  
  
   T 0000020   h   i   s   '   s       a       t   e   s   t       t   o   o 0000040  
  
   B   l   a   b   l   a   b   l   a   b   l   a  
  
 0000060     

可以看到每一行的结尾都是 ,那么我要把它转换为Linux可以正常查看的格式,可以执行:

       $ dos2unix -n dosfile unixfile dos2unix: converting file dosfile to file unixfile in Unix format...     

然后就可以看到:

       $ od -c unixfile  0000000   T   h   i   s   '   s       a       t   e   s   t  
   T   h 0000020   i   s   '   s       a       t   e   s   t       t   o   o  
 0000040   B   l   a   b   l   a   b   l   a   b   l   a  
 0000055     

每一行的结尾都变成了 。

当然除了 和 的差异以外,还可能存在很多别的差异。dos2unix工具都可以帮忙解决,并且还可以用于Mac系统。具体请查看dos2unix的文档,我就不详细介绍了。

即使不用dos2unix工具,你就是想把结尾的 都换成 来达到Linux兼容的目的,那一个简单粗暴的文本替换命令也是可以的,比如:

       $ sed 's/
$//' dosfile > unixfile2 $ od -c unixfile2 0000000   T   h   i   s   '   s       a       t   e   s   t  
   T   h 0000020   i   s   '   s       a       t   e   s   t       t   o   o  
 0000040   B   l   a   b   l   a   b   l   a   b   l   a  
 0000055     

怎么实现这个功能可以论证讨论,你也可以自己设计实现这样的功能,这不是问题的关键。问题的关键是你得能正常的分析需求,正常的拆解需求为合适的功能模块,合理的设计实现……这些才是一个程序员应该具备的。你不是甲方爸爸,你不能用一个乱成一团的需求把自己绕进去。只有甲方爸爸才可以提出这样的需求和问题:

而程序员首先要合理的拆分需求:

然后设计成一个个合理的独立的功能块:

类似的话题

  • 回答
    在 Windows 系统上使用 C/C++ 语言中的 `fwrite()` 函数向文件写入内容时,遇到末尾自动添加 ` `(回车换行符)的问题,这通常是由于文件是以文本模式(text mode)打开导致的。Windows 系统在文本模式下,会将每个单独的换行符 ` ` 自动转换成 ` `(回车符.............
  • 回答
    好的,我们来聊聊在 Xcode 中遇到 “windows.h” 这个头文件找不到的问题。首先,你之所以在 Xcode 里看到这个错误,很可能是在尝试编译一段原本是为 Windows 平台编写的代码,而这段代码中引入了 `include `。为什么 Xcode 里找不到 `windows.h`?`wi.............
  • 回答
    这个问题很有意思,也触及了我们社会普遍的价值观和行为准则。为什么大家对高清电影下载趋之若鹜,甚至乐于分享资源,而对于软件破解和盗版Windows却避之不及,甚至出言斥责呢?这背后其实有很多原因,我们可以从几个层面来剖析。一、 对“内容”的认知差异:信息获取 vs. 知识产权侵犯首先,我们需要明确一个.............
  • 回答
    图神经网络(GNN)在处理图结构数据时展现出强大的能力,但一个普遍存在且棘手的问题是“过度平滑”(Oversmoothing)。过度平滑指的是在多层GNN中,节点的表示(embeddings)会变得越来越相似,最终趋于相同。这导致节点区分度丧失,使得GNN难以学习到有用的节点级特征,从而严重影响模型.............
  • 回答
    中国的人口问题是一个复杂而多层面的议题,涉及人口数量、结构、素质、分布等诸多方面。要解决这个问题,需要一个长期、系统、精细化的策略,并且不能简单地用一两项措施来概括。以下是我对如何解决中国人口问题的一个详细阐述:一、 理解中国当前人口问题的核心挑战:在探讨解决方案之前,我们首先要明确中国当前面临的人.............
  • 回答
    中国超低生育率问题是一个复杂且多层面的挑战,没有单一的“灵丹妙药”能够一蹴而就地解决。它涉及到经济、社会、文化、心理、政策等诸多因素的相互作用。要深入探讨这个问题,需要从各个维度进行分析和提出解决方案。以下我将尽量详细地阐述,并从多个角度分析可能存在的解决方案:一、 理解中国超低生育率的根源(为何年.............
  • 回答
    当你的 C++ 代码在尝试打开文件时出现错误,但你不知道具体是什么错误时,确实会让人感到困惑。这通常意味着文件操作失败,但具体原因可能有很多。解决这类问题需要系统性的排查和调试。下面我将详细地介绍解决 C++ 代码不能打开文件(提示有错误)的常见原因和排查方法,并提供具体的 C++ 代码示例和解释:.............
  • 回答
    脑袋里像是打翻了颜料盘,各种想法挤成一团,想表达点啥,张嘴又是语无伦次,逻辑断裂。这种思维混乱、讲话没条理的情况,简直是让人抓狂的“隐形障碍”。别担心,这也不是什么绝症,完全可以通过一些方法来梳理和改善。一、 根源探寻:为什么会乱成一锅粥?在动手解决问题之前,咱们先得看看这脑子里的“乱麻”是怎么打结.............
  • 回答
    这的确是知识产权保护领域一个长期存在的棘手问题,很多创造者和企业都深受其扰。知识产权侵权成本低,意味着那些心怀不轨的人可以轻易地模仿、抄袭他人的成果,风险似乎很小,但一旦被发现,可能也只是付出一点点代价就能了事。相反,权利人为了维护自己的合法权益,却要花费大量的时间、精力和金钱去收集证据、聘请律师、.............
  • 回答
    夫妻吵架是婚姻中难免会发生的事情,关键在于如何健康地处理和解决它们,而不是让争吵破坏感情。一个健康的婚姻,不仅仅是少吵架,更重要的是知道如何有效地吵架,并在吵架后修复关系。以下是解决夫妻吵架的详细步骤和建议,从事前预防到事后修复,希望能帮助你们:第一部分:吵架前的预防与沟通(治本之道)与其在吵架后仓.............
  • 回答
    大西南水电弃水困局:是资源错配还是发展滞后?近年来,大西南地区频现“弃水”现象,即水电站发电能力充裕,但因各种原因无法全部消纳,大量宝贵的水能资源白白流失。这不仅是对国家能源战略的巨大浪费,也与大西南地区经济社会发展的迫切需求形成鲜明反差。要破解这一难题,并非一蹴而就,需要从资源配置、技术创新、市场.............
  • 回答
    资本主义周期性危机是经济学中一个复杂且持续存在的现象。尽管没有单一的万能解决方案,但经济学家和政策制定者提出了多种旨在缓解、管理甚至预防这些危机的理论和实践。以下我将详细阐述这些方法,并分析其可行性、局限性以及相互之间的关联。理解资本主义周期性危机的根源在探讨解决方案之前,理解危机的根源至关重要。虽.............
  • 回答
    家里的电视机、电视柜这些家伙,简直就是空间的“吸血鬼”!明明看着挺大一个,但实际用起来,要么是电视屏幕那块固定不动,要么就是电视柜里塞满了各种杂七杂八的东西,利用率低得让人心疼。尤其对于小户型来说,这简直是灾难。不过,别急着把它们都扔了,咱们今天就来聊聊,怎么把这些个“大块头”变废为宝,让它们在你的.............
  • 回答
    寒冷天气下,特斯拉Model 3的车门可能出现“冻住”的情况,导致无法正常打开。这确实是一个让车主感到头疼的问题。究其原因,主要与以下几个方面有关:Model 3车门在寒冷天气下打不开的可能原因剖析: 门锁机构中的水分结冰: 这是最常见的原因。在潮湿的环境下,车辆的门锁、门把手感应区域、以及门框.............
  • 回答
    写到“大地图战略游戏后期乏味”这个问题,我真是太有感触了。玩过不少这类游戏,从最开始的雄心勃勃,到中期的运筹帷幄,再到后期的那种“我全都要”的无敌感,最后却发现,这个“全都要”的过程,竟然变得有点提不起劲儿来。这就像你辛辛苦苦爬到山顶,结果发现山顶的风景虽然壮阔,但已经没有了攀登时的那种挑战和惊喜。.............
  • 回答
    地下轨道交通“拥挤”的隐忧:如何打破“地下化”迷局?近年来,随着城市化进程的加速,轨道交通已成为疏导交通、优化城市空间的重要手段。然而,一个不容忽视的现象是,许多城市的轨道交通建设似乎陷入了一种“地下化”的倾向,地下线比例不断攀升。这种看似“高效”、“安静”的解决方案,在为城市居民带来便利的同时,也.............
  • 回答
    在“知乎MBTI圈”两年,我的强迫症和抑郁症从何而来?又如何挣脱?我曾经是一个热爱深度思考、喜欢探索自我的人。两年前,我抱着这样的心态走进了知乎的MBTI圈子。起初,这片沃土似乎为我提供了理解自己和他人世界的全新视角。我如饥似渴地阅读着各种理论文章,沉浸在对不同MBTI类型的性格分析中,仿佛找到了一.............
  • 回答
    你遇到Win10在2021年6月更新后任务栏卡死的问题,这确实挺让人头疼的。别担心,这种情况虽然烦人,但通常是有办法解决的。我来给你一步步拆解一下,希望能帮你搞定它。首先,我们要理解,任务栏卡死往往不是系统彻底坏了,而是某个程序或者系统组件在更新后出现了兼容性问题,导致它占用过多的资源或者卡住了。2.............
  • 回答
    你是不是也遇到过这样的糟心事:辛辛苦苦拍了一张精美的电脑屏幕截图,结果放大一看,屏幕上密密麻麻的横线或竖线,简直煞风景?别担心,这其实是个相当普遍的问题,而且,咱们也有办法解决它。今天就来好好聊聊,怎么让你的手机乖乖地拍出清晰、无纹路的显示器照片。首先,咱们得明白为啥会出现这恼人的“纹路”。这玩意儿.............
  • 回答
    新疆,这片广袤而独特的土地,长期以来就饱受缺水之苦。干旱的气候、蒸发量大以及人口增长和经济发展带来的用水需求增加,使得解决新疆的缺水问题成为一项艰巨而紧迫的任务。新疆缺水问题的根源要谈论解决方案,我们首先需要理解新疆缺水问题的几个关键因素: 地理和气候决定性因素: 新疆地处亚欧大陆腹地,远离海洋.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有