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

时间:2015-12-04 06:26:07

标签: c file-handling

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

但是当我打开output.dat时,我得到一个这样的结果: 一个 乙 C d Ë F G H 一世 Ĵ ķ 大号 中号 ñ Ø P Q [R 小号 Ť ü V w ^ X ÿ Zÿ< - Z之类的东西很奇怪,我不知道这是什么,为什么它一次又一次地发生。请有人向我解释这个 C代码:

int main()
{
    char ch;
    FILE *fpin,*fpout;

    fpin=fopen("textfile.dat","r");
    if(fpin==NULL)
        {printf("CANNOT FIND THE DESIGNATED FILE.");
            exit(1);
        }

    fpout=fopen("output.dat","w");

    while(!feof(fpin))
    {
        ch=getc(fpin);
        printf("\t%c",ch);
        putc(ch,fpout);
    }
    fclose(fpin);
    fclose(fpout);

    return 0;
}

3 个答案:

答案 0 :(得分:1)

这是因为while循环条件不是你想要的,因为它比你想要的运行一次:

while(!feof(fpin))

feof(fp)测试fp是否只有在过去文件标记的末尾时才会返回非零值。

我建议您使用fgets()代替将行读为解析sscanf()。一次读一个字符效率不高。

char buf[1024];

while( fgets(buf, sizeof buf, stdin) ) {
   ...
   ...
}

如果缓冲区中有空格,请记住fgets()也会读取换行符。所以你可能需要删除它,如果这是一个问题。例如,你可以这样做:

char *p = strchr(buf, '\n');
if (p) *p = 0;

在循环内部(在fgets()读取输入之后)删除尾随换行符(如果有的话)。

答案 1 :(得分:1)

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

相反,你应该做类似的事情:

while((ch = getc(fpin)) != EOF)
{
    printf("\t%c",ch)
    putc(ch,fpout);
}

这将循环直到它读取EOF,然后在EOF被打印或写入输出文件之前中断循环。

另外:您需要在文件开头#include <stdio.h>#include <stdlib.h>

答案 2 :(得分:1)

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

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

正如您在其他答案中指出的那样while (fpin != feof())在循环中用于读取文本文件时几乎总是错误。您从文件中读取文本的选择是使用面向字符的输入函数,如(getcharfgetc等)或通过读取一行 - 使用面向行的输入函数(如{fgetsgetline)的时间,然后是那些有限的情况,数据的布局本身会使fscanf可用的功能集。虽然使用fgets面向行的输入会使您的程序变得微不足道,但看起来目的是让您接触面向字符的方法。

考虑到这些因素,您可以编写类似于以下内容的代码。注意:简单的ternary运算符(例如(test) ? (if true code) : (if false code);使得在命令行上获取输入和输出文件名变得非常容易,同时在没有参数的情况下仍然提供默认文件名这允许用户指定输入/输出文件名而不会被硬编码值所困扰。(这也允许通过简单的更改从文件或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;
}

编译(始终启用警告)

您希望始终编译并启用警告(至少-Wall,并建议-Wall -Wextra)。警告将指出您的代码需要注意的位置。在您学习C期间编译的任何代码中,应该保留 No 警告。示例编译字符串:

gcc -Wall -Wextra -O3 -o bin/read_AZ read_AZ.c 

输入文件

$cat dat/AZ.txt
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/AZout.dat
ABCDEFGHIJKLMNOPQRSTUVWXYZ

注意:最后没有有趣的人物......如果您有任何问题,请与我联系。