首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何让LZO处理文件流?

如何让LZO处理文件流?
EN

Stack Overflow用户
提问于 2010-11-21 05:09:06
回答 3查看 4K关注 0票数 2

我正在尝试用LZO压缩一个文件流,但没有走得太远。具体地说,在提取由我的compressFileWithLzo1x函数创建的归档文件时,我得到了一个分段错误。

我的main函数和原型声明是:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include "lzo/include/lzo/lzo1x.h"

#define LZO_IN_CHUNK (128*1024L)
#define LZO_OUT_CHUNK (LZO_IN_CHUNK + LZO_IN_CHUNK/16 + 64 + 3)

int compressFileWithLzo1x(const char *inFn, const char *outFn);
int extractFileWithLzo1x(const char *inFn);

int main(int argc, char **argv) {

    const char *inFilename = "test.txt";
    const char *outFilename = "test.txt.lzo1x";

    if ( compressFileWithLzo1x(inFilename, outFilename) != 0 )
        exit(EXIT_FAILURE);

    if ( extractFileWithLzo1x(outFilename) != 0 )
        exit(EXIT_FAILURE);

    return 0;
}

下面是我的压缩函数的实现:

代码语言:javascript
复制
int compressFileWithLzo1x(const char *inFn, const char *outFn) {

    FILE *inFnPtr = fopen(outFn, "r");
    FILE *outFnPtr = fopen(outFn, "wb");
    int compressionResult;
    lzo_bytep in;
    lzo_bytep out;
    lzo_voidp wrkmem;
    lzo_uint out_len;
    size_t inResult;

    if (lzo_init() != LZO_E_OK)
        return -1;

    in = (lzo_bytep)malloc(LZO_IN_CHUNK);
    out = (lzo_bytep)malloc(LZO_OUT_CHUNK);
    wrkmem = (lzo_voidp)malloc(LZO1X_1_MEM_COMPRESS);

    do { 
        inResult = fread(in, sizeof(lzo_byte), LZO_IN_CHUNK, inFnPtr);
        if (inResult == 0)
            break;
        compressionResult = lzo1x_1_compress(in, LZO_IN_CHUNK, out, &out_len, wrkmem);
        if ((out_len >= LZO_IN_CHUNK) || (compressionResult != LZO_E_OK))
            return -1;
        if (fwrite(out, sizeof(lzo_byte), (size_t)out_len, outFnPtr) != (size_t)out_len || ferror(outFnPtr))
            return -1;
        fflush(outFnPtr);
    } while (!feof(inFnPtr) && !ferror(inFnPtr));

    free(wrkmem);
    free(out);
    free(in);
    fclose(inFnPtr);
    fclose(outFnPtr);

    return 0;
}

下面是我的解压缩函数的实现:

代码语言:javascript
复制
int extractFileWithLzo1x(const char *inFn) {

    FILE *inFnPtr = fopen(inFn, "rb");
    lzo_bytep in = (lzo_bytep)malloc(LZO_IN_CHUNK);
    lzo_bytep out = (lzo_bytep)malloc(LZO_OUT_CHUNK);
    int extractionResult; 
    size_t inResult;
    lzo_uint new_length;

    if (lzo_init() != LZO_E_OK)
        return -1;

    do {
        new_length = LZO_IN_CHUNK;
        inResult = fread(in, sizeof(lzo_byte), LZO_IN_CHUNK, inFnPtr);
        extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);
        if ((extractionResult != LZO_E_OK) || (new_length != LZO_IN_CHUNK))
            return -1;
        fprintf(stderr, "out: [%s]\n", (unsigned char *)out);
    } while (!feof(inFnPtr) && (!ferror(inFnPtr));

    free(in);
    free(out);
    fclose(inFnPtr);

    return 0;
}

分段故障发生在这里:

代码语言:javascript
复制
extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);

这种方法导致分段错误的原因是什么?

我希望这次我没有遗漏任何代码。如果我需要添加更多信息,请随时告诉我。提前感谢您的建议。

EN

回答 3

Stack Overflow用户

发布于 2012-04-22 15:55:11

您正在压缩独立的块。LZO解压缩器需要压缩数据的字节长度,因为当它解码EOF时,它会检查是否已经消耗了所有的输入字节(如果没有,则返回一个错误),因此您还需要存储每个压缩块的长度。因此,您需要更复杂的文件格式。例如:

代码语言:javascript
复制
# compressing, in python-like pseudocode
ifile = open("data", "rb")
ofile = open("data.mylzo", "wb")
input, input_len = ifile.read(65536)
while input_len > 0:
  compressed, compressed_len = lzo1x(input, input_len)
  compressed_len -= 1 # store len-1 of next block
  if compressed_len < 65536 - 1:
    ofile.write(compressed_len & 255) # be sure of endianess in file formats!
    ofile.write(compressed_len >> 8)
    ofile.write(compressed)
  else:
    ofile.write(255) # incompressible block stored it as-is (saves space & time).
    ofile.write(255)
    ofile.write(input)
  input, input_len = ifile.read(65536)
ofile.close()
ifile.close()

# decompressing, in python-like pseudocode
ifile = open("data.mylzo", "rb")
ofile = open("data", "wb")
compressed_len_s = ifile.read(2)
while len(compressed_len_s) == 2:
  compressed_len = (compressed_len_s[0] | (compressed_len_s[1] << 8)) + 1
  if compressed_len == 65536:
    ofile.write(ifile.read(65536)) # this can be done without copying
  else:
    compressed = ifile.read(compressed_len)
    decompressed = lzo1x_decompress(compressed, compressed_len)
    ofile.write(decompressed)
  compressed_len_s = ifile.read(2)
ofile.close()
ifile.close()

如果您希望能够在不跳过的情况下解压缩块(无论是并行解压缩还是随机访问),您应该将压缩块的长度放在第一个块之前的开头。在它们前面加上组块的数量。

最后一个块可以比64k短,它可以是不可压缩的,但我们仍然会存储压缩形式,即使它比非压缩形式长,因为只有完整的64k块按原样存储。如果整个文件小于64k,它将增长。

票数 2
EN

Stack Overflow用户

发布于 2010-11-21 07:51:58

您给出的代码将无法编译(#defines中的虚假=;不同位置的inFilePtr而不是inFnPtr,等等)。但是:

  1. 压缩时,您不会考虑fread()返回的实际数据量,它很可能小于LZO_IN_CHUNK

compressionResult = lzo1x_1_compress(in,LZO_IN_CHUNK,out,&out_len,wrkmem);

可能应该是

compressionResult = lzo1x_1_compress(in,inResult,out,&out_len,wrkmem);

(这不太可能是问题所在,但会在文件的末尾添加虚假的垃圾文件。)

  • 在解压缩时,您会遇到类似的问题,并且in / out参数颠倒过来,这很可能是您的段错误的原因。

extractionResult = lzo1x_decompress(out,LZO_OUT_CHUNK,in,&new_length,NULL);

可能应该是

extractionResult = lzo1x_decompress(in,inResult,out,&new_length,NULL);

票数 1
EN

Stack Overflow用户

发布于 2012-11-16 17:46:33

我认为您在int compressFileWithLzo1x中打开了错误的文件

代码语言:javascript
复制
FILE *inFnPtr = fopen(outFn, "r");

它应该是

代码语言:javascript
复制
FILE *inFnPtr = fopen(inFn, "r");
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4235019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档