【问题标题】:Converting text to a binary file将文本转换为二进制文件
【发布时间】:2013-08-20 14:55:54
【问题描述】:

我需要将以下格式的文本文件转换为二进制:

第一行包含库存中的产品数量,以下行包含:
产品名称'\t'产品价格'\t'数量'\n' (列之间可以有多个 \t)

对于每个产品,二进制输出文件将包含一个表示产品名称长度的 int、保存产品名称的字符、一个表示价格的 int 和一个表示数量的 int。

示例输入文件:

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

我编写了以下代码,我知道我应该以纯文本形式查看字符串,而整数将显示为乱码(二进制):

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

但见鬼,我的输出文件看起来像这样:

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

其中不包含纯文本。我尝试将 fopen 参数从“wb”更改为“w”,但我仍然得到乱码文件。我做错了什么?

【问题讨论】:

    标签: c binary converter


    【解决方案1】:

    在这里你写的是指针和额外的垃圾而不是它指向的字符串:

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

    你应该使用:

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

    在您的版本中,您将指针传递给指针,但您想传递指针本身。

    顺便说一句:在你的函数getProdName() 中,你应该添加一个额外的字符,因为你正在分配确切的字符串长度,但最后没有空间给0 字节。这也可能导致问题。 fgets 也少读一个字符。查看fgets 的手册页。除了使用fgets,您还可以使用fread,因为无论如何您都知道长度。无需额外解析。

    更新

    改变这个:

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

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

    【讨论】:

    • 使用fread会解决'\0'空间未分配的问题吗?
    • 不,它会读到你说的那么多。所以你应该要么 memset 分配的内存(只是为了确定)或者做 fread 然后把零字节放在最后。如果出现错误,fgets 可能会保持内存不变,所以如果你不检查这个,你的 strlen 和后续操作也会因为缺少 0 字节而导致问题。数完字符串长度后,分配+1内存。
    • 你的意思是fgets 不会告诉我我做错了什么但会返回错误值?
    • 顺便说一句:我应该在文本文件的每一行末尾使用fseek 跳过'\n' 吗?
    • 阅读手册页。它说 scanf 家族将忽略空格和换行符。这就是你不需要在这里使用 fseek 的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多