【问题标题】:How do I convert a binary file to size_t?如何将二进制文件转换为 size_t?
【发布时间】:2020-08-20 18:11:50
【问题描述】:

我试图理解指针和二进制文件,但我被卡住了。我想将包含 5 个水果的列表写入二进制文件。所以首先我尝试写 (size_t) 5,然后为每个水果片写它的大小,然后是字符串本身。 这是我到目前为止得到的:

// Write
vector<string> fruit_list = {"Apple", "Pear", "Banana", "Cherry", "Melon"};
ofstream fruits_out;
fruits_out.open("fruits.bin", std::ios::binary | std::ios::out);
size_t fruit_total = fruit_list.size();
fruits_out.write((char*)&fruit_total, sizeof(fruit_total));
for (const string& fruit : fruit_list){
    size_t fruit_size = fruit.size();
    fruits_out.write((char*)&fruit_size, sizeof(fruit_size));
    fruits_out.write(&fruit.c_str()[0], fruit_size);
}
fruits_out.close();

// Read
ifstream fruits_in;
fruits_in.open ("fruits.bin", std::ios::binary | std::ios::in);
char *buffer = new char;
fruits_in.read((char*)&buffer, sizeof(size_t));
cout << *buffer << endl;

我什至无法读取第一个值。 请帮帮我,没关系,我坚持了很久。

【问题讨论】:

  • 您只为单个字符分配了空间。
  • 文件是字节流。在将数据写入文件或从文件读取数据之前,您应该记录要写入和读取的精确字节流。您将写入多少字节来存储大小?每个字节的值是多少?我强烈建议你在编写代码之前这样做——它会让你的生活变得更轻松。
  • 但是我必须先缓冲到 char 类型对吧?
  • 您似乎认为传递给read() 的指针必须使用new 创建。这不是真的。附言对,一个“char 类型的缓冲区”。但是“1 个字符的缓冲区”和“10 亿个字符的缓冲区”之间存在很大差异。它们都是“char 类型的缓冲区”,但只有一个可以用于 read() size_t 的字符,而不会导致内存损坏。
  • 请将代码放在您的帖子中,而不是在评论部分。

标签: c++ pointers binary buffer fstream


【解决方案1】:

您的代码写得很好(减去错误处理的不足,当c_str() 本身就足够时,不需要使用&amp;c_str()[0])。

但是,您的阅读代码全错了。您不仅要分配一个大小仅为 1 字节的 buffer,然后您还要尝试将 sizeof(size_t) 的字节数读入其中。但更糟糕的是,您正在读取buffer 变量所在的堆栈空间,而不是您分配的buffer 指向的动态内存!

就像编写代码通过指向ostream::write() 的指针传递size_t 一样,您也可以通过指向istream::read() 的指针传递size_t

试试这样的:

std::ostream& writeSizeT(std::ostream &out, size_t value)
{
    out.write(reinterpret_cast<char*>(&value), sizeof(value));

    /* alternatively:
    uint64_t temp = htobe64(value); // or equivalent...
    out.write(reinterpret_cast<char*>(&temp), sizeof(temp));
    */

    return out;
}

std::ostream& writeString(std::ostream &out, const std::string &value)
{
    size_t size = value.size();
    if ((writeSizeT(out, size)) && (size > 0)) {
        out.write(value.c_str(), size);
    }
    return out;
}

std::ostream& writeFruitList(std::ostream &out, const std::vector<std::string> &list)
{
    if (writeSizeT(out, list.size())) {
        for (const std::string &fruit : list){
            if (!writeString(out, fruit)) {
                break;
            }
        }
    }
    return out;
}

std::vector<std::string> fruit_list = {"Apple", "Pear", "Banana", "Cherry", "Melon"};
std::ofstream fruits_out("fruits.bin", std::ios::binary);
writeFruitList(fruits_out, fruit_list);
fruits_out.close();
std::istream& readSizeT(std::istream &in, size_t &value)
{
    in.read(reinterpret_cast<char*>(&value), sizeof(value));

    /* alternatively:
    uint64_t temp;
    if (in.read(reinterpret_cast<char*>(&temp), sizeof(temp))) {
        temp = be64toh(temp); // or equivalent...
        value = static_cast<size_t>(temp);
    }
    */

    return in;
}

std::istream& readString(std::istream &in, std::string &value)
{
    value.clear();
    size_t size;
    if ((readSizeT(in, size)) && (size > 0)) {
        value.resize(size);
        in.read(&value[0]/*or: value.data()*/, size);
    }
    return in;
}

std::istream& readFruitList(std::istream &in, std::vector<std::string> &list)
{
    list.clear();
    size_t size;
    if (readSizeT(in, size)) {
        list.reserve(size);
        std::string fruit;
        for (size_t i = 0; (i < size) && (readString(in, fruit)); ++i){
            list.push_back(std::move(fruit));
        }
    }
    return in;
}

std::vector<std::string> fruit_list;
std::ifstream fruits_in("fruits.bin", std::ios::binary);
readFruitList(fruits_in, fruit_list);
fruits_out.close();

for (const auto &fruit: fruit_list) {
    std::cout << fruit << std::endl;
}

【讨论】:

    猜你喜欢
    • 2017-07-11
    • 2015-11-07
    • 2017-06-28
    • 1970-01-01
    • 2021-01-07
    • 2020-03-16
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    相关资源
    最近更新 更多