C#で、ヘッダー行があり、その下に数値データが並んでいるCSVファイルを一括して取り込む。
ヘッダー(複数行可)はStringのジャグ配列に、数値データは、列ごとにDoubleのジャグ配列に入れる。
開発環境
Visual Studio 2019
Windows 10
C#
.net 5
ファイル 先頭から指定行スキップして、指定行数取り込み
もしかしたら.toArray()しないほうが、速度、メモリ的に有利なのかもしれないけど、扱いが楽なのでArray化
string CsvFilePath = "test.csv";
int RowsToSkip = 2;
int Rows = 1000;
string[] Lines = System.IO.File.ReadLines(CsvFilePath)
.Skip(RowsToSkip).Take(Rows).ToArray();
CSV文字列一行を、double配列にする
double[] CsvString.Split(',')
.Select(n => double.TryParse(n.Trim(), out double result) ? result : 0)
.ToArray();
コード一式
/// <summary>
/// CSV文字列一行を、double配列にする
/// </summary>
/// <param name="CsvString"></param>
/// <returns></returns>
private double[] CsvStringToDoubleArray(string CsvString)
{
return CsvString.Split(',').Select(n => double.TryParse(n.Trim(), out double result) ? result : 0).ToArray();
}
/// <summary>
/// CSVファイルからデータ読み込み
/// ヘッダー列と数値データ配列を得る
/// </summary>
/// <param name="CsvFilePath">CSVファイルパス</param>
/// <param name="RowsToSkip">読み込みから飛ばす行数</param>
/// <param name="HeaderRows">ヘッダー行数</param>
/// <param name="HeaderEncode">ヘッダー文字のエンコード</param>
/// <param name="FixedDataRows">読み込みサイズ データがこれ以下しかない場合0で埋められる</param>
/// <returns></returns
public (string[][] Header, double[][] NumericData) CSVtoDoubleArray
(string CsvFilePath, int RowsToSkip = 0, int HeaderRows = 1, string HeaderEncode = "Shift_JIS",int FixedDataRows = 0)
{
//.net 5以降これがないとShift_JISエンコードが読み込まれない
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
string[] Lines;
try
{
//FixedDataRowsが設定されていなかったら、全行、設定されていた、その行数分取得
if (FixedDataRows == 0)
Lines = System.IO.File.ReadLines(CsvFilePath, Encoding.GetEncoding(HeaderEncode)).Skip(RowsToSkip).ToArray();
else
Lines = System.IO.File.ReadLines
(CsvFilePath, Encoding.GetEncoding(HeaderEncode)).Skip(RowsToSkip).Take(HeaderRows + FixedDataRows).ToArray();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return (null, null);
}
int DataRows = Lines.Length- HeaderRows;
//データ列が0以下なら戻す
if (DataRows <= 0)
return (null, null);
string[][] Header = new string[HeaderRows][];
//ヘッダー行数分読み込み
for (int i = 0; i < HeaderRows && i < Lines.Length; i++)
Header[i] = Lines[i].Split(',').Where(x => x != "").Select(x => x.Trim('\"')).ToArray(); //空白列は除外 注 行最後の,を想定 途中に,,があるとずれる
int DataColumns;
//ヘッダーがあれば、先頭ヘッダーの列数 なければ先頭データの列数
if (HeaderRows > 0)
DataColumns = Header[0].Length;
else
DataColumns = CsvStringToDoubleArray(Lines[0]).Length;
//データ配列確保用行数
int AllocationDataRows = DataRows;
if (FixedDataRows != 0)
AllocationDataRows = FixedDataRows;
//ヘッダー、指定行数のジャグ配列の領域確保
double[][] NumericData = new double[DataColumns][];
for (int Col = 0; Col < DataColumns; Col++)
NumericData[Col] = new double[AllocationDataRows];
for (int Row = 0; Row < DataRows && Row < FixedDataRows; Row++)
{
var line = CsvStringToDoubleArray(Lines[Row + HeaderRows]);
for (int Col = 0; Col < DataColumns && Col < line.Length; Col++)
NumericData[Col][Row] = line[Col];
}
return (Header, NumericData);
}
呼び出し例
var CsvFilePath = "Test.csv";
//6000行読み込み
(string[][] Header, double[][] Data) = CSVtoDoubleArray(CsvFilePath,RowsToSkip:4,FixedDataRows:6000);
Header[0] ヘッダー一行目のstring配列
Header[0][0] ヘッダー一行目、1列目
Data[0] データ一列目のdouble配列
Data[0][0] データ一列目の一つ目のデータ