目标是从二进制文件中读取16位有符号整数。首先,我以ifstream格式打开文件,然后我想使用istream_iterator将每个数字复制到vector中和copy算法。我不明白这段代码有什么问题:
int main(int argc, char *argv[]) {
std::string filename("test.bin");
std::ifstream is(filename);
if (!is) {
std::cerr << "Error while opening input filen";
return EXIT_FAILURE;
}
std::noskipws(is);
std::vector<int16_t> v;
std::copy(
std::istream_iterator<int16_t>(is),
std::istream_iterator<int16_t>(),
std::back_inserter(v)
);
//v is still empty
}
这段代码没有产生错误,但是在调用std::copy之后,vector仍然为空。。由于我是在标准输入模式下打开文件("text "模式),我期待istream_iterator即使文件是二进制文件也能工作。当然,对于这个类的行为,我还遗漏了一些东西。
首先,要使用ifstream
读取二进制文件,您需要以binary
模式打开文件,而不是文本模式(默认模式)。否则,读操作可能会错误地解释换行字节并在平台编码之间转换它们(例如,CRLF->LF,反之亦然),从而损坏二进制数据。
第二,istream_iterator
使用operator>>
,它默认读取和解析格式的文本,这不是您在读取二进制文件时想要的。您需要使用istream::read()
代替。然而,没有这样的迭代器包装器(但如果需要,您可以自己编写)。
试试这个:
int main(int argc, char *argv[]) {
std::string filename = "test.bin";
std::ifstream is(filename, std::ifstream::binary);
if (!is) {
std::cerr << "Error while opening input filen";
return EXIT_FAILURE;
}
std::vector<int16_t> vec;
int16_t value;
while (is.read(reinterpret_cast<char*>(&value), sizeof(value))) {
// swap value's endian, if needed...
vec.push_back(value);
}
// use vec as needed...
return 0;
}
也就是说,如果你真的想用istream_iterator
作为二进制文件,那么你必须写一个自定义类/结构来包装int16_t
,然后为该类型定义一个operator>>
来调用read()
,例如:
struct myInt16_t {
int16_t value;
operator int16_t() const { return value; }
};
std::istream& operator>>(std::istream &is, myInt16_t &v) {
if (is.read(reinterpret_cast<char*>(&v.value), sizeof(v.value))) {
// swap v.value's endian, if needed...
}
return is;
}
int main(int argc, char *argv[]) {
std::string filename = "test.bin";
std::ifstream is(filename, std::ifstream::binary);
if (!is) {
std::cerr << "Error while opening input filen";
return EXIT_FAILURE;
}
std::noskipws(is);
std::vector<int16_t> vec;
std::copy(
std::istream_iterator<myInt16_t>(is),
std::istream_iterator<myInt16_t>(),
std::back_inserter(vec)
);
// use vec as needed...
return 0;
}
由于我以标准输入模式打开文件("text "模式),我希望istream_iterator即使文件是二进制文件也能工作。
你在概念上把它颠倒了。由于文件是二进制的1,所以即使文件以文本模式2打开,您也不应该期望istream_iterator
工作。文件的格式决定了你可以用它做什么;没有任何工具可以读取格式化为人类可读文本的"数字"。从文件中读取,除非文件实际上打算以这种方式读取。您的文件大概是打算作为"字节对"来读取的,每个字节对表示一个16位的数值,因此您需要与该格式兼容的工具。文件模式只是拼图的一小部分。
要有意义地遍历文件,您需要以二进制模式打开它(以避免在Windows平台上损坏)并且使用能够以您想要的方式解释二进制数据的工具。您还需要确保正确地考虑了数据。尝试使用noskipws
之类的东西是没有意义的,因为数据没有空白的概念,因为它不代表文本。
-
严格来说,这并不意味着什么;但一般来说,说一个文件是二进制文件提示文件内容为而不是为了便于人类阅读,数值的表示方式与它们在计算机内存中的表示方式一样,即直接以256为基数,而不是。使用字节来表示文本,而文本又使用阿拉伯数字、
.
符号等来表示数字。 -
以文本模式打开文件"这取决于您使用的语言和平台。在许多语言中(包括C和c++),它对Windows的影响很小(基本上只是翻译CR-LF序列),在类似linux的平台上没有影响(至少我最近检查过)。在某些情况下(如Python 3.x),它会自动引入将字节转换为表示实际文本的对象的机制,实际上是使用编码而不是假装字节是字符;(他们不是)。