次の方法で共有


VBAでUTF8形式テキストファイルを1行ずつ正常に読込めない

質問

2018年6月10日日曜日 17:42

次のVBAでUTF8形式テキストファイルを1行ずつ読み込めません。

(A)の個所で、2行目以降は、行の先頭が1列目からではなく、行の途中から読み込んでいるようです。

このため、(B)の行の先頭にある日付の比較で合致せず、必要なログの抽出ができません。

なぜでしょうか。ご教示いただきたく宜しくお願い致します。

Sub chk_Log()
    Dim i As Long
    Dim rBk As Workbook
    Dim Path, Target As String
    Dim toDay As Date
   
    toDay = Date
   
    Path = ThisWorkbook.Path & "\aaaadata.log"
    Target = Path
   
    Set rBk = Workbooks.Add
   
    i = 0
       
    With CreateObject("ADODB.Stream")
        .Charset = "UTF-8"
        .Open
        .LoadFromFile Target
       
        Do Until .EOS
            Logrec = .ReadText(-2)  <--(A)
            If toDay <= Left(Logrec, 10) Then   <--(B)
                i = i ; 1
                rBk.Sheets(1).Cells(i, 1) = Logrec
            End If
        Loop
       
        .Close
    End With
       
End Sub

すべての返信 (7)

2018年6月11日月曜日 1:17 ✅回答済み | 1 票

Windows 7 SP1, ADODB.Stream.6.0, Excel 2007で確認しましたが、BOM付き・BOM無し共に問題なく行単位で読めました。

とりあえず、以下の点を確認されてみては。

  • 読み取った各行を全て各セルに出力するなどして、ReadTextがどのような文字列を返してきているか
  • テキストファイルの改行がCRLFになっているか(バイナリエディタで開いて、0D 0Aを確認する)※ADODB.StreamではCRのみまたはLFのみは改行として認識されないようです。

2018年6月12日火曜日 0:31 ✅回答済み | 1 票

その UTF-8 ファイルの改行コードを確認してみてください。
ADODB.Stream 側での改行の切り替えは、LineSeparator プロパティで行えます。

このプロパティの既定値は adCRLF (=-1) で、VBA でいうところの vbCrLf (0D,0A) に相当します。
adCR (=&H0D) にすると、vbCr 改行(0D) 扱いで
adLF (=&H0A) にすると、vbLf 改行(0A) 扱いです。

この 3 種類以外の改行については、行単位であるとは認識されません。
また、複数の改行コードが混在しているようなファイルにも対応していません。

もしも改行コードの混在がありえる場合には、
.ReadText( adReadLine ) で行単位に読み取るのではなく、
.ReadText( adReadAll ) でファイル全体を読み取った上で
自前で改行コードの統一化や切り出しを行うようにします。

Dim allText As String
'ファイル全体を読み取り
allText = stm.Read(adReadAll)

'Replace 呼び出しを 3 回行うことで、
'Cr / CrLf / Lf が混在しているテキストを CrLf 改行に揃える
allText = Replace(allText, vbCrLf, vbLf, , , vbBinaryCompare)
allText = Replace(allText, vbCr, vbLf, , , vbBinaryCompare)
allText = Replace(allText, vbLf, vbCrLf, , , vbBinaryCompare)

'CrLf で区切って、一次元配列に変換
Dim lines() As String
lines = Split(allText, vbCrLf, , vbBinaryCompare)

2018年6月12日火曜日 4:03 ✅回答済み | 1 票

改行のチェックが済んでからの話ですが、

If toDay <= Left(Logrec, 10) Then
これはおかしいです。
(セルには自動で日付型に変換して入れてくれますが)
(文字列の段階での比較はうまくいかない思いますけど、、)

Dim var As Variant     '追加
      var = Left(Logrec, 10)
      If IsDate(var)
      If toDay <= CDate(var)
など。


2018年6月12日火曜日 5:28 ✅回答済み | 2 票

If toDay <= Left(Logrec, 10) Then

これはおかしいです。
(セルには自動で日付型に変換して入れてくれますが)
(文字列の段階での比較はうまくいかない思いますけど、、)

「書式がyyyy/mm/ddで、1桁の数値には前ゼロが必ず付いている」を前提とできるなら、文字列の比較で問題ないです。


2018年6月12日火曜日 6:04 ✅回答済み | 2 票

さらに言うと、Logrec 側と toDay 側の双方の書式が問題となりえますね。

今回の場合、変数 toDay は Date 型ですが、対する Left 関数は「内部処理形式 String のバリアント型」を返すため、日付型としての比較ではなく、文字列型としての比較処理が行われます。

暗黙の型変換によって、日付型が文字列型に変換される場合、その書式はコントロールパネルの地域設定に依存したものとなります。そのため、たとえば和暦モードに設定されている環境で実行した場合などは、予期していた物とは異なる結果になる可能性があります。

しかし UTF-8 なファイルの方は、コントロールパネル依存なわけではなく、固定フォーマットなはずです。できれば toDay 変数は String 型に変更しておき、Format 関数で明示的な書式指定を行うことをお奨めします。


2018年6月12日火曜日 7:43

一旦、すべて読込んで処理することにしました。

また、日付の比較についても、月と日は2桁の固定であることから、正常に処理することができました。

皆さんありがとうございます。


2018年6月12日火曜日 9:45 | 1 票

いまから書いてもいいのかなあ、、

そうなんですか、ガックリガックリ。
たしかにtoDay以前のものははじいてますね(ビックリ)。
(toDay以後と日付なしの行は通してますけれど。)
(2018-9-21とか、2019/11/9の日付でも大丈夫でした。)
("2005-5-7  発送方法" のように2個以上スペースを入れておく必要がありますが)