時系列データが記録されたcsv形式のファイルを読み込むという処理をしています。
readFileStreamを用いて1行ずつ、順を追って読み込むという処理は容易なのですが、
CSVデータを利用した処理結果如何によっては過去(前の行)のデータに戻るという処理
を加えたいと思っています。
全てのデータを一括して配列に読み込めば一応は解決するのですが、
データ数が数万件に及びますので、メモリの関係上、そのような処理はとりたくないと考
えています。
ReadLineした後にファイルの読み込んだ位置を保存し、場合によってはその位置を操作し
てから再び読み込み始めるというような処理をすることは可能なのでしょうか?
全ての行番号と、ファイル内でのその行の開始位置を保存しておいて、Seek すればいい
んじゃないのかな。
> readFileStreamを用いて1行ずつ、順を追って読み込むという処理は容易なのですが、
readFileStream ?
> CSVデータを利用した処理結果如何によっては過去(前の行)のデータに戻るという処
理
> を加えたいと思っています。
基本的に出来ません。
# 出来るように自分で工夫をした場合を除く
> ReadLineした後にファイルの読み込んだ位置を保存し、場合によってはその位置を操作
し
> てから再び読み込み始めるというような処理をすることは可能なのでしょうか?
StreamReaderを仮定した場合,StreamReaderはバッファリングを行うので不可能です。
a.) 前処理を行って,固定長にしてSeek可能にしておく
b.) あきらめて全てメモリにため込む
c.) 毎回先頭から読み直す
といった方法を採る必要があります。
# ADO.NETでJET OLE DB経由,というのは使えるのかなぁ……。データ次第ですが。
> 全ての行番号と、ファイル内でのその行の開始位置を保存しておいて、Seek すればい
い
> んじゃないのかな。
「その行の開始位置」の取得が厳しいです。
PositionやSeekはBaseStreamにしかないので。
# とりあえず,こちらもStreamReaderを仮定。FileStream + BinaryReaderなら可能か
と。
>
StreamReaderを仮定した場合,StreamReaderはバッファリングを行うので不可能です。
ReadLine が終わった時点での Position は次の行の開始位置とは限らんのか。
> ReadLine が終わった時点での Position は次の行の開始位置とは限らんのか。
とりあえず,マニュアルには記載がないので,仮定は出来ません。
現実問題としては,StreamReaderにバッファサイズを指定しなかった場合,
BaseStream.Positionは1024単位で移動しました。
# .NET Framework 2.0.50727.42で確認。
平日忙しく、折角ご回答いただいたのになかなか返答できませんでした、すみません。
Seek()を使うというヒントを頂きましたので、これを利用してコードを書いてみました。
初回読み込み時に行先頭の位置をArrayListに保存して、
その後、行移動はArrayListに保存した位置を手掛かりにSeekするというものです。
StreamReaderが具体的にどのような処理をしているのか理解不足ですので、
処理としては無駄な箇所があるかと思いますが、とりあえず動くには動きましたので
ご報告いたしました。
助言、ありがとうございます。
ArrayList ALColumnByte = new ArrayList();
FileStream fsCSV;
StreamReader srCSV;
string strBuff, strAll;
ALColumnByte.Add(0);
fsCSV = new FileStream(strFilePath, FileMode.Open);
srCSV = new StreamReader(fsCSV, Encoding.GetEncoding(Shift_JIS));
strAll = ";
while ((strBuff = srCSV.ReadLine()) != null){
strAll += strBuff + \r\n;
Encoding sjisEnc = Encoding.GetEncoding(Shift_JIS);
ALColumnByte.Add(sjisEnc.GetByteCount(strAll));
}
srCSV.Close();
fsCSV.Close();
fsCSV.Seek((long)(int)ALColumnByte[i], 0);
strBuff = srCSV.ReadLine().Split(',');
解決となっていますが……。
StreamReader.BaseStream.Seekを呼び出したあとは,
StreamReader.DiscardBufferedDataを呼び出した方がよいです。
もちろん,BaseStreamを介していない場合でもです。