1

I need to convert a text file of the following format to binary:

The first line contains the number of products in the inventory, The following lines contains:
product name '\t' product price '\t' quantity '\n' (there can be more than one \t between columns)

For every product the binary output file will contain an int representing the length of the product name, the chars that hold the product name, an int representing the price and an int representing the quantity.

Sample input file:

Asus Zenbook    1000    10
iPhone 5        750     22
Playstation 4   1000    0

I have wrote the following code, and I understood that I'm supposed to see the string in plain text while the integers will show up as gibberish (in binary):

int convertTextToBinary(char *fileName)
{
    FILE *pText, *pBinary;

    int size, i;

    char *currProdName;
    int currProdNameLen, currQuantity, currPrice;

    if (checkFileExists(fileName) == FALSE)
    {
        printf("- Given file does not exists!\n");
        return ERROR;
    }

    else
        pText = fopen(fileName, "r");

    // get the number of products in the inventory
    fscanf(pText, "%d", &size);
    #ifdef DBG
    printf("##DBG Successfuly read &size = %d DBG##\n", size);
    #endif  
    pBinary = fopen(strcat(fileName, ".bin"), "wb");

    fwrite(&size, sizeof(int), 1, pBinary);
    #ifdef DBG
    printf("##DBG Successfuly wrote &size = %d DBG##\n", size);
    #endif  
    for (i = 0; i < size; i++)
    {
        // get product name and name length
        currProdNameLen = getProdName(pText, &currProdName);
        #ifdef DBG
        printf("##DBG %d Successfuly read &currProdName = %s DBG##\n", i+1, currProdName);
        printf("##DBG %d Successfuly read &currProdNameLen = %d DBG##\n", i+1, currProdNameLen);
        #endif          
        // get product price 
        fscanf(pText, "%d", &currPrice);
        printf("##DBG %d Successfuly read &currPrice = %d DBG##\n", i+1, currPrice);
        // get product quantity
        fscanf(pText, "%d", &currQuantity);
        printf("##DBG %d Successfuly read &currQuantity = %d DBG##\n", i+1, currQuantity);
        // write data to binary file
        fwrite(&currProdNameLen , sizeof(int), 1, pBinary);
        fwrite(&currProdName, sizeof(char), currProdNameLen, pBinary);
        fwrite(&currPrice, sizeof(int), 1, pBinary);
        fwrite(&currQuantity, sizeof(int), 1, pBinary);
        free(currProdName);
    }

    fclose(pText);
    fclose(pBinary);
    return 1;
}

/* This function checks if a file in a given path exists or not by using fopen with "read" argument */
BOOL checkFileExists(char *fileName)
{
    FILE *fp;

    fp = fopen(fileName, "r");

    // file does not exists
    if (fp == NULL)
        return FALSE;

    // file does exists
    else
    {
        fclose(fp);
        return TRUE;
    }
}
int getProdName(FILE *fp, char **prodName)
{
    int nameLen = 0, offset;

    // count the length of the product name
    while (fgetc(fp) != '\t')
        nameLen++;

    // allcoate memory for the product name
    *prodName = (char*)malloc(sizeof(char)*nameLen);
    //checkalloc(&prodName);

    // get the cursor back to the original position
    offset = -1 * nameLen;
    fseek(fp, offset, SEEK_CUR);

    // copy product name from text to string
    fgets(*prodName, nameLen, fp);

    return strlen(*prodName);
}

But the hell, my output file looks like this:

       ¨ ּּּּּט        ¨ ּּּ¯        ¨ ּּּּּּּּ   ּּּ«
        ¨      

Which holds no plain text. I have tried changing the fopen argument from "wb" to "w" but I still get gibberish files. What am I doing wrong?

1 Answer 1

1

Here you write the pointer and additional garbage instead of the string it points to:

    fwrite(&currProdName, sizeof(char), currProdNameLen, pBinary);

You should use:

    fwrite(currProdName, sizeof(char), currProdNameLen, pBinary);

In your version you are passing the pointer to the pointer, but you want to pass the pointer itself.

BTW: In your function getProdName(), you should add an additional character, because you are allocating the exact string lenght, but no room for the 0 Byte at the end. This can also cause problems. Also fgets reads one char less. Check the man page for fgets. Instead of using fgets, you can also use fread because you know the length anyway. No additional parsing needed.

update

Change this:

    fscanf(pText, "%d", &currQuantity);

to

    fscanf(pText, "%d\n", &currQuantity);
Sign up to request clarification or add additional context in comments.

17 Comments

will using fread solve the problem with the space not allocated for '\0'?
No it will read as much as you tell it. Sou you should either memset the allocated memory (just to be sure) or do fread and then put the zero byte at the end. In case of an error, fgets will leave the memory possibly untouched, so if you don't check this, your strlen and subsequent operations will also cause problems because of the missing 0 Byte. After you counted the length of the string, allocate +1 memory.
You mean that fgets won't tell me I'm doing something wrong but will return false values?
BTW: Should I use fseek to jump over '\n' at the end of each line in the textfile?
Read the manpage. It says that the scanf familly will ignore whitespaces and newlines. That's why you don't need to use fseek here.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.