C ++程序,用于读取数组中具有恒定(但未知)列数的未知大小的csv文件(仅用浮点数填充)

Ale*_*sse 1 c c++ csv file-io matlab

我想知道是否有人可以帮助我尝试构建一个程序,以从csv文件读取大小未知的浮点大数据块。我已经在MATLAB中编写了此代码,但希望对其进行编译和分发,因此转向c ++。

我只是学习并尝试阅读以开始

7,5,1989
2,4,2312
Run Code Online (Sandbox Code Playgroud)

从文本文件。

到目前为止的代码。

// Read in CSV
//
// Alex Byasse

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <stdlib.h>

int main() {

    unsigned int number_of_lines = 0;
    FILE *infile = fopen("textread.csv", "r");
    int ch;
    int c = 0;
    bool tmp = true;
    while (EOF != (ch=getc(infile))){
      if(',' == ch){
    ++c;
      }
      if ('\n' == ch){
    if (tmp){
      int X = c;
      tmp = false;
    }
            ++number_of_lines;
    }
    }
    fclose(infile);

  std::ifstream file( "textread.csv" );

  if(!file){
    std:cerr << "Failed to open File\n";
    return 1;
  }

  const int ROWS = X;
  const int COLS = number_of_lines;
  const int BUFFSIZE = 100;
  int array[ROWS][COLS];
  char buff[BUFFSIZE];
  std::string line; 
  int col = 0;
  int row = 0;
  while( std::getline( file, line ) )
  {
    std::istringstream iss( line );
    std::string result;
    while( std::getline( iss, result, ',' ) )
      {
        array[row][col] = atoi( result.c_str() );
        std::cout << result << std::endl;
        std::cout << "column " << col << std::endl;
        std::cout << "row " << row << std::endl;
        col = col+1;
    if (col == COLS){
    std:cerr << "Went over number of columns " << COLS;
    }
      }
    row = row+1;
    if (row == ROWS){
      std::cerr << "Went over length of ROWS " << ROWS;
    }
    col = 0;
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我使用的Matlab代码是>>

fid = fopen(twoDM,'r');

s = textscan(fid,'%s','Delimiter','\n');
s = s{1};
s_e3t = s(strncmp('E3T',s,3));
s_e4q = s(strncmp('E4Q',s,3));
s_nd = s(strncmp('ND',s,2));

[~,cell_num_t,node1_t,node2_t,node3_t,mat] = strread([s_e3t{:}],'%s %u %u %u %u %u');
node4_t = node1_t;
e3t = [node1_t,node2_t,node3_t,node4_t];
[~,cell_num_q,node1_q,node2_q,node3_q,node_4_q,~] = strread([s_e4q{:}],'%s %u %u %u %u %u %u');
e4q = [node1_q,node2_q,node3_q,node_4_q];
[~,~,node_X,node_Y,~] = strread([s_nd{:}],'%s %u %f %f %f');

cell_id = [cell_num_t;cell_num_q];
[~,i] = sort(cell_id,1,'ascend');

cell_node = [e3t;e4q];
cell_node = cell_node(i,:);
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏。亚历克斯

Die*_*ühl 5

很明显,我只会使用IOStreams。从CSV文件中读取同构数组或多个数组,而不必理会任何引用是很简单的:

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

std::istream& comma(std::istream& in)
{
    if ((in >> std::ws).peek() != std::char_traits<char>::to_int_type(',')) {
        in.setstate(std::ios_base::failbit);
    }
    return in.ignore();
}

int main()
{
    std::vector<std::vector<double>> values;
    std::istringstream in;
    for (std::string line; std::getline(std::cin, line); )
    {
        in.clear();
        in.str(line);
        std::vector<double> tmp;
        for (double value; in >> value; in >> comma) {
            tmp.push_back(value);
        }
        values.push_back(tmp);
    }

    for (auto const& vec: values) {
        for (auto val: vec) {
            std::cout << val << ", ";
        }
        std::cout << "\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

给定文件的简单结构,实际上可以简化逻辑:如果不自动读取分隔符,则可以将每一行视为一系列值,而不是单独读取值。由于逗号不会被自动读取,因此在为内部行创建字符串流之前,逗号将被替换为空格。相应的代码变为

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

int main()
{
    std::vector<std::vector<double> > values;
    std::ifstream fin("textread.csv");
    for (std::string line; std::getline(fin, line); )
    {
        std::replace(line.begin(), line.end(), ',', ' ');
        std::istringstream in(line);
        values.push_back(
            std::vector<double>(std::istream_iterator<double>(in),
                                std::istream_iterator<double>()));
    }

    for (std::vector<std::vector<double> >::const_iterator
             it(values.begin()), end(values.end()); it != end; ++it) {
        std::copy(it->begin(), it->end(),
                  std::ostream_iterator<double>(std::cout, ", "));
        std::cout << "\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

这是发生了什么:

  1. 目的地values定义为的向量的向量double。没有什么可以保证不同的行具有相同的大小,但是一旦读取文件就很难检查。
  2. 一个std::ifstream被定义并与文件初始化。构造后可能值得检查文件,以查看是否可以将其打开以进行读取(if (!fin) { std::cout << "failed to open...\n";)。
  3. 一次处理文件一行。只需使用std::getline()将行读入即可读取这些行std::string。如果std::getline()失败,则无法读取另一行,转换结束。
  4. 一旦line被读取,所有的逗号之间用空格代替。
  5. 根据这样修改的,line构成用于读取行的字符串流。原始代码重用了std::istringstream在循环外部声明的a ,以节省始终构造流的成本。由于流在行结束时变坏,因此首先需要对其进行in.clear()ed设置in.str(line)
  6. 单个值使用进行迭代,std::istream_iterator<double>后者仅从构造它的流中读取一个值。给定的迭代器in是序列的开始,默认构造的迭代器是序列的结束。
  7. 迭代器产生的值序列用于立即构造std::vector<double>代表行的临时项。
  8. 临时向量被推到目标数组的末尾。

之后的所有事情都只是使用C ++ 11功能(基于范围的for和具有auto明码推导类型的变量)简单地打印生成的矩阵的内容。