2017-11-28 8 views
1

私は、学生のバイナリファイルオブジェクトから読み込んでテキストファイルに書き込むプログラムに取り組んできましたが、バイナリファイルはテキストのファイル。私はそうするために2つの機能を行いました。バイナリへのテキストはうまくいきましたが、テキストにバイナリは私にエラーを与えています。私のコードですバイナリからテキストへの誤り訂正

#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; 
    } 

私は私のバイナリファイルが空ではないにもかかわらず、なぜまだ私にはわからない、ファイルをテキスト形式、バイナリからの書き込みをしようとすると、「ファイルが空である」取得しています

+0

あなたの読み込みまたは書き込みの妥当性は確認されていません。 (f、 "%s%s%d"、名前、名字、年齢)== 3){...} 'while(!feof(f)){...よりもはるかに良いでしょう} [**] while(!feof(file))はいつも間違っているのですか?**](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) '* /}の後にストリームエラーを処理する' '(fclose(g)== -1) 'を確認する必要があります。 –

+0

' char surname {char}'を持つときに 'Binarycopy'で' char surnames [20];を宣言するのはなぜですか? [15]; '' struct a'の中で? –

+0

それはタイプミスでした、私はあなたに編集していただきますありがとうございます –

答えて

2

ファイルのオープン、ファイルの読み取り、ファイルの書き込み、およびファイルのクローズにエラーが発生した場合の検出を防止する検証には、多くの問題があります。そこに行く前に、定数が必要な場合は#defineenumを使用して定数を定義します。

enum { NAMSZ = 15, MAXC = 512 }; 

(あなたのコード点在マジックナンバーを持っていないような方法は、注:scanfフィールド幅修飾子は例外です - 彼らは、指定しなければならず、変数や定数のラベルを使用することはできません。

:)

typedef struct a {...を宣言する必要はありません、あなただけの構造体のtypedefを使用し、aを使用しません0

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をチェックし、長さを書き、次に文字数を入力し、年齢を入力すると、struct-at-a-timeを書くことができますが、注:のデータファイルはアノトで動作することは保証されていませんパッディングの違いにより、アーキテクチャやコンパイラに影響を与えます。構造体を記述して同じコンパイラで読み戻すこともできますが、データのシリアライズは適切な方法です。

お読みになりたい場合は、逆の操作を行います。 freadstruct相当のデータを入力し、テキストファイルにその行を書き込みます。 main()

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; 
} 

あなたのオプションを検証します。 -bまたは-tが表示されない場合は、エラーを処理してください。またstrcmpを使用する必要はありません。argv[1](たとえばargv[1][1])の2番目の文字が'b'または't'であるかどうかを確認してください。

#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 

使用例/出力

コピーバイナリへ:

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; 
} 

は完全にそれを置く、あなたのような何かを行うことができます:

$ ./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 dat/nameagecpy.txt 
John Smith 30 
Mary Jane 35 
Dan Kane 55 
Annie Adams 40 

ご質問がある場合は、私に連絡してください。

+1

喜んで助けてください。古いC89コンパイラ(Windows 7など)だけで、 'id'を初期化したい場合はVS10が名前付き初期化子を許可しないので' sid id = {{0}、{0}、0};あなたは 'id'を全く初​​期化する必要はありません(バイナリファイル内の各文字列の* nul-terminating *文字の後ろの何バイトにも影響を与えない)。構造体を初期化すると、すべてのバイトがゼロになります(見た目がよく見えるようになります)。 –

関連する問題