【问题标题】:ASCII compressor works for short test file, not on longASCII 压缩器适用于短测试文件,不适用于长
【发布时间】:2011-03-05 04:00:12
【问题描述】:

系统编程中的当前项目是想出一个 ASCII 压缩器,它会删除顶部的零位并将内容写入文件。

为了方便解压,先将原始文件大小写入file,然后是压缩后的char字节。有两个文件可以运行测试——一个是 63 字节长,另一个是 5344213 字节。我的代码在第一个测试文件中按预期工作,因为它写入了 56 字节的压缩文本和 4 字节的文件头。

但是,当我在长测试文件上尝试时,压缩版本比原始文件短 3 个字节,当时它应该大约小 749KiB,或原始大小的 14%。我已经计算出长测试文件的前两个写入循环的二进制位移值,它们与我的测试打印输出中记录的内容相匹配。

while ( (characters= read(openReadFile, unpacked, BUFFER)) >0 ){
   unsigned char packed[7]; //compression storage
   int i, j, k, writeCount, endLength, endLoop;

    //loop through the buffer array
    for (i=0; i< characters-1; i++){
        j= i%7; 

        //fill up the compressed array
        packed[j]= packer(unpacked[i], unpacked[i+1], j);

        if (j == 6){
            writeCalls++; //track how many calls made

            writeCount= write(openWriteFile, packed, sizeof (packed));
            int packedSize= writeCount;
            for (k=0; k<7 && writeCalls < 10; k++)
                printf("%X ", (int)packed[k]);      

            totalWrittenBytes+= packedSize;
            printf(" %d\n", packedSize);
            memset(&packed[0], 0, sizeof(packed)); //clear array

            if (writeCount < 0)
                printOpenErrors(writeCount);
        }
        //end of buffer array loop
        endLength= characters-i;
        if (endLength < 7){

            for (endLoop=0; endLoop < endLength-1; endLoop++){
                packed[endLoop]= packer(unpacked[endLoop], unpacked[endLoop+1], endLoop);
            }

            packed[endLength]= calcEndBits(endLength, unpacked[endLength]);
        }
    } //end buffer array loop
} //end file read loop

打包函数:

//calculates the compressed byte value for the array
char packer(char i, char j, int k){
    char packStyle;

    switch(k){
        //shift bits based on mod value with 8
        case 0:
                packStyle= ((i & 0x7F) << 1) | ((j & 0x40) >> 6);
            break;
        case 1:
            packStyle= ((i & 0x3F) << 2) | ((j & 0x60) >> 5);
            break;
        case 2:
            packStyle= ((i & 0x1F) << 3) | ((j & 0x70) >> 4);
            break;
        case 3:
            packStyle= ((i & 0x0F) << 4) | ((j & 0x78) >> 3);
            break;
        case 4:
            packStyle= ((i & 0x07) << 5) | ((j & 0x7C) >> 2);
            break;
        case 5:
            packStyle= ((i & 0x03) << 6) | ((j & 0x7E) >> 1);
            break;
        case 6:
            packStyle= ( (i & 0x01 << 7) | (j & 0x7F));
            break;
    }

    return packStyle;
}

我已验证每次刷新打包缓冲区时都会写入 7 个字节,并且对长文件进行了 763458 次写入调用,匹配最多写入 5344206 个字节。

我从打印输出中得到的十六进制代码与我事先以二进制形式计算的相同,我可以看到每个字节的最高位被删除。那么为什么位移没有反映在结果中呢?

【问题讨论】:

  • @Andrew 听起来像,但如果是这样,让 Jason 标记它,只是为了确定。无论如何,这是一个很好的问题
  • @Andrew & Earlz,这是作业,但是目前 SO 的态度是不应该使用作业标签,所以这就是我避免使用它的原因。另外,在第一段中,我说这是一个系统编程项目
  • 啊,我在 Meta 的更新还不够多,无法了解社区当前的偏好:P

标签: c compression bit-manipulation


【解决方案1】:

好的,因为这是作业,我只是给你一些提示而不给出解决方案。

首先,您确定在第一个文件中获得的 56 个字节是正确的字节吗?当然计数看起来不错,但是您很幸运计数(证明是第二个测试文件)。我可以立即看到代码中至少有两个关键错误。

为了确保您有正确的输出,字节数是不够的。你需要深入挖掘。如何一一检查字节本身。 63个字符是不是太多了嘿?有很多方法可以做到这一点。你可以使用od(一个非常好的Linux/Unix工具来查看文件的二进制内容,如果你在Windows上使用一些十六进制编辑器)。或者你可以从你的程序中打印出调试信息。

祝你好运。

【讨论】:

  • 好的,是统计数据收集代码中的错误,还是移位中的错误?此外,我通过 ddd 运行代码,并且打包的数组内容与我在纸上按照前 20 个元素的打包函数逻辑计算出的内容相匹配。
  • 哈,但是论文逻辑是否检查了代码是否按照您期望的方式工作?还是纸上逻辑检查代码是否与实际需求匹配?打包函数逻辑没问题,就是你如何使用打包函数逻辑坏了。
  • 你这是什么意思?发送给函数的值基于循环计数器,从而避免了数组溢出。此外,论文逻辑是独立验证移位是否正常,因此错误必须与开关变量有关。我在正确的轨道上吗?
  • 就像我说的,在你的小测试文件上逐字节检查输出,你就会得到答案。它应该跳进你的眼睛。请记住有两个关键错误。
  • 我找到了其中之一。打包器功能从 0-7 开始工作,但是当循环自行重置时,当它已经在打包 [6] 中表示时,我还包括缓冲区 [7]。关于其他的任何提示?
【解决方案2】:

为什么您期望输出比输入短 14%?除了最后一组之外,当您将一个字节存储到与输入字节一样多的次数时,它怎么可能呢?输出的大小将始终在输入大小的 7 以内。

【讨论】:

  • 原始文件大小为5344213字节,压缩后为4676193字节,比输入短12.5%。一个字节是位的 12.5%。
  • @Jason 您说压缩版本比原始版本短 3 个字节,并且您希望它短 14%。现在你说它是 4676193 字节,应该短 12.5%。下定决心。
  • @Jason “但是当循环自行重置时,当它已经在 packed[6] 中表示时,我还包括缓冲区 [7]”——这是我的观点;您的循环输出的字节数与读取的字节数一样多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多