- - PR -
VBでCSV読み込み & 書き出しの処理速度向上について
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2007-05-15 12:38
いつも拝見させて頂いております。
今回初めて投稿させて頂きました。 下記環境 Windows XP(CPU:2GHz メモリ:512MB) Visual Basic 2005 Express Edition において、CSVファイルからデータを読み込み、読み込み行を更に分解して再度CSV ファイルに書き出すというプログラムを作成しております。 事情があって、不本意ながら上記仕様のプログラムを作成せざるを得ない状況です。 本題ですが、下記プログラムを実行すると、確かに上記仕様の処理を行ってくれる のですが、5Mバイト程度のCSVファイルを処理しようとすると、処理速度が極端に 落ち、処理が終了するまで30分程の時間を要してしまいます。プログラマとしては 初歩的な質問でお恥ずかしいのですが、処理速度UPの方法をどなたかご教授して頂 けないでしょうか? ***一部抜粋*** Private Structure CsvDat Dim year As String '年 Dim month As String '月 Dim day As String '日 Dim time As String '時 Dim value1 As String '値1 Dim value2 As String '値2 End Structure Private sd() As CsvDat Private spt() As String Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim n As Integer Dim line As String Dim temp() As String Dim sr1 As New System.IO.StreamReader("読み込みファイル名", System.Text.Encoding.Default) Dim sw1 As New System.IO.StreamWriter("書き出しファイル名", False) 'ファイルの最後までループ n = 0 Do Until sr1.Peek() = -1 line = "" temp = Split(sr1.ReadLine(), ",") ReDim Preserve sd(n) spt = Split(temp(0), "/") '年月日分解 sd(n).year = spt(2) '年 sd(n).day = spt(1) '月 sd(n).month = spt(0) '日 sd(n).time = temp(1) sd(n).value1 = temp(2) sd(n).value2 = temp(3) '取得結果を書き出し line = sd(n).year & "," & sd(n).month & "," & sd(n).day & "," & sd(n).time & "," & sd(n).value1 & "," & sd(n).value2 sw1.WriteLine(line) n += 1 Loop sr1.Close() 'ファイルを閉じる sw1.Close() end Sub | ||||
|
投稿日時: 2007-05-15 13:02
sdをループの外で使うんですか? 使わないなら不要な変数だし、使うならコレクションを使ったほうがいいです。 [ メッセージ編集済み 編集者: burton999 編集日時 2007-05-15 13:03 ] | ||||
|
投稿日時: 2007-05-15 13:07
諸農です。
「sd」が何をする機能を持っているのか判りませんが、最初にReadToEnd()で読み込みテキストの行数を取得してからsdの配列要素数を決めれば良いんじゃないでしょうか。 ただ「sd」を一時的にワークとして使用しているのなら、わざわざ配列にする必要もないような気がしますが。。 _________________ 諸農和岳 Powered by Turbo Delphi & Microsoft Visual Studio 2005 十兵衛@わんくま同盟 http://blogs.wankuma.com/jubei/ | ||||
|
投稿日時: 2007-05-15 13:18
最初に調べないにしても、せめて倍倍くらいには、しましょう。
たとえば初期値100で、101行目が来たら200に、201行目が来たら400に、と。 …という処理を、コレクションなら勝手にやってくれるわけですが。 | ||||
|
投稿日時: 2007-05-15 13:22
他の方も指摘されていますが、ループごとに ReDim Preserve するのは
ヒープメモリの確保が頻繁に発生しますので、非常に効率が悪いです。 後続処理でこのデータを使用しないのならば、配列にいれない方がよいと思います。 後続で使用するため、どうしても保持する必要があるのならコレクションを遣いましょう。
この文字列の結合も、String.Format を使ったほうが速いし、見やすくなると思いますよ。 | ||||
|
投稿日時: 2007-05-15 13:25
皆さん指摘されていますが、変数 sd について何も言及されていないので、
後で利用するために配列を確保しているのかそれとも単にワークとして使 用しているのかが不明ですね。 言及されていないこともあって、私にはワークとして使用しているように見 えました。 ワークとして使用しているのであれば、burton999 さんが書かれている ように不要な変数ですし、使わずに済むのであればそちらの方がいいでしょ うね。 時間がかかるのは、ループの中で Redim しているためだと思います。 とりあえずループの中をこんな感じにしてみればいいんじゃないでしょうか。
もし後で使うために取っているというのであれば、それも皆さんがすでに書 かれているようにコレクションを使うと良いと思います。 _________________ ぽぴ王子@わんくま同盟 ぽぴ王子の人生プログラミング中 / ぽぴンち。 | ||||
|
投稿日時: 2007-05-15 13:30
CSVを扱うならTextFieldParserを使ってみてはどうでしょう。
http://www.atmarkit.co.jp/fdotnet/dotnettips/487csvparser/csvparser.html | ||||
|
投稿日時: 2007-05-15 13:44
タスクマネージャーでその間のCPU使用率はどうなっているでしょうか。100%(CPUの数によっては50%や25%)ならば、配列処理が遅いのでしょう。 もし100%よりずっと低ければディスクの読み書きのどちらかまたは両方が遅いのでしょう。APIに対してバッファーサイズの指定ができるはずなので、多めにしてはどうでしょうか。また、読み書きも、読み、と書き、に分けて計測してみることをお勧めします。 -- unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86} |