我正在尝试以二进制格式编写文件。我有以下代码,但它以文本格式保存文件。
#include <iostream>
#include <fstream>
using namespace std;
int main(){
std::string ref = "Ecoli. 123";
unsigned int size = 124;
std::ofstream supp_info_output("binary_file", std::ios::out | std::ios::binary); // saving file
supp_info_output << ref << std::endl;
supp_info_output << size << std::endl;
supp_info_output.close();
std::ifstream supp_info_input("binary_file", std::ios::in | std::ios::binary); // loading file
std::string supp_info_line;
while( std::getline( supp_info_input, supp_info_line ).good() ){
std::cout << supp_info_line << std::endl;
}
supp_info_input.close();
}
在代码中,我正在编写一些数据,然后再次读取数据。读写没有问题,但我需要二进制格式的文件。
答案 0 :(得分:8)
使用ofstream::write来编写二进制数据,使用ifstream::read来读取它们。请注意,您应该保存字符串的长度,因为您应该知道要进一步读取多少字节。
std::string ref = "Ecoli. 123";
unsigned int size = 124;
std::ofstream supp_info_output("binary_file", std::ios::out | std::ios::binary); // saving file
unsigned int stringLength = ref.length();
supp_info_output.write( (char*)( &stringLength ), sizeof( stringLength ) );
supp_info_output.write( ref.c_str(), ref.length() );
supp_info_output.write( (char*)( &size ), sizeof( size ) );
supp_info_output.close();
以下是阅读方法:
std::string ref;
unsigned int size;
std::ifstream supp_info_input("binary_file", std::ios::in | std::ios::binary); // loading file
unsigned int stringLength;
supp_info_input.read( (char*)( &stringLength ), sizeof( stringLength ) );
ref.resize( stringLength );
supp_info_input.read( (char*)ref.c_str(), stringLength );
supp_info_input.read( (char*)( &size ), sizeof( size ) );
supp_info_input.close();
答案 1 :(得分:2)
对AwaitedOne的回答发表评论我不喜欢为每一个输出语句编写大量代码。相反,我更喜欢使用移位运算符重载,以使用户代码更容易,更不容易出错。
作为起点,给出以下示例。没有提供所有可能的重载,并且BinaryFile类不那么“准备生产”。它仅作为可编译的起点给出,以开始自己的调查。
请记住: 二进制文件不可移植,二进制表示可以从编译器/ libc / other的版本更改为版本。它还依赖于操作系统和系统的结束,以及体系结构(32对64位)和许多其他。
因此,除非您编写具有已定义的输入/输出格式的处理程序方法,否则通常不应使用二进制数据来使数据持久以供“稍后”使用。我的例子简单地写了数据存储的内存,这是非常愚蠢的,并导致所有问题都被提到。随意为可交换的二进制格式开始自己的“完美”实现。
但是,不应该重新发明,有人应该准备好使用已经到处都给出的实现。搜索“序列化器”,你会发现一组很好的库,比如boost serialize和许多其他库。
#include <fstream>
#include <cstring>
class BinaryOut: public std::ofstream
{
public:
BinaryOut( const char* fname ):
std::ofstream( fname, std::ios::binary )
{}
};
// use a generic func to use for everything which not handled in special way
template < typename DataType >
BinaryOut& operator << ( BinaryOut& out, const DataType& data )
{
out.write( (char*)&data, sizeof( DataType ));
return out;
}
// if pointer type, write not pointer but values which pointer points to:
template < typename DataType >
BinaryOut& operator << ( BinaryOut& out, const DataType*& data )
{
out.write( (char*)data, sizeof( DataType ));
return out;
}
// special case for char ptr ( old style c string ) which ends with '\0'
// use old style c here ( no std::string is involved )
BinaryOut& operator << ( BinaryOut& out, const char* ptr )
{
out.write( ptr, strlen( ptr ));
return out;
}
// may be some more overloads for << if needed...
int main()
{
BinaryOut out("example.bin");
int i=123;
double d=9.876;
double* ptrd=&d;
const char* dummy = "Ptr to Text";
out << i << d << ptrd << "Hallo, this is a test" << dummy;
}
答案 2 :(得分:1)
比用二进制文件写数据要困难一些。我建议使用C FILE *接口,因为许多C ++程序员重载&lt;&lt;和&gt;&gt;在文本模式下插入和提取更高级别的对象。当你转到二进制文件时,你会失去它。
要插入一个整数,您需要知道它是16位还是32位,big-endian还是little-endian。然后使用shift和mask并调用fputc()直接写入字节。要插入asciiz字符串,请同样调用fputc并确保编写nul。
答案 3 :(得分:0)
@Klaus是对的,如果你将int传递给&lt;&lt;在二进制文件中,它只是将文本写入文件。如果要将int二进制文件写入带有&lt;&lt;的文件,则应将字节流传递给&lt;&lt;。例如,在您的代码中,您需要每次使用&lt;&lt;来写入int的4个字节,然后将二进制int写入您的文件。您可以查看以下代码:
#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;
union data {
int i;
char bytes[4];
};
int main(){
data src;
src.i = 0xabcddcba;
std::ofstream supp_info_output("binary_file", ios::out | ios::binary); // saving file
supp_info_output << src.bytes[0];
supp_info_output << src.bytes[1];
supp_info_output << src.bytes[2];
supp_info_output << src.bytes[3];
supp_info_output.close();
data dst;
dst.i = 0;
std::ifstream supp_info_input("binary_file", ios::in | ios::binary); // loading file
supp_info_input >> dst.bytes[0];
supp_info_input >> dst.bytes[1];
supp_info_input >> dst.bytes[2];
supp_info_input >> dst.bytes[3];
supp_info_input.close();
std::cout << ((src.i == dst.i)?"Pass check.":"Failed check.") << std::endl;
getchar();
}
我认为&lt;&lt;的行为在二进制文件模式下是预期的,因为在二进制文件模式下,所有内容都应该被视为字节流而不管其类型如int,double,short int,...等。