CSV文件处理
目录
2.2 写CSV文件
1. CSV文件简单介绍
CSV,Comma-Separated Values,翻译过来就是逗号分隔值,也可以称为符号分隔值,因为也可以不是逗号分隔的。CSV文件的内容是以逗号分隔开的一系列数据。CSV文件可用Excel和记事本打开。
工作中用到CSV文件无非是读和写CSV文件,接下来是关于CSV文件读和写的操作。
2. CSV文件的读写操作
读CSV文件可以按照读TXT文件去读,写CSV文件时需要注意要确保当前文件的位置是在最后一行。
2.1 读CSV文件
有的CSV文件是有标题行的,如下。通常是读取需要的内容,标题行舍弃掉。
2.1.1 C读取CSV文件
使用C读取CSV文件需要用到fseek()函数,该函数原型为fseek(FILE* stream,long offset,int fromwhere);
参数fromwhere表示从什么地方开始,取值有三个,分别是:
设置值 | 备注 |
SEEK_SET=0 | 表示从文件开头 |
SEEK_CUR=1 | 表示从文件当前位置 |
SEEK_END=2 | 表示从文件末尾 |
#include <stdio.h>
bool ReadCSV(const char* filename) { FILE *fp = nullptr; char *line, *record; char buffer[1024]; if ((fp = fopen(filename, "at+")) != nullptr) { line = fgets(buffer, sizeof(buffer), fp); // 1. 获取第一行的内容 fseek(fp, strlen(line), SEEK_SET); // 2. 定位到第二行 while ((line = fgets(buffer, sizeof(buffer), fp)) != nullptr)// 3. 逐行获取文件内容 { record = strtok(line, ","); while ((record = strtok(line, ",")) != nullptr)// 4. 分隔每一行的每一个数据 printf("%s ", record);// 5. 打印每一行的每一个数据,以空格隔开 printf("\n"); } fclose(fp); fp = nullptr; return true; } else { printf("Open file fail!"); return false; } }
2.1.2 C++读取CSV文件
使用fstream文件流读取CSV文件。
使用正则表达式匹配每个单元格的内容,需要添加头文件#include <regex>,
bool ReadCSV_CPP(const std::string& filename) { std::fstream file(filename,std::ios::in); // 1. 打开文件 if(!file.is_open()) { std::string exp_string = "Open File FAIL!"; throw exp_string; } std::string strline; std::smatch sm; std::regex rx("(\\w+)"); //CSV文件每个单元格的格式,此处匹配的是字母、数字、下划线 std::string strtemp; while (std::getline(file,strline)) { // 2. 逐行读取csv文件 while (std::regex_search(strline, sm, rx)) // 3. 正则表达式匹配每个单元格的内容 { strtemp = sm.begin()->str(); // 4. 匹配到的单元格内的内容 strline = sm.suffix().str(); // 5. 剩下的字符 printf("%s ",strtemp.c_str()); } if(!strline.empty()) { strtemp = strline; printf("%s ",strtemp.c_str()); } printf("\n"); } file.close(); return true; }
2.1.3 QT读取CSV文件
bool ReadCSV_Qt(const QString& filename) { QFile file(filename); if(!file.open(QFile::ReadOnly | QFile::Text)) { std::string s ="read file fail"; throw s; } QStringList content; // 所有逗号分隔的内容 content.clear(); QTextStream text(&file); QStringList listContent; //每行的内容 while (!text.atEnd()) { listContent.push_back(text.readLine()); // 逐行获取每行内容 } for(QString& str:listContent) { content.push_back(str.split(",")); // 获取每行的逗号分隔开的内容 } file.close(); return true; }
2.2 写CSV文件
写CSV文件时需要注意当前文件指针位置在文件的最后一行的开始位置。
2.2.1 C写CSV文件
同样的,C写CSV文件时也会用到fseek()函数,此时fromwhere参数需要设置为SEEK_END,表示文件指针定位到文件末尾。
// data数据类型可以任意为需要保存的内容 bool WriteCSV_C(const char* filename,const char* data) { FILE *pf = nullptr; pf = std::freopen(filename, "at", stdout); // freopen()函数用于文件流重定向 if (nullptr == pf) { const char* chErrmsg = "Open File FAIL!"; throw chErrmsg; } long longfileSizeTemp = ftell(pf); // 获取当前文件大小 size_t datasize = strlen(data); fseek(pf, 0, SEEK_END); //将文件指针定位到文件末尾 longfileSizeTemp = ftell(pf); if (0 == longfileSizeTemp) // 若文件大小=0表示该文件还未写入数据 { for(int i=0;i<datasize;i++) { printf("col_%d,",i);// 输入csv的标题内容 } } printf("\n"); for(int i=0;i<datasize;i++) { printf("%c,",data[i]);// 输入csv的数据内容 } fclose(pf); pf = nullptr; return true; }
2.2.2 C++写CSV文件
使用fstream类写CSV文件,需要使用到seekp()、tellp()获取到文件是否为空。
bool WriteCSV_CPP(const std::string& filename,const std::vector<int>& data) { std::fstream file(filename,std::ios::out|std::ios::app); // 1. 打开文件,ios::app表示在文件尾追加,如果不加该属性,那么每次写的时候会覆盖文件内容 if(!file.is_open()) { std::string exp_string = "Open File FAIL!"; throw exp_string; } // 以下两行获取文件的大小,首先设置文件流指针位置为末尾,然后返回当前文件写指针的位置,如果为0表示该文件为空 file.seekp(0,file.end); // seekp()函数设置输出文件流的文件流指针位置 size_t filesize = file.tellp(); // 返回文件写指针的位置 int iDataSize = data.size(); if(0 == filesize) { for(int i=0;i<iDataSize;++i) // 如果文件为空,添加标题 { file << "col_" << i << ","; } } file << std::endl; for(int i=0;i<iDataSize;++i) // 写入内容 { file << data.at(i) << ","; } file.close(); return true; }
2.2.3 Qt写CSV文件
bool WriteCSV_Qt(const QString& filename,const QStringList& data) { QFile file(filename); if(!file.open(QFile::WriteOnly | QFile::Text | QFile::Append)) // 1. 以追加方式打开文件 { std::string s ="Open File FAIL"; throw s; } qint64 filesize = file.size(); // 获取文件大小 int iDataSize = data.size(); if(0 == filesize) { QString strTemp; for(int i=0;i<iDataSize;++i) //文件为空时,填入标题 { strTemp.sprintf("col_%d,",i); file.write(strTemp.toStdString().c_str()); } } file.write("\n"); for(QString str:data) { file.write(str.toStdString().c_str()); // 写入文件内容 file.write(","); } file.close(); return true; }