LoginSignup
3
3

More than 3 years have passed since last update.

【VBS】テキストファイルの処理速度について

Posted at

はじめに

CSVファイルを読み込んで別のCSVファイルを出力する、という処理をVBScriptで書いていたところ、処理速度が遅くなり、改善のため試行錯誤することになりました。
そこで、テキストの書き込みに関して、どのような処理が遅いのか、少し調べてみます。

1行ずつ書き込む場合

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim output
output = "xxx\output.csv"

Dim write
Set write = fso.OpenTextFile(output, 2, True)

Dim i
For i = 1 To 1000
    write.WriteLine("abc")
Next

write.Close

【結果】
約0.01秒/1,000行
約0.1秒/10,000行
約1.1秒/100,000行

思っていたほど遅くありません。大きなファイルでなければ特に工夫せずに1行ずつ書き込んでも問題なさそうです。

毎回ファイルを開いて書き込む場合

開く度に閉じる場合

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim output
output = "xxx\output.csv"

Dim write

Dim i
For i = 1 To 1000
    Set Write = fso.OpenTextFile(output, 8, True)
    write.WriteLine("abc")
    write.Close
Next

【結果】
約11秒/1,000行

開いたあと閉じる処理を書かない場合

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim output
output = "xxx\output.csv"

Dim write

Dim i
For i = 1 To 1000
    fso.OpenTextFile(output, 8, True).WriteLine("abc")
Next

【結果】
約10秒/1,000行

OpenTextFileTextStreamオブジェクトを取得する処理が遅いようです。
実際の作業では、ここにハマって失敗しました。
1つのファイルにつき1回で済ませるべきですね。

文字列を結合して一気に書き込む

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim output
output = "xxx\output.csv"

Dim write
Set Write = fso.OpenTextFile(output, 2, True)

Dim str

Dim i
For i = 1 To 1000
    str = str & "abc" & vbCrLf
Next

write.WriteLine(str)
write.Close

【結果】
約0.01秒/1,000行
約0.07秒/10,000行
約9秒/100,000行

行が多くなるとかなり遅くなるという意外な結果ですが、「VBA 文字列結合 遅い」とググるといろいろ情報が出てきます。文字列結合は遅いのですね。
行数が少なければ気にしなくても良いかもしれませんが、多い場合は注意が必要です。

連想配列に文字列を格納し、ループ処理で書き込む

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim output
output = "xxx\output.csv"

Dim write
Set Write = fso.OpenTextFile(output, 2, True)

Dim dict
Set dict = CreateObject("Scripting.Dictionary")

Dim i
For i = 1 To 1000
    dict.Add i, "abc"
Next

Dim key
For Each key In dict
    write.WriteLine(dict(key))
Next

write.Close

【結果】
約0.01秒/1,000行
約0.15秒/10,000行
約1.8秒/100,000行

実用的な速度だと思います。

配列に文字列を格納し、ループ処理で書き込む

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim output
output = "xxx\output.csv"

Dim write
Set Write = fso.OpenTextFile(output, 2, True)

Dim arr(999)

Dim i
For i = 1 To 1000
    arr(i - 1) = "abc"
Next

Dim str
For Each str In arr
    write.WriteLine(str)
Next

write.Close

【結果】
約0.01秒/1,000行
約0.15秒/10,000行
約1.2秒/100,000行

これもなかなかの速度ですね。
1行ずつ書き込む処理とあまり時間が変わらないところをみると、配列への格納や配列からのデータの取り出しには時間がかからないようです。

配列に文字列を格納し、Join関数で結合して書き込む

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

Dim output
output = "xxx\output.csv"

Dim write
Set Write = fso.OpenTextFile(output, 2, True)

Dim arr(999)

Dim i
For i = 1 To 1000
    arr(i - 1) = "abc"
Next

write.WriteLine(Join(arr, vbCrLf))
write.Close

【結果】
約0.01秒/1,000行
約0.01秒/10,000行
約0.04秒/100,000行
約0.4秒/1,000,000行

おお、早い。書き込みを1回にしたからですね。
何らかの事情で、文字列をどこかに確保したあとで書き込みたい場合は、この手法を使うのが良いようです。
配列のサイズをうまく調整できるかがポイントです。

おまけ

VBSではCollectionが使えません。
Dictionaryを使いましょう。
VBSではLikeが使えません。
→部分一致の場合はInStrを使いましょう。そうでない場合は正規表現を使いましょう。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3