C++ 程序,用于将具有恒定(但未知)列数的未知大小的 CSV 文件(仅填充浮点数)读取到数组中
c++ program for reading an unknown size csv file (filled only with floats) with constant (but unknown) number of columns into an array
想知道是否有人可以帮我一把,我试图构建一个程序,该程序可以从 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 Filen";
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,:);
任何帮助表示赞赏。亚历克斯
,我只会使用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";
}
}
以下是发生的情况:
- 目标
values
定义为double
的向量。没有什么可以保证不同的行大小相同,但是一旦读取文件,检查这一点就很简单了。 std::ifstream
是用文件定义和初始化的。可能值得在构造后检查文件,看看是否可以打开它进行读取(if (!fin) { std::cout << "failed to open...n";
)。- 文件一次处理一行。只需使用
std::getline()
读取这些行即可将它们读入std::string
。当std::getline()
失败时,它无法读取另一行,转换结束。 - 读取
line
后,所有逗号都将替换为空格。 - 从这样修改的
line
构造用于读取行的字符串流。原始代码重用了在循环外声明的std::istringstream
,以节省始终构建流的成本。由于流在行完成时会变坏,因此首先需要对其进行in.clear()
,然后再使用in.str(line)
设置其内容。 - 各个值使用
std::istream_iterator<double>
进行迭代,该仅从构造它的流中读取值。给定in
迭代器是序列的开始,默认构造的迭代器是序列的结束。 - 迭代器生成的值序列用于立即构造表示行的临时
std::vector<double>
。 - 临时向量被推送到目标数组的末尾。
之后的一切只是使用 C++11 个特征(基于范围的 for 和具有auto
推导类型的变量)打印生成的矩阵的内容。
正如这里建议的那样,更改 getline 转义可以帮助您更好地读取 csv 文件,但您需要将类型从字符串更改为 int。
为了处理任意数量的行和列,您可以使用多维向量(此处描述的向量内的向量),然后将每一行放在一个向量中,所有行都在较大的向量中
int fclose(infile);
这句话是错误的。编译器认为您正在尝试使用FILE*
初始化变量fclose
,这是错误的。如果您只是尝试关闭文件,则应该是这样的:
fclose(infile);
我打算将其作为对 Dietmar Kuhl 解决方案的编辑,但它因编辑太大而被拒绝......
将 Matlab 转换为 C++ 的通常原因是性能。因此,我对这两种解决方案进行了基准测试。我用 G++ 4.7.3 为 cygwin 编译了以下选项"-Wall -Wextra -std=c++0x -O3 -fwhole-program"。我在 32 位英特尔凌动 N550 上进行了测试。
作为输入,我使用了 2 10,000 行文件。第一个文件是每行 10 个"0.0"值,第二个文件是每行 100 个"0.0"值。
我使用时间从命令行计时,并使用了三次运行中 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的同步。
- 继承期间显示未知行为的子类
- 正在将csv文件读取为双精度矢量
- 输入中的字符串数未知(以字母表示)
- 具有未知值时的时间复杂性
- 链表中写入访问冲突的未知原因
- 正在生成未知类实例
- Bjarne Stroustrup Book - std_lib_facilities.h - 不起作用(未知类型名称)
- 读取文件时运行时的未知行为
- 代码在我的计算机上运行良好,但是在将其提交给coursera时遇到未知的信号11问题
- 如何选择在 csv 文件中输出的位置
- 初始化多个未知基类
- 使用 make 编译 MPI,几个命名空间错误,例如"错误:未知类型名称'使用'?
- 如何存储未知次数迭代的输入?
- QtQuick - qml:28:错误:未知方法返回类型:自定义类型
- 编译 Boost 时在 OS X 上的"ld:未知选项:-soname"
- 未知的 CMake 命令"create_single_source_cgal_program"
- 有没有办法在不使用 getline() 的情况下从.csv文件中读取?
- 如何在C++中循环访问未知对象方法?
- Coursera :自动评分器的未知信号 11
- C++ 程序,用于将具有恒定(但未知)列数的未知大小的 CSV 文件(仅填充浮点数)读取到数组中