一个c++程序,用于阅读一个未知大小的csv文件(只填充浮点数),其中列数为常数(但未知),并将其放入数组中

mpgws1up  于 2023-10-13  发布在  其他
关注(0)|答案(5)|浏览(133)

我想知道是否有人可以给予我一只手,我试图建立一个程序,读入一个大数据块的浮动与未知大小从csv文件。我已经在MATLAB中写了这个,但想编译和分发它,所以移动到c++。
我只是学习和尝试阅读在这开始

7,5,1989
2,4,2312

从一个文本文件。
代码到目前为止

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

我用的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,:);

谢谢你的帮助。亚历克斯

i2loujxw

i2loujxw1#

当然,我会使用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";
    }
}

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

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

以下是发生的情况:
1.目的地values被定义为double的向量的向量。没有任何东西可以保证不同行的大小相同,但是一旦读取文件,检查这一点就很简单了。

  1. std::ifstream是用文件定义和初始化的。在构造后检查文件是否可以打开以进行阅读(if (!fin) { std::cout << "failed to open...\n";)可能是值得的。
    1.文件一次处理一行。使用std::getline()将行读取到std::string中。当std::getline()失败时,它无法读取另一行,转换结束。
    1.读取line后,所有逗号都将替换为空格。
    1.从这样修改的line构造用于阅读行的字符串流。原始代码重用了一个std::istringstream,它在循环外部声明,以保存构造流的所有时间。由于流在行完成时会变坏,因此在将其内容设置为in.str(line)之前,首先需要对其进行in.clear() ed。
    1.使用std::istream_iterator<double>迭代各个值,该std::istream_iterator<double>仅从构造它的流中读取值。给定的迭代器in是序列的开始,默认构造的迭代器是序列的结束。
    1.迭代器产生的值序列用于立即构造一个表示行的临时std::vector<double>
    1.将临时向量推到目标数组的末尾。
    之后的一切都只是使用C++11特性(基于范围的for和具有auto自动推导类型的变量)打印生成的矩阵的内容。
e0uiprwp

e0uiprwp2#

正如here建议的那样,改变getline escape可能会帮助你更好地阅读csv文件,但你需要将类型从string改为int。
为了处理任何数量的行和行,您可以使用多维向量(向量内部的向量,如所述here),然后您将每行放在一个向量中,所有行都放在更大的向量中

p1tboqfb

p1tboqfb3#

int fclose(infile);

这条线是错的。编译器认为你试图用FILE*初始化变量fclose,这是错误的。如果你只是想关闭文件,应该是这样的:

fclose(infile);
mdfafbf1

mdfafbf14#

我打算这作为一个编辑迪特马尔库尔的解决方案,但它被拒绝了太大的编辑.
将Matlab转换为C的通常原因是性能。所以我对这两种解决方案进行了基准测试。我用G 4.7.3为cygwin编译了以下选项“-Wall -Wextra -std=c++0x -O3 -fwhole-program”。我在32位Intel Atom N550上测试过。
作为输入,我使用了2个10,000行文件。第一个文件是每行10个“0.0”值,第二个文件是每行100个“0.0”值。
我在命令行中使用time计时,并使用了三次运行中user+sys的平均值。
我修改了第二个程序,像第一个程序一样从std::cin读取。
最后,我用std::cin.sync_with_stdio(false);再次运行了测试
结果(以秒为单位的时间):

sync                no sync
        10/line  100/line     10/line  100/line
prog A    1.839    16.873       0.721     6.228
prog B    1.741    16.098       0.721     5.563

显而易见的结论是,版本B稍微快一点,但更重要的是,您应该禁用与stdio的同步。

gblwokeq

gblwokeq5#

下面的代码从csv文件中读取行并打印它们。

void print_csv_file(string csv_file){
  ifstream inFile;
  inFile.open(csv_file);
  string sString;

  while (!inFile.eof() ){ 
      // read row string from csv until end of line \n
      getline(inFile, sString, '\n');
      // print the readed string
      cout<<sString<<endl;
  }
}

相关问题