【问题标题】:How to read a matrix from a file? (c++)如何从文件中读取矩阵? (c++)
【发布时间】:2020-06-10 06:21:49
【问题描述】:

我一直在尝试很多东西并尝试搜索解决方案,但我所做的一切都不起作用。这甚至不是一件难事,但我这辈子都做不到。

基本上我有一个由 Matlab 生成的 .txt 文件,它是一个 640*480 矩阵。每个单元格有 2 个值,以逗号分隔。

我想从该文件中读取数据以创建一个包含我的 2 个值的 640*480 二维数组,以便我可以快速访问单元格以获取这两个值。

基本上,我正在做的是在 matlab 上进行一些图像分析,图像的每个像素都会给出 2 个值,稍后我将使用它们。我将 640*480 矩阵保存到 .txt 文件中。

完成后,我手动将该文件传输到我的 c++ 文件夹中。我的 c++ 代码跟踪标签的位置(中心坐标)。我想使用 c++ 代码访问该文件,以便我可以在 c++ 中创建我的数组,然后访问单元格以使用其中的 2 个值将它们显示在图像上(仅对应于标签中心坐标的单元格)。

P.S:我认为我无法使其工作的原因是因为 coma 将 2 个值分开,但我不知道如何解决这个问题。

只是为了让您更清楚地了解我的矩阵是什么样的:

1,1     1,2     1,3     1,4

2,1     2,2     2,3     2,4

3,1     3,2     3,3     3,4

4,1     4,2     4,3     4,4

【问题讨论】:

  • 请给我们看“一堆东西”。
  • 一种方法是:将文件中的一行读入字符串流。从字符串流中读取一个数字、一个逗号、一个数字、3 个空格……。

标签: c++ arrays matrix


【解决方案1】:

因此,解决方案是使用代理类。您的 Cell 的抽象。

如果您有一个包含 2 个值的单元格,那么我们将定义一个具有 2 个值的类,并覆盖该类的插入器和提取器运算符。只有类应该知道如何读取和写入其数据。

读取诸如“1,2”之类的内容的提取器相当简单。这是

stream >> value1 >> c >> value2;

所以,我们提取一个整数,然后是一个逗号,然后又是一个整数。所以,真的很简单。而且,由于该文件是由 Matlab 生成的,因此我们依赖于正确的输入格式。

因此,通过将大问题分解为小问题,我们可以找到更简单的解决方案。

接下来,如果我们有像1,1 1,2 1,3 1,4 这样的完整行,如何阅读。如果你用sn 替换x,y,那么你可以写

stream >> s1 >> s2 >> s3 >> s3;

但是如果元素的数量是未知的,那么我们需要遍历所有的值。为此,我们有std::istream_iterator。请阅读here。只要输入可用,它基本上会为给定类型调用提取器运算符>>。所以,如果类型是Cell,它会重复调用>> cell[n]

如果我们定义一个std::vector,我们可以使用它的范围构造函数来填充std::vector。请阅读here 中关于 5 号构造函数的信息。开始迭代器将是 std::istream_operator 的构造函数,结束迭代器将是通过 {} 构造的默认 std::istream_iterator。见Constructor number 1

这将导致:

std::vector<Cell> lineVector(std::istream_iterator<Cell>(lineStream), {})

请注意,我们对std::vector&lt;Cell&gt;```=CV```` 使用 typedef(使用),这使编写更简单。这样,我们得到:

CV lineVector(std::istream_iterator<Cell>(lineStream), {})

好的,现在我们有了完整的解析行。

此外,我们还有一个结果std::vector,其中包含上述所有数据。

要将这样的解析行添加到生成的“单元格”-vector,我们现在可以使用push_back 函数。但我们可以更好地使用emplace_back 函数,避免临时线向量并进行就地构造。

所有这一切最终将在:

cells.emplace_back(CV(std::istream_iterator<Cell>(lineStream), {}));

所以,我们将有一个非常简单的机制来解析完整的文件。

请看下面的具体解决方案。

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>

std::istringstream testStream{R"(1,1     1,2     1,3     1,4
2,1     2,2     2,3     2,4
3,1     3,2     3,3     3,4
4,1     4,2     4,3     4,4)"};

// Proxy class to abstract a Cell
struct Cell {

    int value1{};
    int value2{};

    // Overwrite exctractor
    friend std::istream& operator >> (std::istream& is, Cell& c) {
        char comma;
        return is >> c.value1 >> comma >> c.value2;
    }
    // Overwrite inserter
    friend std::ostream& operator << (std::ostream& os, const Cell& c) {
        return os << c.value1 << ',' << c.value2;
    }
};

using CV = std::vector<Cell>;

int main() {

    // The target data
    std::vector<CV> cells{};

    // Read and parse complete source file. 
    // Readd all lines of the source file
    for (std::string line{}; std::getline(testStream, line); ) {

        // Put the line into a stringstream
        std::istringstream lineStream{ line };

        // Parse the line data and add the result to our cells vector
        cells.emplace_back(CV(std::istream_iterator<Cell>(lineStream), {}));
    }


    // Show result on console
    // Go through all lines
    for (const CV& cv : cells) {
        // Go through all columns
        for (const Cell& c : cv) std::cout << c << '\t';
        std::cout << '\n';
    }
    return 0;
}

请注意:我们主要只有 3 行完成所有工作。

如果您还有其他问题,请提出。

【讨论】:

  • 我对其进行了测试并对其进行了调整以读取我的文件,它可以正常工作,谢谢。我有另一个似乎可以工作但不适用于我所有文件的程序。我有 640 行和 480 列,但由于某种原因我无法读取超过 640x404 的内容,因为它无法运行
  • 只是为了确保,当您说“覆盖”时,您的意思是“重载”运算符?或者是别的什么
  • 是的,我的意思是超载。抱歉,与新的 override 关键字有点混淆。关于你的其他问题。向量定义请在前面加上static。然后数据将存储在堆上。也许你遇到了堆栈大小的问题。请尝试。
  • 问题不在于你的答案,而在于我之前尝试自己做的事情。我没有在我尝试过的东西上使用向量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-21
相关资源
最近更新 更多