0

我正在尝试为一个函数编写一个测试器,该函数将写入信息从一个文件一点一点地写入另一个文件。我很确定我的 BitOutputStream 类可以正常工作,因为下面的代码按预期打印出“A”。但是,当我将代码更改为下面的第二个版本时,该版本采用输入文件并写入输出文件,输入与输出不匹配。我不确定我是否无意中更改了我不应该更改的内容,或者输入文件具有某些“隐藏”字符,这些字符会导致不匹配或字节移位发生。我怀疑我可能没有正确使用 get() 。任何帮助将不胜感激。

/* 第一个(工作)版本 */

int main(int argc, char* argv[])
{
  BitOutputStream bos(std::cout);  // channel output to stdout
  bos.writeBit(1);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(1);

  // prints an 'A' as expected

  return 0;
}

/* 第二个(非工作)版本 */

int main(int argc, char* argv[])
{
  std::string ifileName = std::string(argv[1]);
  std::string ofileName = std::string(argv[2]);

  ofstream ofile;
  ifstream ifile;

  if(ifile)
    ifile.open(ifileName, ios::binary);
  if(ofile)
    ofile.open(ofileName, ios::binary);

  BitOutputStream bos(ofile);

  int i;
  while (ifile.good()) { 
    i = bos.writeBit(ifile.get()); // could the error be due to incorrect usage of get()?
    std::cout << i << std::endl;  // just to see how many bits have been processed
  }

    bos.flush();

    ifile.close();
    ofile.close();

    return i;
 }

我打电话的第一个版本

./a.out

我打电话的第二个版本

./a.out input output

它将 1 2 3 打印到终端指示 writeBit 被调用了 3 次,但我预计它会被 'A' 调用 8 次,那么为什么只调用 3 次呢?

输入文件中只有“A”。在输入文件上调用 hexdump 生成:

0000000 0a41
0000002

在输出文件上调用 hexdump 生成:

0000000 0005
0000001

另外为什么 hexdump 在 0a-'linefeed' 和 41-'A' 之前生成 7 个 0,最后的 '0000002' 是什么意思?我可以在代码的第二个版本中更改什么,以便输入和输出的 hexdump 匹配?

编辑:这是 BitOutputStream 的声明/定义

#ifndef BITOUTPUTSTREAM_HPP
#define BITOUTPUTSTREAM_HPP
#include <iostream>

class BitOutputStream {

private: 
  char buf;             // one byte buffer of bits
  int nbits;            // how many bits have been written to buf
  std::ostream& out;    // reference to the output stream to use

public:
  /* Initialize a BitOutputStream that will 
   * use the given ostream for output. 
   * */
  BitOutputStream(std::ostream& os) : out(os) {
    buf = nbits = 0;    // clear buffer and bit counter
  }

  /* Send the buffer to the output, and clear it */
  void flush() {
  out.put(buf);
  buf = nbits = 0;
  }


  /* Write the least sig bit of arg into buffer */
  int writeBit(int i) {
  // If bit buffer is full, flush it.
  if (nbits == 8) 
    flush();

  int lb = i & 1;      // extract the lowest bit
  buf |= lb << nbits;  // shift it nbits and put in in buf

  // increment index
  nbits++;

  return nbits;
  }
};

#endif // BITOUTPUTSTREAM_HPP
4

1 回答 1

1

问题是位与字节的概念。大多数函数使用的字节是位的集合。文件以字节为单位读取。您的writeBit方法写入位而不是字节。

如果您真的必须写入位,则需要读取字节,转换为位并写入每个位。(顺便说一句,大多数计算机在处理更大的单位时会更好,例如字节和字。)

#include <cstdint>
#include <iostream>

using namespace std; // Because I'm lazy and this is an example.

int main(void)
{
    uint8_t byte;
// Open the file
//....

//  Read file as bytes.
    while (ifile.read(&byte, sizeof(byte)))
    {
        for (unsigned int i = 0;
             i < CHAR_BIT; // number of bits in a byte
             ++i)
        {
            bos.writeBit(byte & 1);
            byte = byte >> 1;
        }
    }
//...
    return EXIT_SUCCESS;
}  

有更快的方法可以将一个文件的内容复制到另一个文件。首先想到的是让操作系统来做。

编辑1:程序分析。
该类BitOutputStream将累积传递给该writeBit方法的整数的最低有效位。一旦累积了 8 位,该writeBit方法就将一个字节写入输出流。

在第一个程序中,您传递的整数只有一个有效位,或者您假设整数常量只有一个有效位。

在第二个程序中,您通过istream::get()方法读入一个字节(8 位)。该writeBit方法仅查看最低有效位并将该位放入BitOutputStream缓冲区。然后循环从输入文件中获取另一个字节,并且仅将最低有效位附加到BitOutputStream缓冲区。

读取第 8 个字节后,BitOutputStream缓冲区将有 8 位,然后将一个 8 位字节写入流。

因此,如果我有一个文件只有一个“A”字符,即 0x41,或二进制 MSB:0100 0001。
writeBit方法将值与 0x1 进行与运算,结果为 0x01 或二进制 1。该位被放入输出缓冲器。 字节的剩余位被忽略writeBit

当只有 1 个字符时,BitOutputStream缓冲区只有 1 位。此外,您的程序永远不会调用BitOutputStream::flush(),因此部分位永远不会输出到流中。没有析构函数,因此当bos对象被析构并且没有任何内容写入输出流时,不完整的字节(只有 1 位)会消失。

由于您的第二个程序将 8 位的整个字节传递给仅使用 1 位的函数,因此我推断您混淆了位和字节的概念。请参阅我上面解决您的问题的代码片段。

编辑2:测试BitOutputStream类。
测试此类的最佳过程是从ostream. 此类应该有一个方法,您可以将预期已知值传递给该方法。将此类的实例传递给BitOutputStream. 类的put方法可以将值与BitOutputStream预期已知值进行比较。

于 2013-08-24T17:27:34.303 回答