解析結果として得られた大量のテキストファイルを高速で1つのエクセルファイルに読み込むマクロを作る
目的とフローチャート
今回の目的は,前回(>XFLR5で二次元翼を解析して結果を出力する)で出力した大量のテキストファイルを1つのエクセルファイルに読み込むことである
テキストファイルの中身はこんな感じ
最初の数行にファイルの説明があって,それ以下にスペース区切りでデータが入力されている
xflr5 v6.43
Calculated polar for: DAE31
1 1 Reynolds number fixed Mach number fixed
xtrf = 1.000 (top) 1.000 (bottom)
Mach = 0.000 Re = 0.100 e 6 Ncrit = 9.000
alpha CL CD CDp Cm Top Xtr Bot Xtr Cpmin Chinge XCp
------- -------- --------- --------- -------- ------- ------- -------- --------- ---------
-9.800 -0.2128 0.13213 0.12747 -0.0500 0.9789 0.0569 -1.3124 0.0000 -0.0078
-9.700 -0.2097 0.13112 0.12646 -0.0507 0.9774 0.0575 -1.3107 0.0000 -0.0147
-9.600 -0.2060 0.13007 0.12541 -0.0517 0.9760 0.0581 -1.3141 0.0000 -0.0244
-9.500 -0.2023 0.12906 0.12440 -0.0532 0.9747 0.0586 -1.3268 0.0000 -0.0365
-9.400 -0.1991 0.12813 0.12348 -0.0551 0.9736 0.0589 -1.3504 0.0000 -0.0503
-9.300 -0.1970 0.12709 0.12245 -0.0552 0.9719 0.0591 -1.3435 0.0000 -0.0537
-9.200 -0.1920 0.12580 0.12116 -0.0554 0.9705 0.0596 -1.3205 0.0000 -0.0626
-9.100 -0.1870 0.12461 0.11997 -0.0561 0.9692 0.0601 -1.3065 0.0000 -0.0745
-9.000 -0.1817 0.12345 0.11880 -0.0571 0.9680 0.0608 -1.3019 0.0000 -0.0896
-8.900 -0.1764 0.12228 0.11764 -0.0586 0.9670 0.0616 -1.3054 0.0000 -0.1077
: : : : : : : : : :
18.900 1.6401 0.11388 0.10755 -0.0790 0.0766 1.0000 -6.1234 0.0000 0.2624
19.000 1.6434 0.11462 0.10825 -0.0791 0.0749 1.0000 -6.1735 0.0000 0.2620
19.100 1.6363 0.11708 0.11086 -0.0801 0.0740 1.0000 -6.1546 0.0000 0.2626
19.200 1.6338 0.11880 0.11265 -0.0808 0.0727 1.0000 -6.1657 0.0000 0.2628
19.300 1.6412 0.11885 0.11260 -0.0805 0.0708 1.0000 -6.2426 0.0000 0.2621
19.400 1.6331 0.12152 0.11543 -0.0817 0.0702 1.0000 -6.2143 0.0000 0.2629
19.500 1.6277 0.12376 0.11779 -0.0828 0.0693 1.0000 -6.2035 0.0000 0.2634
19.600 1.6412 0.12274 0.11658 -0.0818 0.0671 1.0000 -6.3208 0.0000 0.2622
19.700 1.6319 0.12566 0.11967 -0.0833 0.0666 1.0000 -6.2826 0.0000 0.2631
19.800 1.6237 0.12842 0.12259 -0.0848 0.0661 1.0000 -6.2505 0.0000 0.2640
19.900 1.6176 0.13087 0.12515 -0.0861 0.0654 1.0000 -6.2310 0.0000 0.2648
20.000 1.6190 0.13194 0.12623 -0.0865 0.0643 1.0000 -6.2641 0.0000 0.2647
Excelファイルとテキストデータは同じディレクトリにおいてあり,Re数が100,000から1,000,000までのデータが20,000おきに出力されている
この手法は,学生実験などの結果がテキストファイルで与えられたときなどにも役立つと思うのでぜひ参考にしてほしい
マクロのフローチャートを以下に示す
- 変数を宣言する
- 必要な値をシートから読み込む
- 読み込んだ値からテキストファイルのファイル数を計算し,ループを始める
- 読み込みたいファイル名を生成する
- テキストファイルを開く
- テキストファイルを1行ずつ読み込む
- 1行を数値ごとに分割して配列に格納する
- さらにループを回してすべての必要なデータを配列に格納する
- ファイルを閉じる
- すべてのファイルについて上の処理が終われば,配列をエクセルシートに貼り付ける
プログラムの解説
それでは実際に解説していく
プログラム全文は以下の通り
Sub ReadTextFile()
'変数の宣言
Dim file_number As Integer 'ファイル数
Dim data_number As Integer 'データ数
Dim Re_min As Double '最小Re数
Dim Re_max As Double '最大Re数
Dim Re_delta As Double 'Re数刻み
Dim foil_name As String '翼型名
Dim file_name As String 'ファイル名
Dim data(30000, 10) As Double 'データ格納用配列
Dim data_tmp As Variant
'カウンター
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim n As Integer
'タイマーの変数
Dim startTime As Double
Dim endTime As Double
Dim processTime As Double
'ActiveWorkbook.Save'まず上書き保存
Application.ScreenUpdating = False '画面更新の非表示
Application.DisplayAlerts = False '警告画面の非表示
startTime = Timer '開始時間取得
'値の読み込み
Re_min = Cells(1, 4) '最小Re数
Re_max = Cells(1, 6) '最大Re数
Re_delta = Cells(1, 8) 'Re数刻み
foil_name = Cells(1, 2) '翼型名
'ファイル数の計算
file_number = (Re_max - Re_min) / Re_delta + 1
For i = 0 To file_number - 1 'すべてのファイルのループ
'開きたいファイル名を作る
file_name = foil_name & "_T1_Re" & Format((Re_min + Re_delta * i) / 1000000, "0.000") & "_M0.00_N9.0.txt"
Open ThisWorkbook.Path & "\" & file_name For Input As #1 'txtファイルを読込専用で開く
j = 0
Do Until EOF(1) 'txtファイルの終わりまでのループ
Line Input #1, buf '1行ごとに読み込み
If (j > 10 And buf <> "") Then
data_tmp = Split(buf, " ") '文字列を空白で分割
num = 0
For k = 0 To UBound(data_tmp, 1)
If (data_tmp(k) <> "") Then '空白を飛ばして読み込み
data_tmp(num) = data_tmp(k)
num = num + 1
End If
Next k
'文字列からDoubleに変換する
data(data_number, 0) = Val(data_tmp(0)) 'alpha
data(data_number, 1) = Val(data_tmp(1)) 'Cl
data(data_number, 2) = Val(data_tmp(2)) 'Cd
data(data_number, 3) = Val(data_tmp(4)) 'Cm
data(data_number, 4) = Re_min + Re_delta * i 'Re
data_number = data_number + 1
End If
j = j + 1
Loop
Close #1
Application.StatusBar = "反復回数" & i & "/" & file_number - 1 'ステータスバーに反復回数を表示
DoEvents
Next i
Application.StatusBar = False
Range(Cells(2, 1), Cells(2 + data_number - 1, 5)) = data()
'終了時間取得
endTime = Timer
'処理時間表示
processTime = endTime - startTime
MsgBox "計算が終了しました" & vbCrLf & "処理時間:" & processTime
End Sub
使用する変数
マクロに使用する変数を以下に示す
'変数の宣言
Dim file_number As Integer 'ファイル数
Dim data_number As Integer 'データ数
Dim Re_min As Double '最小Re数
Dim Re_max As Double '最大Re数
Dim Re_delta As Double 'Re数刻み
Dim foil_name As String '翼型名
Dim file_name As String 'ファイル名
Dim data(30000, 10) As Double 'データ格納用配列
Dim data_tmp As Variant
'カウンター
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim n As Integer
'タイマーの変数
Dim startTime As Double
Dim endTime As Double
Dim processTime As Double
データ数data_numberは最後に配列をシートに貼り付けるときのみ使用
データ格納用配列data()を動的配列にしてもよかったが,面倒なのでやめた.データ数は30000もあれば十分だろう
ほしいデータの種類はα,CL,CD,Cm,Reなので,余裕をもってdata(0:30000, 0:10)で宣言した
前準備
(>Excel VBA/マクロ について知っておいてほしいこと)でも言ったとおり,マクロの操作は戻るボタンで取り消せないので,壊滅的な被害を防ぐためにプログラムの最初に次のコードを入れておく
ActiveWorkbook.Save '上書き保存
Application.ScreenUpdating = False '画面更新の非表示
Application.DisplayAlerts = False '警告画面の非表示
警告画面というのは,Excelファイルを閉じるときの「変更内容を保存しますか?」みたいなやつのこと
値の読み込み・ファイル数の計算
まず,今回のマクロに必要な値をシートから読み込む
'値の読み込み
Re_min = Cells(1, 4) '最小Re数
Re_max = Cells(1, 6) '最大Re数
Re_delta = Cells(1, 8) 'Re数刻み
foil_name = Cells(1, 2) '翼型名
読み込みに使うのはRangeでもCellsでもいいが,両方使えるときはCellsのほうが少し早いらしい
解析に使用した最小Re,最大Re,およびRe数の刻みから,解析結果のファイル数は次のように計算できる
'ファイル数の計算
file_number = (Re_max - Re_min) / Re_delta + 1
ファイルのループ開始
ファイルのループを開始する
data_number = 0
For i = 0 To file_number - 1 'すべてのファイルのループ
(各ファイルについての処理)
next i
データ数data_numberは,配列に格納しながら数えていくので,ループが始まる前に初期値の0を入れておく
ファイル名の生成
それぞれのファイルについて,まず開きたいファイル名を生成する
i番目のファイルのファイル名をfile_nameに格納するコードは次のようになる
'開きたいファイル名を作る
file_name = foil_name & "_T1_Re" & Format((Re_min + Re_delta * i) / 1000000, "0.000") & "_M0.00_N9.0.txt"
&は複数の文字列の結合で,Format(数値,書式)
を使えば,指定した桁数で数値を文字列に変換できる
ファイルを開く/閉じる
ファイルを開くにはOpen
を使い,ファイルがある場所(パス)とファイル名を指定する必要がある
Open ThisWorkbook.Path & "\" & file_name For Input As #1 'txtファイルを読込専用で開く
ThisWorkbook.Path
はむちゃくちゃ便利な奴で,マクロが書かれているエクセルシートと同じ場所を指定してくれる
こうすれば,だれがどのパソコンで使おうと,2つのファイルが同じフォルダにありさえすればいいので使いやすい
ファイルを閉じるには次のコードを使えばいい
Close #1
エクセルシートを置いているフォルダをOneDriveと同期している場合はThisWorkbook.Pathが使えないのでこちらを参考
≫[VBA]OneDriveで同期しているファイルまたはフォルダのURLをローカルパスに変換する関数
OneDriveUrlToLocalPath(ByRef Url As String)
テキストファイルを行ごとに読み込む
行ごとにテキストファイルのデータを読み込んでいく
j = 0
Do Until EOF(1) 'txtファイルの終わりまでのループ
Line Input #1, buf '1行ごとに読み込み
If (j > 10 And buf <> "") Then
data_tmp = Split(buf, " ") '文字列を空白で分割
num = 0
For k = 0 To UBound(data_tmp, 1)
If (data_tmp(k) <> "") Then '空白を飛ばして読み込み
data_tmp(num) = data_tmp(k)
num = num + 1
End If
Next k
'文字列からDoubleに変換する
data(data_number, 0) = Val(data_tmp(0)) 'alpha
data(data_number, 1) = Val(data_tmp(1)) 'Cl
data(data_number, 2) = Val(data_tmp(2)) 'Cd
data(data_number, 3) = Val(data_tmp(4)) 'Cm
data(data_number, 4) = Re_min + Re_delta * i 'Re
data_number = data_number + 1
End If
j = j + 1
Loop
行数がわからないテキストファイルを読み込むには, Do Until EOF(1) ~ Loop
を使う
ファイルの最終行(End of File:EOF)に到達すると自動的にループを抜けてくれる
If (j > 10 And buf <> "") Then ~ End If
と j = j + 1
で,テキストファイル冒頭の説明の部分の読み込みをスキップしている
テキストファイルを行ごとに読み込むには, Line Input
を使う.読み込み先のファイルとして#1
を指定し,読み込んだ行は文字列としてbuf
に格納される
Line Input #1, buf
によって,buf
には次の文字列が格納されている
" -9.800 -0.2128 0.13213 0.12747 -0.0500 0.9789 0.0569 -1.3124 0.0000 -0.0078"
この文字列を data_tmp = Split(buf, " ")
の行で空白区切りにしてdata_tmp
に格納している
この時点では,data_tmp
の配列の中には次のような空の要素""
が混じってしまっている
この空の要素は For k = 0 To UBound(data_tmp, 1) ~ Next k
で取り除かれている
最後はVal()
を使って文字列を数値に変換して出力用配列data()
に格納している
値の貼り付け
すべてのファイルについてのループを終了すれば,最後にデータをエクセルシートに貼り付ける
'値の貼り付け
Range(Cells(2, 1), Cells(2 + data_number - 1, 5)) = data()
配列の貼り付けはこれでできる
くれぐれもセル1つずつに数千回貼り付けを行うようなことはしないように
これでコードは終了である
プログラムの実行
今回作成したプログラムを実際に実行してみる
46個のファイルを読み込んで実行時間は約0.5秒だった
まとめ
2年前に書いた記事のプログラムと比べて,実行時間を50倍以上高速化することができた
上の説明でわからないことがあればグーグルで検索してみよう.きっと答えはそこにあるはず
↓おすすめ記事
コメント