1. 程式人生 > 其它 >CSV檔案處理

CSV檔案處理

目錄

1. CSV檔案簡單介紹

2.CSV檔案的讀寫操作

  2..1 讀CSV檔案

    2.1.1 C讀取CSV檔案

    2.1.2 C++讀取CSV檔案

    2.1.3 QT讀取CSV檔案

  2.2 寫CSV檔案

    2.2.1 C寫CSV檔案

    2.2.2 C++寫CSV檔案

    2.2.3 Qt寫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;
}