想知道是否有人可以帮助我,我正在尝试构建一个程序,从 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,:);
任何帮助表示赞赏。 亚历克斯
显然,我会只使用 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
自动推导类型的变量)打印生成的矩阵的内容。
int fclose(infile);
这条线是错误的。编译器认为您正在尝试使用
fclose
来初始化变量 FILE*
,这是错误的。如果您只是想关闭文件,应该是这样的:
fclose(infile);
我本打算将此作为对 Dietmar Kuhl 解决方案的编辑,但由于编辑太大而被拒绝......
将 Matlab 转换为 C++ 的通常原因是性能。所以我对这两个解决方案进行了基准测试。我使用 G++ 4.7.3 for 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 的同步。
以下代码从 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;
}
}