-1

I need to convert a text file of the following format to binary file. The input file only contains characters A, B, C or D. 'A' changes to '00','B' changes to '01', C changes to '10', D changes to '11'. Sample input file:

ABBCDA
BBAABCD
BACBB

Sample output file:

000101101100
01010000011011
0100100101

I have wrote the following code, but it doesn't work.

int main()
{
    FILE * fop;
    FILE * fout;
    int length=0;
    int i;
    char buffer[1000];
    fop = fopen("filename.txt","r");
    fout = fopen("filename.bin", "wb");
    while(!feof(fop))
    {
        fgets(buffer,1000,fop);
        length = strlen(buffer)-1;
        for(i=0; i<length; i++)
         {
           if(buffer[i]=='A')
           strcpy(buffer[i],'00');
           if(buffer[i]=='B')
           strcpy(buffer[i],'01');
           if(buffer[i]=='C')
           strcpy(buffer[i],'10');
           if(buffer[i]=='D')
           strcpy(buffer[i],'11'); 
         }
      fwrite(buffer, 1, sizeof(char)*length, fout);
      fwrite("\n",1,sizeof(char),fout);
    }
    fclose(fop);
    fclose(fout);
    return 0;
}

What's wrong? How to solve it? Thank you.

  • 1
    Copying **two characters**? You have two problems now! – iBug Nov 24 '17 at 05:01
  • 1. Please check the return values from `fopen`. 2 Read [this](https://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) about the use of `feof`. 3. Check the return value from `fgets` ... – Ed Heal Nov 24 '17 at 05:01
  • 1
    You should also compile will all the warnings on – Ed Heal Nov 24 '17 at 05:10

1 Answers1

2

This is the part to be fixed

while(fgets(buffer,1000,fop))
{
    length = strlen(buffer)-1;
    char sout[3];
    for(i=0; i<length; i++)
    {
        *sout = '\0';
        if(buffer[i]=='A')
            strcpy(sout,"00");
        if(buffer[i]=='B')
            strcpy(sout,"01");
        if(buffer[i]=='C')
            strcpy(sout,"10");
        if(buffer[i]=='D')
            strcpy(sout,"11"); 
        fwrite(sout, 1, strlen(sout), fout);
    }
    fwrite("\n",1,sizeof(char),fout);
}

Notes

  • the fgets within the while condition
  • sout to store temporarily the 2-bits (as string)
  • fwrite writes to sout (does not overwrite buffer), and is integrated within the for loop while the writing of \n is outside.

Version to write actual bytes (in binary) ...

while(fgets(buffer,1000,fop))
{
    length = strlen(buffer)-1;
    for(i=0; i<length; i++)
    {
        unsigned char byte = 0;
        if(buffer[i]=='A')
            byte = 0x0;
        if(buffer[i]=='B')
            byte = 0x1;
        if(buffer[i]=='C')
            byte = 0x2;
        if(buffer[i]=='D')
            byte = 0x3; 
        fwrite(&byte, 1, 1, fout);
    }
    // no more : fwrite("\n",1,sizeof(char),fout);
}

Using 0x notation to show I'm dealing with binary stuff...

And version David C. Rankin (perfectionist!)

while (fgets (buf, MAXC, fop)) {    /* read each line */
    char *p = buf;                  /* pointer to buf */
    while (*p) {                    /* while not '\0' */
        uint8_t byte = 0;           /* declare byte */
        if ('A' <= *p && *p <= 'Z') /* if char is A-Z */
            byte = *p - 'A';        /* encode 0 - 25 */
        else
            byte = *p;              /* write char as is */
        if (fwrite (&byte, 1, 1, fout) != 1) {   /* validate write */
            fprintf (stderr, "error: write of '%c' failed.\n", *p);
            goto badwrite;          /* jump out of loops on fail */
        }
        p++;    /* increment pointer */
    }
}
badwrite:;

fclose (fop);                /* close input file */
if (fclose (fout) == -1)     /* close/validate output file */
    fprintf (stderr, "error: on fout close.\n");

There is yet some stuff that can be improved, but for now ...

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
Déjà vu
  • 28,223
  • 6
  • 72
  • 100
  • `char sout[2];` -> `char sout[3];` – Ed Heal Nov 24 '17 at 05:15
  • Are you sure `char sout[2]` won't run into problems? – iBug Nov 24 '17 at 05:15
  • `fwrite("\n",1,sizeof(char),fout);` - Would `fputc` be a better choice – Ed Heal Nov 24 '17 at 05:19
  • Also a `switch` statement might be better than all those `ifs` – Ed Heal Nov 24 '17 at 05:21
  • 1
    I'm still confused. if `'A'` is supposed to be **zero**, `'B'` is supposed to be `1`, `'C'` is supposed to be `2`... (each being a (byte) -- "Why are we not writing `uint8_t` to the file?" – David C. Rankin Nov 24 '17 at 05:40
  • @yoyoyoyo11 [3] is the number of characters in sout, 2 for the text version of the binary byte (00, 01 ...), one for the trailing `\0` – Déjà vu Nov 24 '17 at 05:47
  • Only thing I would do different is walk down each line with `uint8_t byte = *p - 'A';` and then validate the close of the output file `if (fclose (fout) == -1)` to catch any stream error on close (you don't care about the input file, but the output file close is worth checking) – David C. Rankin Nov 24 '17 at 06:02
  • @David indeed again. Added your version! However TBH, the code I write here on SO tries to stick more to OP's code (otherwise they might seem lost). But you definitely have the touch! – Déjà vu Nov 24 '17 at 06:19
  • 1
    The only other thing that really ought to be done if we are encoding the character file to a binary file with `'A-Z'` encoded `0-25` is we should also write the `newline`. (and that is my fault for not catching it sooner). That is required to allow the binary file to be decoded to exactly what the original was. So I would add/change to `char *p = buf; while (*p) { uint8_t byte = 0; if ('A' <= *p && *p <= 'Z') byte = *p - 'A'; else byte = *p; if (fwrite (&byte, 1, 1, fout) != 1) { /* handle error */} p++; }` Then you can get back exactly what you put in `:)` – David C. Rankin Nov 24 '17 at 06:25
  • I took the liberty to change that part in your answer `:)` – David C. Rankin Nov 24 '17 at 06:36
  • @David it's partly yours now ;-) – Déjà vu Nov 24 '17 at 06:39
  • I'm happy to share. Once I get my last cat in the house (to insure it's not fox-bait -- which produces really unhappy kids in the morning) I'm letting the turkey win and closing my eyes `:)` – David C. Rankin Nov 24 '17 at 06:41