![]() ![]() ![]() | 投稿するにはまず登録を |
スレッド表示 | 新しいものから | 前のトピック | 次のトピック | 下へ |
投稿者 | トピック |
---|---|
nuda | 投稿日時: 2012-3-8 13:02 |
一見さん ![]() ![]() 登録日: 2012-3-8 居住地: 投稿: 3 |
FileStreamによる行単位ロードについて 初めて投稿させていただきますnudaと申します。
よろしくお願いいたします。 さて 現在、数百MB〜数GBのサイズのテキストファイル(CSV)を行単位でロードする機能を作成中です。 FileStreamクラスを用いて、1バイトずつ読み込み改行コード判定(0x0D0A)を行なって、ラインブレイク+行ごとの処理 という風に実装しているのですが、1バイト単位で判定が行なわれるため、思ったように速度が出ません。 生のバイトストリームを行単位(0x0D0A)でかつ高速にロードするテクニックをご存知の方いらっしゃいましたらご教示願います。 ※ちなみに、FileStreamはopenAsyncを使って非同期で開いています。 |
Pepe | 投稿日時: 2012-3-8 22:22 |
モデレータ ![]() ![]() 登録日: 2006-1-10 居住地: 投稿: 1274 |
Re: FileStreamによる行単位ロードについて 1点気になるのですが、ロードしたデータをどうなさるのでしょうか?
数ギガなので変数(=メモリ)に展開は無いと思うのですが… それと別に1バイトずつ読み込まなくても readUTFBytes で1度に1メガぐらいで読み込んで 改行コードで string.split(",") して、配列化すれば 良いのではないでしょうか?
|
nuda | 投稿日時: 2012-3-8 22:41 |
一見さん ![]() ![]() 登録日: 2012-3-8 居住地: 投稿: 3 |
Re: FileStreamによる行単位ロードについて Pepeさん、投稿ありがとうございます。
>1点気になるのですが、ロードしたデータをどうなさるのでしょうか? ロードしたデータはSQLiteに格納して後続処理で使います。 CSVを1レコードずつ読んで、SQLiteにINSERTするようなイメージです。 >改行コードで string.split(",") して、配列化すれば 良いのではないでしょうか? 当初はFile#loadメソッドで一括で読み込んでCRLFでスプリットしていましたが、それだとあまりにメモリを圧迫するため、1バイトずつ読むような処理に変えました。 また、ある程度のチャンクサイズでロードしてCRLFでスプリットする方法も考えたのですが、スプリットしてしまうとレコード区切りがわからなくなるので断念しました。(「ロードしたデータの末尾がCRLFでないなら断片データ」のような判定条件を使えば、できないことは無いかもしれませんが…) また、ロード対象のCSVは列方向が可変長であり、1行のデータをSQLite上のテーブルに正規化するようなイメージですので、あくまで「1行単位」の処理をする必要があるのです。 加えて、問題のロジックは上位のクラスから「HogeHoge#next」のような形でコールされ、nextメソッドを呼ぶたびにCSV1レコード分のデータを返すようなイメージです。 制約上この構造を返るわけにはいかないので(インタフェースの実装として定義されるため、他との兼ね合いで変更するわけにはいきません)、なんとかうまい方法は無いものかと考えております。 |
Pepe | 投稿日時: 2012-3-9 9:40 |
モデレータ ![]() ![]() 登録日: 2006-1-10 居住地: 投稿: 1274 |
Re: FileStreamによる行単位ロードについて 1メガ読み込んで最初の改行コードまでのデータを処理して、
ファイル・ハンドルのオフセットをその位置に戻すなどできますが、 基本的に1バイト単位、又は1行単位にI/Oが発生するようでは 速度は決して上がりません。 また、処理するデータ量が少ない場合は 非同期では無く同期的にデータを読み込む方が早くなるはずです。 「先読み」というのは一般的な方法です。 先読みしたデータをキャッシュしておき 返すのは1レコードにすれば良いだけだと思います。 それすらできないロジック構造ならば それはI/O処理において適切では無い構造と言うことになります。
|
nuda | 投稿日時: 2012-3-9 10:14 |
一見さん ![]() ![]() 登録日: 2012-3-8 居住地: 投稿: 3 |
Re: FileStreamによる行単位ロードについて Pepeさん、返信ありがとうございます、nudaでございます。
>基本的に1バイト単位、又は1行単位にI/Oが発生するようでは 速度は決して上がりません。 確かにおっしゃるとおりですね。 今までバイトをいじくるような処理をあまり書いたことがなかったので「ストリームから1バイトずつロードし判定する処理」と「内部バッファから1バイトずつロードし判定する処理」のI/O負荷の違いを意識していませんでした。 アドバイスにしたがって、以下のようなコードで処理を実現しようと思います。
※1 変数の使い方など、汚い部分がありますがご了承ください。 ※2 終了条件はnextメソッドをコールする側で判断していますので、nextメソッド内にEOFブレイクのコードはありません |
スレッド表示 | 新しいものから | 前のトピック | 次のトピック | トップ |
投稿するにはまず登録を | |