我正在尝试用LZO压缩文件流而不是很远。具体来说,我在提取由compressFileWithLzo1x
函数创建的存档文件时会出现分段错误。
我的main
函数和原型声明是:
#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;
}
这是我的压缩功能的实现:
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;
}
以下是我的解压缩功能的实现:
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;
}
此处发生分段错误:
extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);
这种方法导致分段错误有什么问题?
我希望这次没有留下任何代码。如果我需要添加更多信息,请随时告诉我。提前感谢您的建议。
答案 0 :(得分:2)
您正在压缩独立块。 LZO解压缩器需要压缩数据的字节长度,因为当它解码EOF时,它会检查它是否已经消耗了所有输入字节(如果没有则返回错误),因此你需要存储每个压缩块的长度。因此,您需要更复杂的文件格式。例如:
# 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,它将会增长。
答案 1 :(得分:1)
您提供的代码将无法编译(=
; #defines
中的虚假inFilePtr
,而不是inFnPtr
在各个地方,等等。但是:
压缩时,您没有考虑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);
(这不太可能是问题,但会在文件末尾添加虚假垃圾。)
解压缩时,你遇到了类似的问题,和输入/输出参数是错误的方式,这可能是你的段错误的原因。
extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);
应该是
extractionResult = lzo1x_decompress(in, inResult, out, &new_length, NULL);
答案 2 :(得分:1)
我认为您在int compressFileWithLzo1x
打开了错误的文件:
FILE *inFnPtr = fopen(outFn, "r");
应该是
FILE *inFnPtr = fopen(inFn, "r");