Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用缓冲区和二进制文件_C++_Vector_Binary_Buffer - Fatal编程技术网

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;icout当您实际上想要一个指向
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;
}