【问题标题】:Write bitstream to file in C在C中将比特流写入文件
【发布时间】:2021-06-14 08:01:58
【问题描述】:

我目前正在尝试使用 CMP 解压缩器:https://web.archive.org/web/20070113004119/http://rewiki.regengedanken.de:80/wiki/.CMP

实际上它确实解压缩了 cmp,但它不会将其写入文件。 所以我自己尝试了。

int main(int argc, char** argv)
{
    int length, dstLength;
    unsigned char* fileInMem; //compressed data
    unsigned char* dstFile; //decompressed data

    if (argc < 2) {
        fprintf(stderr, "give filename.cmp as parameter\n");
        return 1;
    }

    printf("%s", argv[1]);

    fileInMem = loadFile(argv[1], &length); //compressed data read
    if (fileInMem == NULL) {
        return 1;
    }

    dstFile = parseCmp(fileInMem, length, &dstLength); //decompress and assign data to dstFile
    if (dstFile) {
        /* Now we can save the file from dstFile, dstLength bytes */
        printf("%d bytes depacked\n", dstLength);

        for (int i = 0; i < 16; i++) {
            dataArray[i] = fileInMem[i];
        }

            FILE *writer = fopen(argv[2], "r+");
            //fputs(fileInMem, writer);
            //fputs(dstFile, writer);
         
            fclose(writer);
        free(dstFile);
    }

    free(fileInMem);

    return 0;
}

如您所见,解压缩的数据是指向无符号字符的指针(根据网站的比特流),我尝试了 stdio.h 中的 fputs(),但以十六进制查看时,生成的文件仅包含 4 个字节-编辑。

如果您需要更多信息,请发表评论。

提前谢谢你。

编辑:感谢您的帮助,这是我能够更改的内容,但是当我打开文件时,它仍然是空的:

FILE* writer = fopen(argv[2], "wb");
fwrite(dstFile, 192, 192, writer);

192,因为第一个解压后的Image长度为192 Bytes大。

【问题讨论】:

  • fputs 用于字符串。它不适用于二进制数据,因为它会在数据中有 0 时立即停止(这在二进制数据中很常见)。使用fwrite
  • 在您的帮助下,我能够输出原始数据。解压后的数据根本没有写,不过我觉得和你的回答没有关系。至少我学到了一些新东西。谢谢凯勒姆。

标签: c file pointers bitstream


【解决方案1】:

这是一个常见问题。

首先,您需要打开输出文件writer以二进制模式写入("wb")。

FILE *writer = fopen(argv[2], "wb");

其次,您不能使用fputs 将任意数据写入文件,因为它需要一个字符串。请改用fwrite:(假设writer 是输出文件,dstFile 是解压后的数据,dstLength 是要写入的字节数)

fwrite(dstFile, 1, dstLength, writer);

如果您使用十六进制编辑器检查生成的文件,您会发现它与解压缩的数据相同。

测试更新

我写了一些测试代码来看看有什么问题,分享你的结果以便我们帮助你。

将这些函数添加到您的代码中:

void printDataToScreen(unsigned char *dataptr, int datalen)
{
    if (dataptr == NULL)
    {
        printf("[!] ERROR, NULL POINTER PROVIDED!\n");
        return;
    }
    printf("> Dumping %d bytes of data into the terminal...\n", datalen);
    for (int i = 0; i < datalen; i++)
    {
        if (i % 16 == 0)
            printf("\n   ");
        printf("%02X ", dataptr[i]);
    }
    printf("\n\n");
}

void writeDataToFile(char *fileName, unsigned char *dataptr, int datalen)
{
    FILE *file = fopen(fileName, "wb");
    if (dataptr == NULL)
    {
        printf("[!] ERROR, NULL POINTER PROVIDED!\n");
        return;
    } else if (file == NULL)
    {
        printf("[!] ERROR WHILE OPENING FILE '%s'!\n", fileName);
        return;
    }
    
    printf("> Writting %d bytes of data to '%s'...\n", datalen, fileName);
    int writtenBytes = fwrite(dataptr, 1, datalen, file);
    printf("   Done, %d bytes written!\n\n", writtenBytes);
    
    fclose(file);
}

void runTest(char *fileName, unsigned char *dataptr, int datalen)
{
    printf("Running tests... [0/2 done]\n");
    printDataToScreen(dataptr, datalen);
    printf("Running tests... [1/2 done]\n");
    writeDataToFile(fileName, dataptr, datalen);
    printf("Finished! [2/2 done]\n");
}

这样称呼它:

runTest(argv[2], dstFile, dstLength);

在你的代码中添加对这个地方的调用(注释这个代码,也是你关闭writer的那一行):

FILE *writer = fopen(argv[2], "r+");
//fputs(fileInMem, writer);
//fputs(dstFile, writer);

请分享你的结果。

【讨论】:

  • 我要补充一点,您应该尝试一次写入所有内容(而不是每个字节 1 个字节),以尽量减少运行时成本高昂的 i/o 操作。
  • @AntoninGAVREL fwrite 被缓冲,因此昂贵的系统调用量仅取决于流缓冲区的大小。我不确定是否使用write,因为它只是 POSIX(fwrite 是 ISO C)。但是现在你让我好奇地尝试一下,看看在交换sizenmemb 时调用fwrite 是否有明显的速度差异(我不知道它们是如何实现的TBH,但我的猜测 是应该没有明显的区别)。
  • @AntoninGAVREL 在对中等大小的文件(2GB)进行了十几次实验后,我得出的结论是,在fwrite 中交换sizenmemb 对运行时没有积极影响执行速度。 (但是,由于我无法确定的其他因素,速度可能会有很大的变化,因为我获得的结果不是很一致)。
  • 你能在 github 上分享你的基准测试吗?邀请agavrel,很高兴看到它!
  • 感谢您的建议。我把它改成了 wb,但它仍然没有输出。
猜你喜欢
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-26
  • 2015-12-22
相关资源
最近更新 更多