所以我有一个包含三个数字的 vector 。 65、66 和 67。我将这些数字从 int 转换为二进制并将它们附加到一个字符串中。字符串变为 100000110000101000011(分别为 65、66、67)。我正在通过 dynamic_bitset 库将此数据写入文件。我有 BitOperations 类,它可以读取和写入文件。当我从文件中读取数据而不是给出上述位时,它给了我这些 001100010100001000001 位。
这是我的 BitOperations 类:
#include <iostream>
#include <boost/dynamic_bitset.hpp>
#include <fstream>
#include <streambuf>
#include "Utility.h"
using namespace std;
using namespace boost;
template <typename T>
class BitOperations {
private:
T data;
int size;
dynamic_bitset<unsigned char> Bits;
string fName;
int bitSize;
public:
BitOperations(dynamic_bitset<unsigned char> b){
Bits = b;
size = b.size();
}
BitOperations(dynamic_bitset<unsigned char> b, string fName){
Bits = b;
this->fName = fName;
size = b.size();
}
BitOperations(T data, string fName, int bitSize){
this->data = data;
this->fName = fName;
this->bitSize = bitSize;
}
BitOperations(int bitSize, string fName){
this->bitSize = bitSize;
this->fName = fName;
}
void writeToFile(){
if (data != ""){
vector<int> bitTemp = extractIntegersFromBin(data);
for (int i = 0; i < bitTemp.size(); i++){
Bits.push_back(bitTemp[i]);
}
}
ofstream output(fName, ios::binary| ios::app);
ostream_iterator<char> osit(output);
to_block_range(Bits, osit);
cout << "File Successfully modified" << endl;
}
dynamic_bitset<unsigned char> readFromFile(){
ifstream input(fName);
stringstream strStream;
strStream << input.rdbuf();
T str = strStream.str();
dynamic_bitset<unsigned char> b;
for (int i = 0; i < str.length(); i++){
for (int j = 0; j < bitSize; ++j){
bool isSet = str[i] & (1 << j);
b.push_back(isSet);
}
}
return b;
}
};
这是调用这些操作的代码:#include <iostream>
// #include <string.h>
#include <boost/dynamic_bitset.hpp>
#include "Utility/BitOps.h"
int main(){
vector<int> v;
v.push_back(65);
v.push_back(66);
v.push_back(67);
stringstream ss;
string st;
for (int i = 0; i < v.size(); i++){
ss = toBinary(v[i]);
st += ss.str().c_str();
cout << i << " )" << st << endl;
}
// reverse(st.begin(), st.end());
cout << "Original: " << st << endl;
BitOperations<string> b(st, "bits2.bin", 7);
b.writeToFile();
BitOperations<string>c(7, "bits2.bin");
boost::dynamic_bitset<unsigned char> bits;
bits = c.readFromFile();
string s;
// for (int i = 0; i < 16; i++){
to_string(bits, s);
// reverse(s.begin(), s.end());
// }
cout << "Decompressed: " << s << endl;
}
我做错了什么导致不正确的行为?编辑:这是 extractIntegersFromBin(string s) 函数。
vector<int> extractIntegersFromBin(string s){
char tmp;
vector<int> nums;
for (int i = 0; s[i]; i++ ){
nums.push_back(s[i] - '0');
}
return nums;
}
编辑 2:这是 toBinary 的代码:stringstream toBinary(int n){
vector<int> bin, bin2;
int i = 0;
while (n > 0){
bin.push_back(n % 2);
n /= 2;
i++;
}
// for (int j = i-1; j >= 0; j--){
// bin2.push_back(bin[j]);
// }
reverse(bin.begin(), bin.end());
stringstream s;
for (int i = 0; i < bin.size(); i++){
s << bin[i];
}
return s;
}
最佳答案
您面临两个不同的问题:
to_block_range
通过在末尾附加零,将输出填充到内部块大小。在您的情况下,内部块大小为 sizeof(unsigned char)*8 == 8
.因此,如果您写入文件中的位序列 writeToFile
不是 8
的倍数, 附加 0
s 将被写成 8
的倍数.所以如果你用 readFromFile
读回位序列,您必须找到某种方法再次删除填充位。让我们分别讨论每个问题:
关于问题1
我知道您想使用
bitSize
定义自己的块大小。变量,在 boost::dynamic_bitset
的内部块大小之上.例如,在您的 main
方法,你构造BitOperations<string> c(7, "bits2.bin");
.我理解这意味着您希望存储在文件中的位序列的长度是 7
的倍数。 .如果这个理解正确,可以去掉
to_block_range
已经插入的填充位。通过读取文件大小,然后将其四舍五入到最接近的块大小倍数。尽管您应该注意,您目前并未在 BitOperation
中执行此契约(Contract)。构造函数或在 writeToFile
(即通过确保数据大小是 7
的倍数)。在您的
readFromFile
方法,首先注意内循环错误地取了blockSize
考虑到。所以如果 blockSize
是 7
,这错误地只考虑第一个 7
每个块的位。而由 to_block_range
写入的块使用完整8
每个位 1
-byte 块,因为 boost::dynamic_bitset
对您的 7
一无所知-位块大小。所以这会让你错过一些位。以下是如何修复代码的一个示例:
size_t bitCount = (str.length()*8) / bitSize * bitSize;
size_t bitsPerByte = 8;
for (int i = 0; i < bitCount; i++) {
size_t index = (i / bitsPerByte);
size_t offset = (i % bitsPerByte);
bool isSet = (str[index] & ( 1 << offset));
b.push_back(isSet);
}
此示例首先通过将文件大小四舍五入到块大小的最接近倍数来计算总共应读取多少位。然后它遍历输入中的完整字节(即由 boost::dynamic_bitset
写入的内部块),直到读取了目标位数。剩余的填充位被丢弃。另一种方法是使用
boost::from_block_range
.这允许您摆脱一些样板代码(即将输入读入一些字符串缓冲区): dynamic_bitset<unsigned char> readFromFile() {
ifstream input{fName};
// Get file size
input.seekg(0, ios_base::end);
ssize_t fileSize{input.tellg()};
// TODO Handle error: fileSize < 0
// Reset to beginning of file
input.clear();
input.seekg(0);
// Create bitset with desired size
size_t bitsPerByte = 8;
size_t bitCount = (fileSize * bitsPerByte) / bitSize * bitSize;
dynamic_bitset<unsigned char> b{bitCount};
// TODO Handle error: fileSize != b.num_blocks() * b.bits_per_block / bitsPerByte
// Read file into bitset
std::istream_iterator<char> iter{input};
boost::from_block_range(iter, {}, b);
return b;
}
关于问题2一旦你解决了问题 1,
boost::dynamic_bitset
由 writeToFile
写入文件将与 readFromFile
读取的相同.如果您使用相同的方法打印两者,则输出将匹配。但是,如果您使用不同的打印方法,并且这些方法在打印位的顺序上不一致,则会得到不同的结果。例如,在程序的输出中,您现在可以看到“Original:”输出与“Decompressed:”相同,但顺序相反:
Original: 100000110000101000011
...
Decompressed: 110000101000011000001
同样,这并不意味着 readFromFile
工作不正确,只是您使用不同的方式打印位序列。Original:
的输出直接打印0
获得/1
输入字符串 main
从左到右。在 writeToFile
,然后这个字符串按照与 extractIntegersFromBin
相同的顺序分解并将每一位传递给 push_back
boost::dynamic_bitset
的方法. push_back
方法附加到位序列的末尾,这意味着它会将您传递的每个位解释为比前一个更重要( reference ):Effects: Increases the size of the bitset by one, and sets the value of the new most-significant bit to value.
因此,您的输入字符串被解释为输入字符串中的第一位是最低有效位(即序列的“第一个”位),而输入字符串的最后一位是最高有效位(即“最后”位序列)。
而您使用
to_string
构建“解压缩:”的输出.从该方法的文档中,我们可以看到位序列的最低有效位将是 最后 输出字符串的位( reference ):Effects: Copies a representation of b into the string s. A character in the string is '1' if the corresponding bit is set, and '0' if it is not. Character position i in the string corresponds to bit position b.size() - 1 - i.
所以问题很简单,
to_string
(按设计)与您手动打印输入字符串的顺序相反的打印顺序。因此,要解决此问题,您必须反转其中之一,即通过以相反的顺序迭代字符串来打印输入字符串,或反转 to_string
的输出.
关于c++ - 从文件中读取动态bitset写入的数据无法读取正确的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65547187/