C言語でCSVファイルの読み書き方法を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
C言語でCSVファイルの読み書き
C言語でCSVファイルの読み書き方法を紹介します.
CSV(Comma-Separated Values)は,テキストデータをいくつかのフィールド(項目)に分け,区切り文字であるカンマ「,」で区切ったデータ形式のテキストファイルです.
CSVは,以下の特徴があります.
- プログラミング言語に依存しないこと
- テキストファイルなので汎用的なテキストエディタで読み書きできること
- RFC 4180で仕様が標準化されていること
C言語でCSVファイルを読み書きするコードは以下になります.
コード中の主な関数は以下になります.
- read_csv関数:CSVファイルを読み込み,各々のフィールドを構造体に格納
- print_csv関数:構造体の各々のフィールドを表示
- write_csv関数:構造体の各々のフィールドをCSVファイルに書き込み
CSVファイルのレコード数やフィールド数が可変長の場合に対応するため,2段階のmalloc/realloc関数やfree関数を利用しています.
なので,コードがとても複雑になっています.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> struct record { char **fields; size_t nr_fields; }; struct csv_text { struct record *records; size_t nr_records; }; void init_record(struct record *record) { record->fields = NULL; record->nr_fields = 0; } void init_csv(struct csv_text *ct) { ct->records = NULL; ct->nr_records = 0; } void read_csv(struct csv_text *ct, const char *filename) { FILE *fp; char *saveptr; char *token; size_t size, nr_fields; char *line = NULL; size_t n = 0; if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "Error: cannot open %s.\n", filename); exit(1); } while (getline(&line, &n, fp) >= 0) { size = sizeof(struct record) * (ct->nr_records + 1); if ((ct->records = realloc(ct->records, size)) == NULL) { fprintf(stderr, "Error: cannot allocate memory %zu bytes.\n", size); exit(2); } init_record(&ct->records[ct->nr_records]); saveptr = line; while ((token = strsep(&saveptr, ",\n")) != NULL) { if (saveptr == NULL) { break; } size = sizeof(char *) * (ct->records[ct->nr_records].nr_fields + 1); if ((ct->records[ct->nr_records].fields = realloc(ct->records[ct->nr_records].fields, size)) == NULL) { fprintf(stderr, "Error: cannot allocate memory %zu bytes.\n", size); exit(3); } size = sizeof(char) * (strlen(token) + 1); nr_fields = ct->records[ct->nr_records].nr_fields; if ((ct->records[ct->nr_records].fields[nr_fields] = malloc(size)) == NULL) { fprintf(stderr, "Error: cannot allocate memory %zu bytes.\n", size); exit(4); } strcpy(ct->records[ct->nr_records].fields[nr_fields], token); token = saveptr; ct->records[ct->nr_records].nr_fields++; } ct->nr_records++; } if (line) { free(line); } if (fclose(fp) == EOF) { fprintf(stderr, "Error: cannot close %s.\n", filename); exit(4); } } void print_csv(struct csv_text *ct) { int i, j; for (i = 0; i < ct->nr_records; i++) { for (j = 0; j < ct->records[i].nr_fields; j++) { printf("%s", ct->records[i].fields[j]); if (j < ct->records[i].nr_fields - 1) { printf(","); } } printf("\n"); } } void write_csv(struct csv_text *ct, const char *filename) { FILE *fp; int i, j; if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "Error: cannot open %s.\n", filename); exit(1); } for (i = 0; i < ct->nr_records; i++) { for (j = 0; j < ct->records[i].nr_fields; j++) { fprintf(fp, "%s", ct->records[i].fields[j]); if (j < ct->records[i].nr_fields - 1) { fprintf(fp, ","); } } fprintf(fp, "\n"); } if (fclose(fp) == EOF) { fprintf(stderr, "Error: cannot close %s.\n", filename); exit(2); } } void free_csv(struct csv_text *ct) { int i, j; for (i = ct->nr_records - 1; i >= 0; i--) { for (j = ct->records[i].nr_fields - 1; j >= 0; j--) { free(ct->records[i].fields[j]); } free(ct->records[i].fields); } free(ct->records); } int main(int argc, char *argv[]) { struct csv_text ct; if (argc != 3) { fprintf(stderr, "Usage: %s [read_csv_file] [write_csv_file]\n", argv[0]); return 1; } if (strcmp(argv[1], argv[2]) == 0) { fprintf(stderr, "Error: same read/write csv files.\n"); return 2; } init_csv(&ct); read_csv(&ct, argv[1]); print_csv(&ct); write_csv(&ct, argv[2]); free_csv(&ct); return 0; } |
実行結果は以下になります.
読み込むread.csvは,こちらからダウンロードして下さい.
1 2 3 4 5 6 7 8 |
$ gcc csv_rw.c $ a.out read.csv write.csv Name,ID,MATH,ENGLISH, Sato,1,80,90, Suzuki,2,70,100, aa,,,, ,,,, bb,3,1,2,5 |
catコマンドでwrite.csvの中身の表示,diffコマンドで差分がないことを確認する方法は以下になります.
1 2 3 4 5 6 7 8 9 |
$ cat write.csv Name,ID,MATH,ENGLISH, Sato,1,80,90, Suzuki,2,70,100, aa,,,, ,,,, bb,3,1,2,5 $ diff read.csv write.csv $ |
参考:C++/Python言語でCSVファイルの読み書き
C++/Python言語でCSVファイルの読み書き方法を紹介します.
C言語と比較すると,C++/Python言語のコードは行数が短くシンプルなことがわかります.
C++言語でCSVファイルの読み書き
C++言語でCSVファイルを読み書きするコードは以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <iostream> #include <fstream> #include <sstream> #include <vector> void read_csv(std::vector<std::vector<std::string>>& ct, const std::string& filename) { std::string str; std::string buf; std::ifstream ifs(filename); while (std::getline(ifs, str)) { std::istringstream is(str); std::string str; std::vector<std::string> v; while (std::getline(is, buf, ',')) { v.push_back(buf); } ct.push_back(v); } } void print_csv(std::vector<std::vector<std::string>>& ct) { for (std::vector<std::string>& v : ct) { for (std::size_t i = 0; i < v.size(); i++) { std::cout << v.at(i); if (i < v.size() - 1) { std::cout << ","; } } std::cout << std::endl; } } void write_csv(std::vector<std::vector<std::string>>& ct, const std::string& filename) { std::ofstream ofs(filename); for (std::vector<std::string>& v : ct) { for (std::size_t i = 0; i < v.size(); i++) { ofs << v.at(i); if (i < v.size() - 1) { ofs << ","; } } ofs << std::endl; } } int main(int argc, char* argv[]) { std::vector<std::vector<std::string>> ct; if (argc != 3) { std::cerr << "Usage: " << argv[0] << " [read_csv_file] [write_csv_file]" << std::endl; return 1; } std::string in_csv = argv[1]; std::string out_csv = argv[2]; if (in_csv == out_csv) { std::cerr << "Error: same read/write csv files." << std::endl; return 2; } read_csv(ct, in_csv); print_csv(ct); write_csv(ct, out_csv); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 7 8 |
$ g++ csv_rw.cpp $ a.out read.csv write.csv Name,ID,MATH,ENGLISH, Sato,1,80,90, Suzuki,2,70,100, aa,,,, ,,,, bb,3,1,2,5 |
Python言語でCSVファイルの読み書き
Python言語でCSVファイルを読み書きするコードは以下になります.
Python言語のコードは,C++言語のコードよりさらに短いです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Author: Hiroyuki Chishiro # License: 2-Clause BSD # import csv import sys def read_csv(filename): records = [] with open(filename) as fname: reader = csv.reader(fname, quoting=csv.QUOTE_NONE) for rec in reader: records.append(rec) return records def print_csv(records): for rec in records: rlen = len(rec) for i in range(rlen): print(rec[i], end='') if i < rlen - 1: print(',', end='') print('\r') def write_csv(filename, records): with open(filename, 'w') as fname: for rec in records: rlen = len(rec) for i in range(rlen): fname.write(rec[i]) if i < rlen - 1: fname.write(',') fname.write('\r\n') def main(): args = sys.argv if len(args) != 3: print("Usage:", args[0], "[read_csv_file] [write_csv_file]") sys.exit(1) if args[1] == args[2]: print("Error: same read/write csv files") sys.exit(2) records = read_csv(args[1]) print_csv(records) write_csv(args[2], records) if __name__ == "__main__": main() |
実行結果は以下になります.
1 2 3 4 5 6 7 |
$ python3 csv_rw.py read.csv write.csv Name,ID,MATH,ENGLISH, Sato,1,80,90, Suzuki,2,70,100, aa,,,, ,,,, bb,3,1,2,5 |
まとめ
C言語でCSVファイルの読み書き方法を紹介しました.
CSVファイルの読み書きするコードは,C言語では複雑ですが,C++/Python言語では簡単なことがわかりました.
CSVファイルの操作では,C言語は不得意なので,C++/Python言語の方が好ましいと言えます.
C言語を理解していると他のプログラミング言語の習得も簡単になるので,用途毎に適切なプログラミング言語を選べるスキルを身につけましょう!
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!