使用c代码复制.dat文件时出现的额外字符

使用c代码复制.dat文件时出现的额外字符,c,file-handling,C,File Handling,我是C语言的新手,刚刚开始了文件处理章节,所以请随意修改我的代码,我坚持。在下面给出的C代码中,A-Z字符从名为textfile.dat的dat文件复制,并粘贴到名为output.dat的另一个dat文件中 但当我打开output.dat时,会得到如下结果: A. B C D E F G H 我 J K L M N O P Q R s T U v W X Y Zÿ这是因为while循环条件不是您想要的,因为它比您想要的多运行一次: while(!feof(fpin)) feof(fp)测试fp

我是C语言的新手,刚刚开始了文件处理章节,所以请随意修改我的代码,我坚持。在下面给出的C代码中,A-Z字符从名为textfile.dat的dat文件复制,并粘贴到名为output.dat的另一个dat文件中

但当我打开output.dat时,会得到如下结果: A. B C D E F G H 我 J K L M N O P Q R s T U v W X Y
Zÿ这是因为
while
循环条件不是您想要的,因为它比您想要的多运行一次:

while(!feof(fpin))
feof(fp)
测试
fp
是否仅在文件结束标记后返回非零值

我建议您使用,而不是阅读行作为必要的解析。一次读一个字符不是很有效

char buf[1024];

while( fgets(buf, sizeof buf, stdin) ) {
   ...
   ...
}
记住
fgets()
如果缓冲区中有空间,也会读取换行符。因此,如果出现问题,您可能需要将其删除。例如,您可以执行以下操作:

char *p = strchr(buf, '\n');
if (p) *p = 0;
在循环内部(在
fgets()
读取输入后)移除尾随换行符(如果有)。

feof(fpin)
测试EOF指示器;在设置之前,
getc(fpin)
将返回EOF字符。您在输出中看到的是这个角色。(它是-1,在单字节字符中是0xFF。)

相反,您应该执行以下操作:

while((ch = getc(fpin)) != EOF)
{
    printf("\t%c",ch)
    putc(ch,fpout);
}
这个循环直到读取EOF,然后在EOF被打印或写入输出文件之前中断循环


另外:您需要在文件的开头添加
#include
#include

有几个微妙的问题值得注意,但首先是有点小,但足够大,可以讨论。所有应用程序都可以在命令行上获取参数。这是您必须向程序传递信息的方式,以防止在代码中硬编码,如文件名等。
main
的标准声明是
intmain(intargc,char**argv)
(在Linux上,您也可以看到
char**envp
argc
将包含命令行上的参数数量,
argv[]
将包含指向每个参数的指针(
argv[0]
始终是用于启动程序的名称)

接下来,
ch
是type
int
,而不是
char
。这是
fgetc
的返回,它允许处理包含多个字节的字符。确保始终使用正确的数据类型

正如您在其他答案
中所指出的那样,(fpin!=feof())
在循环中用于读取文本文件时几乎总是错误的。从文件中读取文本的选择是使用面向字符的输入函数,如(
getchar
fgetc
,等等),或者使用面向行的输入函数(如(
fgets
getline
)一次读取一行,还有一些有限的情况,数据本身的布局使得
fscanf
函数集可用。虽然使用
fgets
进行面向行的输入会使您的程序变得微不足道,但其目的似乎是让您接触到面向字符的方法

考虑到这些因素,您可以编写类似于以下内容的代码。注:简单的
三元
运算符(例如
(测试)?(如果为真代码):(如果为假代码);
使得在命令行上获取输入和输出文件名非常容易,同时在没有参数的情况下仍然提供默认文件名。这允许用户指定输入/输出文件名,而不必使用硬编码值。(默认情况下,只需进行简单更改,即可从文件或
stdin
中读取)

尝试以下方法:

#include <stdio.h>

int main (int argc, char **argv)
{
    int ch; /* ch is type 'int' */
    FILE *fpin = argc > 1 ? fopen (argv[1], "r") : fopen ("textfile.dat","r");
    FILE *fpout = argc > 2 ? fopen (argv[2], "w") : fopen ("output.dat","w");;

    if (!fpin || !fpout) {
        if (!fpin)  fprintf (stderr, "error: input file open failed\n");
        if (!fpout) fprintf (stderr, "error: output file open failed\n");
        return 1;
    }

    while ((ch = fgetc(fpin)) != EOF) {
        printf ("  %c", ch);
        putc (ch, fpout);
    }
    putchar ('\n');     /* to make stdout output look nice  */
    putc ('\n', fpout); /* POSIX requires newline at EOF    */

    fclose (fpin);
    fclose (fpout);

    return 0;
}
输入文件

$cat dat/AZ.txt
ABCDEFGHIJKLMNOPQRSTUVWXYZ
$cat dat/AZout.dat
ABCDEFGHIJKLMNOPQRSTUVWXYZ
使用/输出

$ ./bin/read_AZ dat/AZ.txt dat/AZout.dat
  A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z
输出文件

$cat dat/AZ.txt
ABCDEFGHIJKLMNOPQRSTUVWXYZ
$cat dat/AZout.dat
ABCDEFGHIJKLMNOPQRSTUVWXYZ

注意:结尾没有有趣的字符…如果您有任何问题,请告诉我。

另外
ch
应为
int
类型。