結城あすかの毎日電波思考 (あすか日記)

アクセスカウンタ

zoom RSS 「C#」でCSVファイルを読み込むにょ

<<   作成日時 : 2010/06/09 23:58   >>

ブログ気持玉 0 / トラックバック 0 / コメント 3

 VBなんかだとExcelのシートに直接アクセスしてデータを入出力するとかいう手法もあるだろうけど、一般的なスプレッドシート型のデータをプログラムから扱う場合に用いられるのはCSV形式のデータだにょ。
 ところが、CSVファイルを読み書きするだなんて需要がありそうな機能は、.NETでも付いてないにょ。したがって、CSVファイルを読み込んで配列や構造体などのデータ構造として取り込む処理は自分で書くというのが一般的だにょ。

 それはそうとして、.NETを使うと標準のC言語なんかよりはずっと簡単に読み込み処理が書けるにょ。
 とりあえず、CSVファイルを読み込んで、文字列として2次元配列に格納するクラスを作ってみたにょ。

class CsvMatrix
{
public string[,] matrix;
public int col;
public int row;

public CsvMatrix(string csvfile, Encoding encode)
{
try {
// マトリックスのサイズを取得
{
string line;
string[] data;
int icol = 0;
int irow = 0;

StreamReader sr = new StreamReader(csvfile, encode);
while ((line = sr.ReadLine()) != null) {
irow++;
data = line.Split(',');
int cnt = 0;
foreach (string elem in data) {
cnt++;
}
if (cnt > icol) {
icol = cnt;
}
}
sr.Close();

this.col = icol;
this.row = irow;

matrix = new string[irow, icol];
}

// マトリックスにデータを格納
{
string line;
string[] data;
int icol = 0;
int irow = 0;

StreamReader sr = new StreamReader(csvfile, encode);
while ((line = sr.ReadLine()) != null) {
data = line.Split(',');
icol = 0;
foreach (string elem in data) {
switch (elem[0]) {
case '"':
matrix[irow, icol] = (elem.Split('"'))[1];
break;
case '\'':
matrix[irow, icol] = (elem.Split('\''))[1];
break;
default:
matrix[irow, icol] = elem;
break;
}
icol++;
}
for (; icol < this.col; icol++) {
matrix[irow, icol] = string.Empty;
}
irow++;
}
sr.Close();
}
}
catch (Exception e) {
this.col = this.row = 0;
throw e;
}
}
}

 使い方は次の通りにょ。

// CSVファイルの読み込み
// (シフトJISで記述されたCSVファイル「csvfile」を読み込み)
CsvMatrix csv = new CsvMatrix(csvfile, System.Text.Encoding.GetEncoding("shift_jis"));

// 要素へのアクセス
// (第2行第3列のデータ)
string data = csv.matrix[2, 3];

マトリックスのサイズは、csv.row と csv.col で分かるにょ。

 読み込みはコンストラクタでやってるから、生成したら後はメンバ変数のマトリックスにアクセスするだけだにょ。直接、メンバ変数にアクセスするのはどうかという場合はメンバ変数のアクセス指定をprivateに変え、新たに値を返すメンバ関数をpublicで作ればいいけど、とくにブラックボックスにする意味は無いから、あんまり変わらないにょ。

 現実的にはデータの中身は数値データも多いだろうから、stringの2次元配列にするよりは、データに合わせたデータ型の構造体配列にした方がいいけど、それは個々のCSVファイル固有の構造だから、汎用的にするならこういう形しかないだろうにょ。

 データを全部読み込んでstringの2次元配列に放り込むなんてことやってるから、レコードが数万件とかいうあんまり巨大なCSVデータの処理には向かないだろうと思うけど、ちょっとした実験データの処理とか、学校のクラスの成績分析とか、年賀状の住所録の管理とかいうようなところには十分だろうにょ。

 StreamReaderクラスで一行ずつ読みだすよりも、FileクラスのReadAllLinesで全行一気に読み込んだ方が良いかもしれないけど、そこは好みとかメモリの範囲内で……

テーマ

関連テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(3件)

内 容 ニックネーム/日時

けっこういい実践的なコードだと思います。オブジェクト指向の勉強になります。コンストラクタで処理を実行させて結果を複数のメンバー変数に入れることで構造体使わないでクラスのインスタンス生成で済んじゃうんですね。見事です!

最初から私のコラムにこんなコード書いてくれる人がいたらよかったのに・・・
みながわけんじ
2010/06/16 13:39
お褒めいただいてありがとうございます。
以前の記事ではずいぶん失礼なことを書いてしまいまして申し訳ありません。
実のところ、私もプログラミングを本格的に勉強したのは昔のC言語の頃で、オブジェクト指向とかは雑誌の記事を読んだりして漠然としたイメージしか持ってなかったんですね。
クラスとかもVC++6.0のMFCを使うようになってから見よう見まねで覚えたくらいで、VC#なんかは最近になって趣味で始めたくらいなので……

基本的には理屈とかよりも「いかに自分が楽できるように形にできるか」なんですよね。上のコードもtry〜catchあたりがずいぶんいいかげんだったりしますが、必要なら呼び出し元で例外を拾ってくれという感じで放り出してますね。
結城あすか
2010/06/17 16:20
読みやすいコードで大変参考になります
1行1行が何をやっているのか、自然と伝わってくるところがいいですね!
うさぎちゃん
2010/12/14 20:13

コメントする help

ニックネーム
本 文
TweetsWind
「C#」でCSVファイルを読み込むにょ 結城あすかの毎日電波思考 (あすか日記)/BIGLOBEウェブリブログ
文字サイズ:       閉じる