[[20181009134212]] 『テキストファイル内の数字以外の文字検索』(GCX) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『テキストファイル内の数字以外の文字検索』(GCX)

こんにちは。
VBAでプログラムを作っています。

特定のフォルダ内にテキストファイルが5000ファイルほど入っており、
1つのテキストファイルは30MB〜70MBほどあります。

テキストファイル内は共通で30行目までがコメントや見出し行となっており
同じ文言が入ります。
31行目からデータの数値が
16 37.009 0.000 -1.134 -2.460 187.674 0.116 ・・・
と20カラム分入っており
数値以外のものは入りません。
ただし、たまに文字化けしていることがあり、それを検出させたいのですが
どのようなロジックにしたらよいかわかりません。

当初はファイルを開き、全データを一旦配列に格納、vbcrlfで行ごとに区切って、
数値以外のものがないか1つ1つ確認する、という風なロジックにしていたのですが、
ファイルを開くだけで十数秒、配列に格納して区切るだけで数分かかり、
しまいにはメモリ不足となってしまってラチがあきません。

高速に数値以外の文字を検知するか、ただ単に
文字化けを検知する方法ってないでしょうか?

< 使用 Excel:Excel2010、使用 OS:Windows7 >


考え方は正しいので、今の遅くてメモリ不足になると言っているマクロを見せてください。 テキスト形式と言っても何が区切り文字なのか判らないし、Excelで保存したものかどうかも判らないし、話はそれからです。

それと、文字化けの原因を調べる事はできませんか? おそらくファイルそのものをここに貼ることはできないでしょうし、こちらでは調査できません。 例えば、問題の値を別のシートのA1セルに張り付けて、B1に「=CODE(MID($A1,COLUMN()-1,1))」という数式を埋め、これを右にドラッグコピーすることで、1文字毎の文字コードが判ります。 ここに数値関係以外のものが混じっていないか調べてみてください。
(???) 2018/10/09(火) 14:32


???様ありがとうございます。
コードはテキストのパスを与えて結果として文字化けがありそうかなさそうかでメッセージを返すような関数にしています。
あとすみません、データは29行目からの誤りでした。

Function GarblationChk(DataPath As String)

    Dim FSO As Object
    Dim TXTFile
    Dim StrREC
    Dim LengStr As Long
    Dim LineCnt As Long
    Dim NGFlag As Boolean
    Dim Msg As String
    Dim i As Long
    Dim n As Long
    Dim Tmp

    Set FSO = CreateObject("Scripting.FileSystemObject")
    NGFlag = False

    'TXTファイルを開く(Line数チェック用)
    Set TXTFile = FSO.OpenTextFile(DataPath, 8)
    LineCnt = TXTFile.Line
    TXTFile.Close

    'TXTファイルを開く(byte確認用)
    Set TXTFile = FSO.OpenTextFile(DataPath, 1)
    StrREC = Split(TXTFile.ReadAll, vbCrLf)
    TXTFile.Close

    'Line数チェック
    If LineCnt <> UBound(StrREC) + 1 Then
        NGFlag = True
        Msg = "LineFeed不一致"
    End If

    '数値チェック
    For i = 28 To UBound(StrREC)
        Tmp = Split(StrREC(i), " ")
        For n = 0 To UBound(Tmp)
            If Len(Tmp(n)) > 0 Then
                If IsNumeric(Tmp(n)) = False Then
                    NGFlag = True
                    Msg = Msg & i + 1 & "行目付近文字化けの可能性"
                    Exit For
                End If
            End If
        Next n
    Next i

    '終了処理
    If NGFlag = True Then
        GarblationChk = "NG(" & Msg & ")"
    Else
        GarblationChk = "OK"
    End If
    Set FSO = Nothing

End Function

(GCX) 2018/10/09(火) 15:37


行数比較のためだけに、1つのファイルを丸ごと2回読んでいるので、読み込み時間が単純に2倍かかっていますね。追記モードで行数調べずとも、ReadAllした末尾がどうなっているかだけ調べるだけで済んだりしないでしょうか?

後は、この自作関数を呼び出す度にFSOをCreateObjectしてますよね? これを引数にして、CreateObjectするのは呼び元で1回にすべきと思います。これで5000回分のCreateObject時間が稼げるでしょう。(Nothingにするのも呼び元で)

関数を抜ける直前に DoEvents を入れてみるのも、効果があるかも知れません。(OSにメモリ解放処理する隙を与える) 逆に、十分処理できていた場合は、少し処理時間が伸びる可能性もありますが。

あと、メモリ不足になるのは、どの箇所でしょう? FSOの確保・解放が連続するので解放が追い付いていないのなら、上の変更で変わるかも知れません。 これでもメモリ不足になるならば、それは対象のテキストファイルが大きすぎるということが考えられるので、1行ずつLine Inputする方法に変えれば収まるでしょう。 でも、1行ずつ読むと、処理時間は増大してしまうので、もう少し様子見です。(対策案としては、FileLen関数でファイルサイズを調べ、一定上ならLine Inputで処理。処理可能なものなら一気読みにする、等)
(???) 2018/10/09(火) 18:17


???さま
返信遅くなり申し訳ありません。

1.読み込み2回を1回に変更
2.都度FSOインスタンスを生成してたのを呼び出し元で1回のみ生成
3.メモリ不足は StrREC = Split(TXTFile.ReadAll, vbCrLf) のあたりでしたので1行ずつ読み込ませるように変更

したら全体の処理的にも早くなり、メモリ不足もなくなりました。
ありがとうございました!!

(GCX) 2018/10/10(水) 09:02


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.