首页 > 解决方案 > fgets 在 Linux 和 Windows 中从同一个文件中写入不同的字符串

问题描述

我刚刚遇到一个问题,我在 Linux 中的 valgrind 和 Windows cmd 中的其他测试之间跳跃。

我正在从这样的文件中读取某行:

fgets(buf, MAX_LINE_LEN, f_input);

当然,buf 的大小是 MAX_LINE_LEN + 1,但我离题了。

这是的输出

printf("String length: %u; Contents: ", strlen(buf));
for (usint i = 0; i < strlen(buf); i++)
  printf("%x ", buf[i]);
puts(";");

在 Windows 中:

String length: 14; Contents: 41 6e 64 72 65 6a 20 50 6c 61 76 6b 61 a ;
String length: 22; Contents: 41 6e 6e 61 20 4d 61 72 69 61 20 43 69 63 6d 61 6e 63 6f 76 61 a ;
String length: 25; Contents: 4d 61 72 69 61 20 52 61 7a 75 73 6f 76 61 20 4d 61 72 74 61 6b 6f 76 61 a ;
String length: 24; Contents: 4d 69 6c 61 6e 20 52 61 73 74 69 73 6c 61 76 20 50 6f 6b 6f 6a 6e 79 a ;
String length: 21; Contents: 4d 69 6c 65 6e 61 20 53 65 64 6d 69 6b 72 61 73 6b 6f 76 61 a ;
String length: 15; Contents: 56 69 6e 63 65 6e 74 20 53 69 6b 75 6c 61 a ;
String length: 17; Contents: 56 69 6e 63 65 6e 74 20 76 61 6e 20 47 6f 67 68 a ;

在 Linux 中:

String length: 15; Contents: 41 6e 64 72 65 6a 20 50 6c 61 76 6b 61 d a ;
String length: 23; Contents: 41 6e 6e 61 20 4d 61 72 69 61 20 43 69 63 6d 61 6e 63 6f 76 61 d a ;
String length: 26; Contents: 4d 61 72 69 61 20 52 61 7a 75 73 6f 76 61 20 4d 61 72 74 61 6b 6f 76 61 d a ;
String length: 25; Contents: 4d 69 6c 61 6e 20 52 61 73 74 69 73 6c 61 76 20 50 6f 6b 6f 6a 6e 79 d a ;
String length: 22; Contents: 4d 69 6c 65 6e 61 20 53 65 64 6d 69 6b 72 61 73 6b 6f 76 61 d a ;
String length: 16; Contents: 56 69 6e 63 65 6e 74 20 53 69 6b 75 6c 61 d a ;
String length: 18; Contents: 56 69 6e 63 65 6e 74 20 76 61 6e 20 47 6f 67 68 d a ;

正如您在 Linux 中看到的,在 NL 之前还有另一个字符,即回车。如果有人能解释这一点并让我免于为 Linux 和 Windows 代码添加语句的痛苦ifdef,我将不胜感激。我知道,linux 在每一行之后都附加了一个回车符,但是当它被读取时,这真的是预期的行为fgets吗?

标签: clinuxfgets

解决方案


MS 和 Linux 对文本文件行结尾的期望不同:"\r\n"vs "\n".

为了应对,建议在fgets()使用后strcspn()切断可能的行尾序列,无论是它"\n"还是"\r\n"缺失。

fgets(buf, MAX_LINE_LEN, f_input);
buf[strcspn(buf, "\n\r")] = '\0';

Windows 上的一些编译器将"\n"用作行尾序列,而其他编译器则使用"\r\n". 因此,我将这种变化更多地归因于编译器及其制造商,而不是操作系统。还有一些旧的 MAC 文本文件以 Linux 结尾'\r'并且会犯规fgets()

进一步:读取具有"\r\n"文本文件的文件,该文件期望"\n"作为行尾序列,在读取完整缓冲区时会出现问题,并且在 next 上读取"......\r"行剩余部分时会出现问题。每当缓冲区不足以容纳一行输入 时,就需要额外的处理来应对这种情况。"\n"fgets()

一种变体的文本文件经常被复制到其他平台,因此这种情况并不罕见。

由于编辑,一些文本文件将混合行尾序列。

Pedantic 代码会将文件作为二进制文件读取并处理变体行结尾本身,而无需fgets(). 祝你好运。


推荐阅读