在Windows和Linux中使用fscanf时,行尾不同的字符

时间:2015-12-29 13:35:57

标签: c linux windows newline

当我使用fscanf阅读时:

 nscan = fscanf(input_file, "%30[^,], %d, %lf, %d%c",
                array[i].epwnymo, &array[i].ypolipo,
                &array[i].epitokio, &array[i].meromhnia, &termch);

termch应为\n,但在Linux中,我得到\r,这会使我的程序给出错误的结果。我在某处看过\n \r\n \r,但为什么我在Linux中获得{{1}}?

3 个答案:

答案 0 :(得分:7)

这在技术上不是C问题,因为你会在所有编程语言中注意到同样的事情。

如果您已经将文件从Windows直接复制到Linux而没有转换换行符(FTP通过选择TEXT或ASCII传输模式为您提供了选项),那么您的Linux程序会看到{{1字符;这些通常会被翻译为Windows中'\r'序列的一部分,但Linux不会自动执行此类翻译。

我建议,当您将文本文件从Windows复制到Linux时,运行"\r\n"来转换这些文本文件(除非您使用为您执行此转换的FTP客户端) )...同样,当您将文本文件从Linux复制到Windows时,您应该使用dos2unix(同样,除了FTP方案)。

答案 1 :(得分:2)

我建议您可以通过先读取字符串,删除所有newline字符,然后扫描字符串,而不进行任何newline测试来处理newline结尾的不同约定。< / p>

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

//...

char input[100];
if (fgets(input, sizeof input, input_file) != NULL) {
    input [ strcspn(input, "\r\n") ] = 0;              // remove trailing newline etc
    nscan = sscanf(input, "%30[^,], %d, %lf, %d",
        array[i].epwnymo, &array[i].ypolipo, &array[i].epitokio, &array[i].meromhnia);    
}

这适用于MSVC中包含以\r\n以及\r\n结尾的行的文件,我无法在Linux上试用。

答案 2 :(得分:0)

推荐一种新方法。当代码需要读取文本的时,请从fgets()开始。

遇到的问题是因为1)各种操作系统使用不同的行结尾,例如\n \r\n\r 2)代码正在处理使用备用行结尾的文本文件和3)OP的代码并未尝试读取行

以下将接受并使用以5个位置结尾的候选行 - 不仅仅是在结尾。

         vv  vv   vv  v
"%30[^,], %d, %lf, %d%c"

"%c"的问题在于它只接受结束\r\n的2个字符行中的1个字符。编译代码时,如果文本文件以\r\n结束,因为流处于文本模式,\r\n将转换为\n,因此这不是问题。但是,如果代码是在只需要1个行尾字符的系统上编译的,则\r\n将保留为2个字符。

经典方法是使用" "中的fscanf()来消耗这些不同的空格。

" %30[^,], %d, %lf, %d"
"%30[^,], %d, %lf, %d "

IMO,阅读文本的最佳第一步是使用fgets()然后解析。

//                        [],sp %d ,sp    %lf    ,sp %d /r/n/0
#define LINE_EXPECT_MAX (30+1+1+20+1+1+(309+1+6)+1+1+20+2+1)
char buf[LINE_EXPECT_MAX];

if (fgets(buf, sizeof buf, input_file) == NULL) return EOF;

使用" %n"检测完整扫描并查找尾随的额外非空白文本很容易:

int n = 0;    
sscanf(buf, "%30[^,], %d, %lf, %d %n",
    array[i].epwnymo, &array[i].ypolipo, &array[i].epitokio, &array[i].meromhnia, &n);
if (n == 0) Handle_Incomplete_Scan();
if (buf[n] != '\0') Handle_Unxpected_Text();

最后,"%d""%lf"之前的空格没什么用处,因为即使没有前导空格,这些说明符也会消耗前导空格。是","之前的空格,将在数字之后和逗号之前传递空格。

" %30[^,],%d ,%lf ,%d %n"