2005-09-09  Excel VBAで改行コードがLFのファイルを読む

Excel VBAで,CRLF以外の改行コードが含まれたテキストファイルを読み込むコードを作りました。

あらまし

VBAではLine Input # ステートメントを使うと,シーケンシャルファイルから1行ずつ読み込むことができます。

ところで,改行コードがLFのファイルを読み込ませてみたら,Excelが応答しなくなってしまいました。 Line Input # ステートメントは,改行コードがLFのファイルには対応していないようです。

そこでCRLF,LF,CRの三種類の改行コードに対応したコードを作ってみました。

動作概要

  • ファイルをバイナリモードで読み出した後,改行コードを認識し1行の文字列に変換する
  • バッファを設けて読み出しの効率化を図る

仕様

  • 認識する改行コード列はCRLF,LF,CRの三種類
  • ファイルの末尾に改行コードがなかった場合にも対応
  • MacのVBAに対応

注意事項

  • このコードは無保証です
  • 細かな挙動は不明です。巨大なファイル,1行がやたらと長いファイル,そもそも改行が一つもないファイルなどを読み込んだ場合にどんな挙動をするか明らかではありません
  • VBA歴の浅い人が書いたので,VBAっぽくないコードかもしれません

コード

Const FILEBUFSIZE = 32767

Dim CR As String
CR = Chr(13)
#If Not Mac Then
    CR = StrConv(CR, vbFromUnicode)
#End If

Dim LF As String
LF = Chr(10)
#If Not Mac Then
    LF = StrConv(LF, vbFromUnicode)
#End If

Dim FileNum As Variant
FileNum = FreeFile()

Open "filename" For Binary Access Read As FileNum Len = FILEBUFSIZE

Dim byteBuf(FILEBUFSIZE - 1) As Byte
Dim strBuf As String
strBuf = ""

Dim FileSize As Long
FileSize = LOF(FileNum)

Do Until EOF(FileNum)

    Get FileNum, , byteBuf

    Dim SeekPoint As Long
    SeekPoint = Seek(FileNum) - 3

    If SeekPoint <= FileSize Then
        strBuf = strBuf & CStr(byteBuf)
    Else
        strBuf = strBuf & LeftB(CStr(byteBuf), FILEBUFSIZE - (SeekPoint - FileSize))
    End If

    Dim p1 As Long
    p1 = 0

    Dim p2 As Long
    p2 = 0

    Do
        p1 = InStrB(1, strBuf, CR, vbBinaryCompare)
        p2 = p1

        If p1 <> 0 Then

            If LenB(strBuf) < p1 + 1 Then
                p1 = 0
            ElseIf MidB(strBuf, p1 + 1, 1) = LF Then
                p2 = p2 + 1
            End If

        Else
           p1 = InStrB(1, strBuf, LF, vbBinaryCompare)
           p2 = p1
        End If

        If p1 = 0 And EOF(FileNum) And LenB(strBuf) > 0 Then
            p1 = LenB(strBuf)
            p2 = p1
        End If

        '

        If p1 <> 0 Then
            Dim head As String
            Dim tail As String

            head = MidB(strBuf, 1, p1 - 1)
            tail = MidB(strBuf, p2 + 1)

            #If Not Mac Then
                head = StrConv(head, vbUnicode)
            #End If

            Dim CurrentLine As String
            CurrentLine = head

            Debug.Print CurrentLine

            strBuf = tail
        End If

    Loop While p1 <> 0
Loop

Close FileNum

ほかの方法

(1) FileSystemObjectオブジェクトのReadLineメソッドも,改行コードLFに対応しているそうです(伝聞なので検証なし)。現在は,このFileSystemObjectオブジェクトを使う方法が主流なのかもしれません。

(2) Excelの機能である「外部データの取り込み」を使うと,シートに任意のテキストファイルを読み出すことができます。この機能では改行コードLFのファイルも読めます。VBAヘルプでQueryTablesオブジェクトを調べてみてください。

メモ

  • 改行コードの種類。WindowsのVBAの改行コードはCRLF(0x0d-0x0a),MacのVBAの改行コードはCR(0x0d)です
  • 文字コード。VBAが出力するテキストファイルの文字コードは,CP932の「はず」です。CP932はSHIFT-JISに拡張文字(たとえば丸で囲んだ数字)を追加した文字コードです
  • Unicode。WindowsのVBAでは内部の文字コードをUnicodeで扱っています。テキストファイルをバイナリファイルとして読み出した場合,その文字列はUnicodeとして扱われません。文字列の比較ならびに出力する際は,明示的に文字コードを変換しなければなりません。MacのVBAはUnicodeを採用していないので,文字コードの変換は不要です
  • GETステートメント。GETステートメントは,常にOpenステートメントで指定したバッファ容量を読み出します。ファイルの末尾だからといって読み出す容量が減ることはありません。ファイル容量を超えて読み出したデータは切り捨てなければなりません