C++ 如何使用缓冲区和二进制文件
我试图将每个字符串的向量写入二进制文件,然后将其读回。我不能再往前走了,因为我的缓冲区有问题。我试着把它当作一个字符,但我不能 代码:C++ 如何使用缓冲区和二进制文件,c++,vector,binary,buffer,C++,Vector,Binary,Buffer,我试图将每个字符串的向量写入二进制文件,然后将其读回。我不能再往前走了,因为我的缓冲区有问题。我试着把它当作一个字符,但我不能 代码: #包括 #包括 #包括 #包括 使用名称空间std; 无效写入_bin(){ 向量向量向量={“Text1”、“Text2”、“Text3”、“Text4”}; 流bin|u out(“binary.bin”,ios::binary | ios::out | ios::trunc); 如果(!bin_out.is_open()){ //首先设置vec的n个大小
#包括
#包括
#包括
#包括
使用名称空间std;
无效写入_bin(){
向量向量向量={“Text1”、“Text2”、“Text3”、“Text4”};
流bin|u out(“binary.bin”,ios::binary | ios::out | ios::trunc);
如果(!bin_out.is_open()){
//首先设置vec的n个大小
bin_out.write((char*)vec.size(),sizeof(int));
for(字符串s:vec){
尺寸=s.尺寸();
bin_out.write((char*)大小,sizeof(size));
bin_out.写入(&s[0],大小);
}
bin_out.close();
}
}
无效读_bin(){
ifstream bin|u in(“binary.bin”,ios::binary | ios::in);
字符串s;
字符*缓冲区;
bin_in.read(缓冲区,sizeof(int));
对于(int i=0;i cout当您实际上想要一个指向size
中存储内容的指针时,您正在强制转换以使size
的值成为指针
所以
应该是
size_t size = s.size();
bin_out.write(reinterpret_cast<const char*>(&size), sizeof(size));
…但请阅读下文,了解如何正确地将二进制格式的大小写入文件或从文件中读取大小
正确的方法是什么
除非您计划存储包含\0
或\n
的字符串,否则使用4或8个字节(通常大小为的大小)来存储大小只是一种浪费,而且由于您没有考虑到endianess,因此会使您的代码不可移植
我建议使用\0
或\n
来标记字符串的结尾,并使用getline
将其读回
如果您想在存储真正大的向量的大小时节省几个字节,请确保以可在所有平台上读取的格式存储它。您当前以不可移植的格式存储它
size\u t
并非在所有平台上都具有相同的sizeof(size\u t)
- 并非所有平台上的持久性都相同
以平台无关的方式存储大小的尝试可能是使用函数在本机格式和文件中存储的格式之间来回转换。您可能有可用的htons
/ntohs
和htonl
/ntohl
函数,或者您可以编写自己的函数
C++20中的朴素实现:
using size_type = std::uint16_t; // use a fixed width type to store sizes
size_type convert_size(std::size_t value) {
if(value > std::numeric_limits<size_type>::max())
throw std::length_error("value to big: " + std::to_string(value));
size_type retval = value;
// decide on a format that can be read on all platforms.
static_assert(std::endian::native == std::endian::little ||
std::endian::native == std::endian::big,
"Mixed endianess not supported");
// Here I've opted to go for big endian:
if constexpr (std::endian::native != std::endian::big) {
// swap the byte order if your platform uses little endianess
std::reverse(reinterpret_cast<char*>(&retval),
reinterpret_cast<char*>(&retval) + sizeof(retval));
}
return retval;
}
使用size\u type=std::uint16\u t;//使用固定宽度类型存储大小
大小类型转换大小(标准::大小值){
如果(值>标准::数值限制::最大值())
抛出std::length_错误(“值到大:”+std::to_字符串(值));
大小\类型retval=值;
//确定可在所有平台上读取的格式。
静态断言(std::endian::native==std::endian::little)||
std::endian::native==std::endian::big,
“不支持混合端性”);
//在这里,我选择了big endian:
if constexpr(std::endian::native!=std::endian::big){
//如果您的平台使用小端,请交换字节顺序
标准::反向(重新解释和重新转换),
重新解释铸型(&retval)+尺寸(retval));
}
返回返回;
}
然后是一个程序,如:
int main() {
size_t foo = 100;
auto size_to_write_to_file = convert_size(foo);
std::cout << size_to_write_to_file << '\n';
size_t size_read_from_file = size_to_write_to_file;
std::cout << convert_size(size_read_from_file) << '\n';
}
intmain(){
尺寸_t foo=100;
自动将大小写入文件=转换大小(foo);
std::cout您正在强制转换以使size
的值成为指针,而实际上您需要一个指向size
中存储内容的指针
所以
应该是
size_t size = s.size();
bin_out.write(reinterpret_cast<const char*>(&size), sizeof(size));
…但请阅读下文,了解如何正确地将二进制格式的大小写入文件或从文件中读取大小
正确的方法是什么
除非您计划存储包含\0
或\n
的字符串,否则使用4或8个字节(通常大小为的大小)来存储大小只是一种浪费,而且由于您没有考虑到endianess,因此会使您的代码不可移植
我建议使用\0
或\n
来标记字符串的结尾,并使用getline
将其读回
如果您想在存储真正大的向量的大小时节省几个字节,请确保以可在所有平台上读取的格式存储它。您当前以不可移植的格式存储它
size\u t
并非在所有平台上都具有相同的sizeof(size\u t)
- 并非所有平台上的持久性都相同
以平台无关的方式存储大小的尝试可能是使用函数在本机格式和文件中存储的格式之间来回转换。您可能有可用的htons
/ntohs
和htonl
/ntohl
函数,或者您可以编写自己的函数
C++20中的朴素实现:
using size_type = std::uint16_t; // use a fixed width type to store sizes
size_type convert_size(std::size_t value) {
if(value > std::numeric_limits<size_type>::max())
throw std::length_error("value to big: " + std::to_string(value));
size_type retval = value;
// decide on a format that can be read on all platforms.
static_assert(std::endian::native == std::endian::little ||
std::endian::native == std::endian::big,
"Mixed endianess not supported");
// Here I've opted to go for big endian:
if constexpr (std::endian::native != std::endian::big) {
// swap the byte order if your platform uses little endianess
std::reverse(reinterpret_cast<char*>(&retval),
reinterpret_cast<char*>(&retval) + sizeof(retval));
}
return retval;
}
使用size\u type=std::uint16\u t;//使用固定宽度类型存储大小
大小类型转换大小(标准::大小值){
如果(值>标准::数值限制::最大值())
抛出std::length_错误(“值到大:”+std::to_字符串(值));
大小\类型retval=值;
//确定可在所有平台上读取的格式。
静态断言(std::endian::native==std::endian::little)||
std::endian::native==std::endian::big,
“不支持混合端性”);
//在这里,我选择了big endian:
if constexpr(std::endian::native!=std::endian::big){
//如果您的平台使用小端,请交换字节顺序
标准::反向(重新解释和重新转换),
重新解释铸型(&retval)+尺寸(retval));
}
返回返回;
}
然后是一个程序,如:
int main() {
size_t foo = 100;
auto size_to_write_to_file = convert_size(foo);
std::cout << size_to_write_to_file << '\n';
size_t size_read_from_file = size_to_write_to_file;
std::cout << convert_size(size_read_from_file) << '\n';
}
intmain(){
尺寸_t foo=100;
汽车
int main() {
size_t foo = 100;
auto size_to_write_to_file = convert_size(foo);
std::cout << size_to_write_to_file << '\n';
size_t size_read_from_file = size_to_write_to_file;
std::cout << convert_size(size_read_from_file) << '\n';
}
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
struct MyData {
// Our vectro with strings
std::vector<std::string> text{};
// Override extractor operator
friend std::istream& operator >> (std::istream& is, MyData& md) {
for (std::string line{}; std::getline(is, line); md.text.emplace_back(std::move(line)));
return is;
}
// overwrite inserter operator
friend std::ostream& operator << (std::ostream& os, const MyData& md) {
std::copy(md.text.begin(), md.text.end(), std::ostream_iterator<std::string>(os, "\n"));
return os;
}
};
const std::string fileName{"test.txt"};
int main() {
// Our test data
MyData myData1{ {"text1", "text2", "text3"} };;
// Open file for writing and check, if it could be opened.
if (std::ofstream ofs{ fileName }; ofs) {
// Write all data from test vector to file
ofs << myData1;
}
else std::cerr << "\n\nError. Could not open file '" << fileName << "' for writing\n\n";
// Open file for reading and check, if it could be opened.
if (std::ifstream ifs{ fileName }; ifs) {
// We will read from the file to this new variable
MyData myData2{};
// Read all data from file
ifs >> myData2;
// Show result on screen
std::cout << myData2;
}
else std::cerr << "\n\nError. Could not open file '" << fileName << "' for reading\n\n";
return 0;
}