C語言讀取寫入CSV文件 [二]進階篇——寫入CSV文件


本系列文章目錄

[一] 基礎篇

[二] 進階篇——寫入CSV

[三] 進階篇——讀取CSV


什么是 包裹(使用雙引號)?

包裹的概念是面向字段的,包裹起來的字段將會被視為一個整體。尤其當字段中包含一些特殊符號(如逗號、換行符、雙引號)時,如果不將這些字段包裹起來,則很有可能導致 CSV 文件解析發生錯誤。那么我們該如何包裹一個字段呢,通常將一個字段放置在雙引號("")之間,例如"ID",ID就是一個被包裹的字段。任何字段都可以使用雙引號("")將其包裹起來,並不存在任何限制。

字段中特殊符號的處理

根據上面的介紹,如果一個字段中包含特殊符號,那么在寫入時必須使用雙引號來包裹這個字段。有一點需要注意,C語言中字符串中的雙引號需要通過使用轉義符號來表示(\")

下面分別用逗號、換行符、雙引號來做示例

  • 逗號fprintf(fp, "3,\"z,xc\",3.3\n");

  • 換行符fprintf(fp, "4,\"qw\nas\",4.4\n");

  • 雙引號fprintf(fp, "5,\"\"aszx\"\",5.5\n");,第一個用作包裹字段,第二個雙引號才是實際的雙引號。

完整的程序如下:

// 2-1.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fp = fopen("tmp.csv", "w+");
    if (fp == NULL) {
        fprintf(stderr, "fopen() failed.\n");
        exit(EXIT_FAILURE);
    }

    fprintf(fp, "ID,Name,Points\n");
    fprintf(fp, "1,qwe,1.1\n");

    int id = 2;
    char *name = "asd";
    float point = 2.2;
    fprintf(fp, "%d,%s,%f\n", id, name, point);

    // special symbols
    fprintf(fp, "3,\"z,xc\",3.3\n");
    fprintf(fp, "4,\"qw\nas\",4.4\n");
    fprintf(fp, "5,\"\"aszx\"\",5.5\n");

    fclose(fp);
    return 0;
}

運行程序,查看 CSV 文件內容,結果為:

Figure. 1

字段開頭和結尾處的空格和制表符

CSV 文件中的字段中的開頭和結尾上,可能會存在空格或制表符,但是該如何處理呢?按照 RFC 4180 標准的規定,“空格被看作字段的一部分,不應當被忽略”。但是RFC 4180 並不是強制標准,因此某些實現中,空格和制表符會被截斷掉。因此 fprintf(fp, " 6,abc,6.6 \n"); 寫入的字段可能是 6,abc,6.6 (按照 RFC 4180 標准) 或者是 6,abc,6.6(空格被截掉)

然而,在 RFC 4180 標准中,並未說明空格字符若出現在被包裹的值之外如何處理,例如在 fprintf(fp, " \"7\",def,\"7.7\" \n"); 語句中,如字段 \"7\",雖然7被包裹,但包裹之外的又有空格,因此目前標准中對這樣的空格該如何處理還沒有規定,可以保留也可以截掉。\"7.7\" 字段也面臨着同樣的問題。

想要將這種空格視為字段中有意義的數據,最省事的方法是將這些空格也包裹起來,例如 fprintf(fp, "\" 8\",ghi,\"8.8 \"\n"); 語句中的 "\" 8\"\"8.8 \"字段中,屬於字段的空格已被包裹。

完整的程序如下:

// 2-2.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fp = fopen("tmp.csv", "w+");
    if (fp == NULL) {
        fprintf(stderr, "fopen() failed.\n");
        exit(EXIT_FAILURE);
    }

    fprintf(fp, "ID,Name,Points\n");
    fprintf(fp, "1,qwe,1.1\n");

    int id = 2;
    char *name = "asd";
    float point = 2.2;
    fprintf(fp, "%d,%s,%f\n", id, name, point);

    // special symbols
    fprintf(fp, "3,\"z,xc\",3.3\n");
    fprintf(fp, "4,\"qw\nas\",4.4\n");
    fprintf(fp, "5,\"\"aszx\"\",5.5\n");

    // leading or trailing spaces
    fprintf(fp, "  6,abc,6.6  \n");
    fprintf(fp, "  \"7\",def,\"7.7\"  \n");
    fprintf(fp, "\"  8\",ghi,\"8.8  \"\n");

    fclose(fp);
    return 0;
}

運行程序,查看 CSV 文件內容,結果為:

Figure. 2

分隔符可能存在的問題

在某些國家(如德國、荷蘭)中,小數點不是點而是逗號,因此如果依然用逗號作分隔符,那么將無法正確表示。那么該在保證小數點是逗號前提下,如何避免CSV文件解析錯誤,存在兩種解決方法:

  1. 將所有包含小數點的數字包裹起來
  2. 使用分號而不是逗號作為分隔符

利用軟件進行配置

無論是開頭或結尾處的空格或制表符,還是分隔符的選擇,在一些功能強大的軟件中,這些其實都可以進行配置,下圖分別展示了在 Microsoft Excel、LibreOffice Calc中如何解析CSV文件的配置界面。

Figure. 3

Figure. 4


如果想要了解偏基礎的 C 語言讀取寫入 CSV 文件的內容,歡迎閱讀:[一] 基礎篇

如果想要了解進階的 C 語言讀取 CSV 文件的內容,歡迎閱讀:[三] 進階篇——讀取CSV


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM