二进制到文本错误更正

时间:2017-11-28 17:50:41

标签: c file binary

我一直致力于从学生的二进制文件对象中读取并将其写入文本文件的程序,但所使用的二进制文件也是通过从文本文件中读取学生的数据来获得的。我做了两个函数,文本到二进制工作正常,二进制到文本仍然给我错误,我不知道为什么。

这是我的代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
 typedef struct a {
 char name[15];
 char surname[15];
int age;
}sID; 

int Binarycopy(char *s1,char *s2)     
{
sID id;
  FILE *f;
  FILE *g;
  char names[15];
  char surnames[15];
  int age;

  f=fopen(s1,"r");
  g=fopen(s2,"wb");// text file giving data about students, gathering them      into a data type structure and then write them in a binary file.


  if(f==NULL)
  { printf("File is empty");
      return -1;
  }
  fscanf(f,"%s %s %d",names,surnames,&age);

  while(!feof(f)){

      strcpy(names,id.name);
      strcpy(surnames,id.surname);
      id.age=age;                //write data into the ID object

      fwrite(&id,sizeof(sID),1,g); //write the ID object inside g

      fscanf(f,"%s %s %d",names,surnames,&age);
  }

  fclose(g);
  fclose(f);

  return 1;
}


 int Textcopy(char *s1,char *s2) 
{
sID id;
FILE *f;
FILE *g;

f=fopen(s1,"rb");
g=fopen(s2,"w");

if(fread(&id,sizeof(sID),1,f)!=sizeof(sID))
{ printf("file is empty");
    return -1;
}
else
    while(1)
    { fprintf(g,"%s %s %d",id.name,id.surname,id.age);

    if(fread(&id,sizeof(sID),1,f)!=sizeof(sID))
    { 
        fclose(f);
            fclose(g);
        return 1;
    }}}

  int main(int argc, char *argv[])
 {
   char b[]={"-b"};
   char t[]={"-t"};
   if(argc<4)
   { printf("Not enough arguments");
       return -1;}

   if(strcmp(argv[1],b)==0)
    Binarycopy(argv[2],argv[3]);

   if(strcmp(argv[1],t)==0)
    Textcopy(argv[2],argv[3]);

   return 1;
  }

我得到&#34;文件是空的&#34;当我尝试从二进制文件写入文本文件时,即使我的二进制文件不是空的,我仍然不知道为什么

1 个答案:

答案 0 :(得分:2)

验证存在许多问题,无法检测文件打开,文件读取,文件写入和文件关闭时是否存在错误。在到达目的地之前,如果您需要常量#define,或使用enum来定义它们,例如

enum { NAMSZ = 15, MAXC = 512 };

(通过这种方式,您的代码中没有幻数注意: scanf 字段宽度修饰符例外 - 必须指定它们,不能使用变量或常量标签)

无需声明typedef struct a {...,您不使用a,只需使用结构的typedef

typedef struct {
    char name[NAMSZ];
    char surname[NAMSZ];
    int age;
} sid;

我已经为您提供了Why is while ( !feof (file) ) always wrong?的链接。相反,声明一个足以容纳每一行的缓冲区并使用fgets读取每一行,然后使用sscanf(或仅指针和循环)从行解析所需的值,例如

int binarycopy (char *s1, char *s2)
{
    sid id = { .name = "" };
    FILE *f, *g;
    char buf[MAXC] = "";

    f = fopen (s1, "r");
    g = fopen (s2, "wb");

    if (f == NULL || g == NULL) {
        fprintf (stderr, "binarycopy: file open failed.\n");
        exit (EXIT_FAILURE);
    }

    while (fgets (buf, MAXC, f)) {
        if (sscanf (buf, "%14s %14s %d", id.name, id.surname, &id.age) == 3) {
            if (fwrite (&id, sizeof id, 1, g) != 1) {
                fprintf (stderr, "error: fwrite error.\n");
                exit (EXIT_FAILURE);
            }
        }
        else {
            fprintf (stderr, "binarycopy error: invalid line format.\n");
            exit (EXIT_FAILURE);
        }
    }

    fclose (f);
    if (fclose (g) == -1) {
        fprintf (stderr, "error: on stream close.\n");
        exit (EXIT_FAILURE);
    }

    return 1;
}

注意: 后验证fclose。可能会发生未经报告的流错误。写完后始终验证fclose

虽然您应该将写入上面的二进制文件的数据序列化(例如,检查每个名称的strlen,然后写出长度,然后写出字符数,然后是年龄,为了学习目的,你可以写一次一个结构,但是注意:由于填充的不同,数据文件不能保证在另一个体系结构或编译器上工作。你可以编写结构并将其读回来相同的编译器,但知道序列化数据是正确的方法。

为了您的阅读,只需反过来。 fread一个struct个数据,并将该行写入文本文件,例如

int textcopy (char *s1, char *s2)
{
    sid id;
    FILE *f;
    FILE *g;

    f = fopen (s1, "rb");
    g = fopen (s2, "w");

    if (f == NULL || g == NULL) {
        fprintf (stderr, "textcopy: file open failed.\n");
        exit (EXIT_FAILURE);
    }

    while (fread (&id, sizeof id, 1, f) == 1)
        fprintf (g, "%s %s %d\n", id.name, id.surname, id.age);

    fclose (f);
    if (fclose (g) == -1) {
        fprintf (stderr, "error: on stream close.\n");
        exit (EXIT_FAILURE);
    }

    return 1;
}

main()验证您的选项。如果您没有得到-b-t来处理错误。此外,无需使用strcmp,只需检查argv[1]中的第二个字符(例如argv[1][1])是'b'还是't',例如

int main (int argc, char *argv[])
{
    if (argc < 4) {
        printf ("Not enough arguments");
        return 1;
    }

    if (argv[1][1] == 'b')
        binarycopy (argv[2], argv[3]);
    else if (argv[1][1] == 't')
        textcopy (argv[2], argv[3]);
    else
        fprintf (stderr, "error: unrecognized option.\n");

    return 0;
}

完全放弃,你可以这样做:

#include <stdio.h>
#include <stdlib.h>

enum { NAMSZ = 15, MAXC = 512 };

typedef struct {
    char name[NAMSZ];
    char surname[NAMSZ];
    int age;
} sid;

int binarycopy (char *s1, char *s2)
{
    sid id = { .name = "" };
    FILE *f, *g;
    char buf[MAXC] = "";

    f = fopen (s1, "r");
    g = fopen (s2, "wb");

    if (f == NULL || g == NULL) {
        fprintf (stderr, "binarycopy: file open failed.\n");
        exit (EXIT_FAILURE);
    }

    while (fgets (buf, MAXC, f)) {
        if (sscanf (buf, "%14s %14s %d", id.name, id.surname, &id.age) == 3) {
            if (fwrite (&id, sizeof id, 1, g) != 1) {
                fprintf (stderr, "error: fwrite error.\n");
                exit (EXIT_FAILURE);
            }
        }
        else {
            fprintf (stderr, "binarycopy error: invalid line format.\n");
            exit (EXIT_FAILURE);
        }
    }

    fclose (f);
    if (fclose (g) == -1) {
        fprintf (stderr, "error: on stream close.\n");
        exit (EXIT_FAILURE);
    }

    return 1;
}


int textcopy (char *s1, char *s2)
{
    sid id;
    FILE *f;
    FILE *g;

    f = fopen (s1, "rb");
    g = fopen (s2, "w");

    if (f == NULL || g == NULL) {
        fprintf (stderr, "textcopy: file open failed.\n");
        exit (EXIT_FAILURE);
    }

    while (fread (&id, sizeof id, 1, f) == 1)
        fprintf (g, "%s %s %d\n", id.name, id.surname, id.age);

    fclose (f);
    if (fclose (g) == -1) {
        fprintf (stderr, "error: on stream close.\n");
        exit (EXIT_FAILURE);
    }

    return 1;
}

int main (int argc, char *argv[])
{
    if (argc < 4) {
        printf ("Not enough arguments");
        return 1;
    }

    if (argv[1][1] == 'b')
        binarycopy (argv[2], argv[3]);
    else if (argv[1][1] == 't')
        textcopy (argv[2], argv[3]);
    else
        fprintf (stderr, "error: unrecognized option.\n");

    return 0;
}

示例输入文件

$ cat dat/nameage.txt
John Smith 30
Mary Jane 35
Dan Kane 55
Annie Adams 40

示例使用/输出

复制到二进制文件:

$ ./bin/filecopytb -b dat/nameage.txt dat/nameagecpy.bin

复制到文字:

$ ./bin/filecopytb -t dat/nameagecpy.bin dat/nameagecpy.txt

比较

$ diff dat/nameage.txt dat/nameagecpy.txt

二进制的Hexdump:

$ hexdump -Cv dat/nameagecpy.bin
00000000  4a 6f 68 6e 00 00 00 00  00 00 00 00 00 00 00 53  |John...........S|
00000010  6d 69 74 68 00 00 00 00  00 00 00 00 00 00 00 00  |mith............|
00000020  1e 00 00 00 4d 61 72 79  00 00 00 00 00 00 00 00  |....Mary........|
00000030  00 00 00 4a 61 6e 65 00  00 00 00 00 00 00 00 00  |...Jane.........|
00000040  00 00 00 00 23 00 00 00  44 61 6e 00 00 00 00 00  |....#...Dan.....|
00000050  00 00 00 00 00 00 00 4b  61 6e 65 00 00 00 00 00  |.......Kane.....|
00000060  00 00 00 00 00 00 00 00  37 00 00 00 41 6e 6e 69  |........7...Anni|
00000070  65 00 00 00 00 00 00 00  00 00 00 41 64 61 6d 73  |e..........Adams|
00000080  00 00 00 00 00 00 00 00  00 00 00 00 28 00 00 00  |............(...|

cat of text:

$ cat dat/nameagecpy.txt
John Smith 30
Mary Jane 35
Dan Kane 55
Annie Adams 40

仔细看看,如果您有其他问题,请告诉我。