我正在尝试为一个函数编写测试程序,将一个文件中的写入信息从一个文件转移到另一个文件。我很确定我的BitOutputStream类可以工作,因为下面的代码按预期打印出一个'A'。但是当我将代码更改为下面的第二个版本时,它接受输入文件并写入输出文件,输入与输出不匹配。我不确定我是否无意中改变了我不应该做的事情,或者输入文件中有某些“隐藏”字符会导致不匹配或字节转换。我怀疑我可能没有正确使用get()。任何帮助将不胜感激。
/ * first(working)version * /
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;
}
/ * second(非工作)版本* /
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被调用三次,但我预计它会被调用8次'A',那么为什么只有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
答案 0 :(得分: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进行AND运算,结果为0x01或二进制1.此位置于输出缓冲区中。 {strong> writeBit
剩余比特的遗漏位置。
当只有1个字符时,BitOutputStream
缓冲区只有1位。此外,您的程序从不调用BitOutputStream::flush()
,因此部分位永远不会输出到流。没有析构函数,因此当bos
对象被破坏而没有写入输出流时,不完整的字节(只有1位)消失。
由于你的第二个程序将一个8位的整个字节传递给一个只使用1位的函数,我推断你已经混淆了位和字节的概念。请参阅我上面解决您的问题的代码片段。
编辑2:测试BitOutputStream
类。
测试此类的最佳过程是从ostream
派生自己的类。此类应该有一个方法,您可以将期望的或已知值传递给。将此类的实例传递给BitOutputStream
。该类的put
方法可以将BitOutputStream
与预期或已知值的值进行比较。