首页 > 解决方案 > 如何将二进制文件转换为 size_t?

问题描述

我试图理解指针和二进制文件,但我被困住了。我想将包含 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;

我什至无法读取第一个值。请帮助我,不管这件事,我已经坚持了很长时间。

标签: c++pointersbinarybufferfstream

解决方案


您编写的代码很好(减去缺少错误处理,并且无需使用&c_str()[0]whenc_str()本身就足够了)。

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

就像编写代码将size_tby 指针传递给一样ostream::write(),您也可以将size_tby 指针传递给istream::read()

尝试更多类似的东西:

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;
}

推荐阅读