【问题标题】:Reading from file into vector<T> line by line works incorrect for binary data C++逐行从文件读取到 vector<T> 对二进制数据 C++ 不正确
【发布时间】:2018-02-28 19:07:16
【问题描述】:

有一个模板可以从文件中填写vector &lt;T&gt;

template<typename T, typename A>
void fill_vector_from_file(const std::string  &filePath, std::vector<T, A> & target)
{
    std::ifstream is(filePath, std::ifstream::in);

    is.seekg(0, std::ifstream::end);
    std::size_t size = is.tellg();
    is.seekg(0, std::ifstream::beg);
    target.reserve(size);

std::string line;
while (std::getline(is, line))
{
    std::istringstream line_in(line);
    while (line_in)
    {
        T val = 0;
        if (line_in >> val)
        {
            target.push_back(val);
        }
    }
}
is.close();

文件中的数据可以是 int 或 binary 并且每行存储一个数字,例如:
对于 int

2 
-3
4

对于二进制

010
111
001

当我使用 std::vector&lt;int&gt; v1 检查模板中的整数时 和 std::vector&lt;unsigned char&gt; v2v2[0] 的结果是 0 而不是 010
(我想,我应该使用 unsigned char 来存储二进制文件)

问题:有没有办法修改模板,所以v2[0]的结果会如预期的那样(010)。

【问题讨论】:

  • unsigned char 的大小只有 1 个字节。您正在逐行读取文件作为文本文件。当然,将"2" 之类的行读取为int 可以正常工作,因为operator&gt;&gt; 支持这种转换。但是您不能将"010" 之类的行读为unsigned char。 STL 没有用于读取二进制数字字符串的 I/O 操纵器。显示的代码将读取单个字符,因此它将改为读取'0''1''0'。您必须添加额外的代码逻辑来读取"010" 行并应用您自己的转换逻辑将其转换为unsigned char (0x02)。
  • 真可惜。谢谢:D
  • 您必须读取第二个文件,知道数据存储为代表二进制的字符串。目前,您的模板中似乎没有这种检测。
  • >>我想,我应该使用 unsigned char 来存储二进制文件 你可以试试std::bitset&lt;3&gt; 输入T,然后再转换成unsigned char

标签: c++ templates binary stdvector


【解决方案1】:

第二个文件似乎包含二进制格式的字符串。假设它们总是 3 位长,在这种情况下,如果您使用 std::bitset&lt;3&gt;,您将完整读取每个数字。如果您使用unsigned char,那么您一次只能读取一个数字。这是您的功能,通过读取不同文件的示例(我想您事先知道的格式)稍作修改。另外,如果您需要,还有如何将std::bitset 向量转换为unsigned char 的示例。

#include <vector>
#include <iostream>
#include <string>
#include <fstream>
#include <bitset>
#include <algorithm> // std::transform

template<typename T, typename A>
void fill_vector_from_file(std::string const &filePath, std::vector<T, A> &vec)
{
    std::ifstream ifs(filePath);
    T val;

    while (ifs >> val)
        vec.push_back(val);
}

int main()
{
    // make sample files
    std::ofstream ofs("myfile.txt");
    ofs << "2\n" << "-3\n" << "4\n";
    ofs.close();
    ofs.open("myfile2.txt");
    ofs << "010\n" << "111\n" << "001\n";
    ofs.close();


    // fill <int> vector
    std::vector<int> vi;
    fill_vector_from_file("myfile.txt", vi);
    // print int vector
    for (auto n : vi)
        std::cout << n << std::endl;


    // fill <bitset> vector 
    std::vector<std::bitset<3>> vbs;
    fill_vector_from_file("myfile2.txt", vbs);
    // print bitset vector
    for (auto n : vbs)
        std::cout << n << std::endl;


    // [OPTIONAL] convert to vector <unsigned char>
    std::vector<unsigned char> vuc(vbs.size());
    std::transform(vbs.begin(), vbs.end(), vuc.begin(),
        [](std::bitset<3> const &bs) -> unsigned char { return static_cast<unsigned char>(bs.to_ulong()); });
    // print vector <unsigned char>
    for (auto n : vuc)
        std::cout << int(n) << std::endl;


    return 0;
}

工作演示:http://coliru.stacked-crooked.com/view?id=42aa04e34e4194c1

2
-3
4
010
111
001
2
7
1

【讨论】:

    【解决方案2】:

    这段代码有很多错误,但你原来的问题有以下答案:

    将 0-1 ASCII 字符串转换为整数。 val 类型为 unsigned char 的代码 line_in &gt;&gt; val 读取单个字符,例如“0”和“1”。您想将一个由 '0' 和 '1' 组成的 ASCII 字符串(形成一个以 2 为底的数字)转换为一个整数。 在这个SO answer 中,您会发现val = std::stoi(line, nullptr, 2); 会为您做到这一点。

    所以,“-3”和“101”都不是整数,而是字符串,它们表示以10为底和以2为底的整数,stoi()为您转换为整数。但是,对于 base-10,iostream operator&gt;&gt;() 也可以正常工作。 (你也可以看看std::setbase()。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-24
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 2019-02-11
      相关资源
      最近更新 更多