VB.NETでテキストファイルを読み書きする方法!(StreamReader/Writer)

VB.NET

VB.NETでテキストファイルを扱うことは、アプリケーション開発において非常に一般的なタスクです。
設定ファイルの読み込み、ログの出力、データの保存と読み出しなど、様々な場面でファイルの読み書きが必要になります。

VB.NETではSystem.IO名前空間のStreamReaderクラスとStreamWriterクラスが、テキストファイルの読み書きを行うための主要な手段として提供されています。
この記事ではStreamWriter を使った書き込み、StreamReader を使った読み込み、そしてリソースの適切な管理に不可欠な Using ステートメントの重要性について解説します。

StreamWriterでテキストファイルを書き込む

StreamWriter クラスは、指定したファイルにテキストを書き込むために使用されます。

構文

' 新しいファイルを作成または既存ファイルを上書き
Dim writer As New StreamWriter("ファイルパス")

' 既存ファイルに追記
Dim writer As New StreamWriter("ファイルパス", True)

' エンコーディングを指定
Dim writer As New StreamWriter("ファイルパス", False, System.Text.Encoding.UTF8)
  • "ファイルパス": 書き込み対象のファイルのパスを指定します。
  • True (2番目の引数): ファイルが既に存在する場合に追記します。省略または False の場合、ファイルは上書きされます。
  • System.Text.Encoding.UTF8: エンコーディングを指定します。省略した場合、システムのデフォルトエンコーディングが使用されます。

ファイルへの書き込み (Write / WriteLine)

  • Write(text As String): 指定したテキストを書き込みます。改行は追加されません。
  • WriteLine(text As String): 指定したテキストを書き込み、その後に改行を追加します。

ファイルの閉鎖 (Close / Dispose / Using ステートメント)

ファイル操作が完了したら、必ずStreamWriterオブジェクトを閉じる必要があります。
これにより、書き込みバッファがフラッシュされ、ファイルハンドルが解放されます。

閉じ忘れると、データが完全に書き込まれなかったり、ファイルがロックされたままになったりする可能性があります。

  • Closeメソッド: 明示的にファイルを閉じます。
  • Disposeメソッド: Closeと同じくリソースを解放します。Usingステートメントで自動的に呼び出されます。
  • Usingステートメント: 最も推奨される方法です。 後述の「Usingステートメントの重要性」で詳しく説明します。

実際に使ってみる

実際にStreamWriterを使って、ファイルの書き込みを行ってみます。

Imports System.IO ' System.IO 名前空間をインポート

Module StreamWriterExample
    Sub Main()
        Dim filePath As String = "example.txt"

        ' --- 新規作成または上書き ---
        Console.WriteLine($"'{filePath}' に新規書き込みまたは上書きします。")
        Using writer As New StreamWriter(filePath, False, System.Text.Encoding.UTF8)
            writer.WriteLine("これは最初の行です。")
            writer.WriteLine("これは2番目の行です。")
            writer.Write("これは改行なしのテキストです。")
            writer.WriteLine("これは改行ありのテキストです。")
        End Using
        Console.WriteLine("書き込みが完了しました。")

        ' --- 追記 ---
        Console.WriteLine($"'{filePath}' に追記します。")
        Using writer As New StreamWriter(filePath, True, System.Text.Encoding.UTF8)
            writer.WriteLine("--- 追記された行 ---")
            writer.WriteLine("これは追記された新しい行です。")
        End Using
        Console.WriteLine("追記が完了しました。")

    End Sub
End Module

この例では、まずexample.txtというファイルに新規でテキストを書き込んでいます。

StreamWriterの第2引数をFalseにすることで、ファイルが既に存在する場合は上書きされます。
WriteLineで改行付きの行を、Writeで改行なしのテキストを書き込んでいます。

次に、同じファイルにテキストを追記しています。StreamWriterの第2引数をTrueにすることで、既存のファイルの内容を消さずに末尾に新しいテキストが追加されます。
どちらの操作もUsingステートメントを使用しており、ブロックの終了時にStreamWriterオブジェクトが自動的に閉じられ、リソースが適切に解放されます。

実際に作られたファイルを確認すると、下記のように書き込まれていることが確認できました。
VB.NETでStreamWriterの動作確認

StreamReaderでテキストファイルを読み込む

StreamReaderクラスは、指定したファイルからテキストを読み込むために使用されます。

構文

' ファイルを読み込み用に開く
Dim reader As New StreamReader("ファイルパス")

' エンコーディングを指定
Dim reader As New StreamReader("ファイルパス", System.Text.Encoding.UTF8)
  • "ファイルパス": 読み込み対象のファイルのパスを指定します。
  • System.Text.Encoding.UTF8: エンコーディングを指定します。省略した場合、システムのデフォルトエンコーディングが使用されます。

ファイルからの読み込み (Read / ReadLine / ReadToEnd)

  • Read() メソッド: ストリームから次の文字を読み込み、その文字の整数表現を返します。ファイルの末尾に達すると -1 を返します。
  • ReadLine() メソッド: ストリームから現在の行を読み込み、文字列として返します。ファイルの末尾に達すると Nothing を返します。
  • ReadToEnd() メソッド: ストリームの現在の位置から末尾まですべての文字を読み込み、1つの文字列として返します。

ファイルの閉鎖 (Close / Dispose / Usingステートメント)

StreamWriter と同様に、StreamReader もファイル操作が完了したら必ず閉じる必要があります。

実際に使ってみる

実際にStreamReaderをつかってファイルを読み込んでみます。

Module StreamReaderExample
    Sub Main()
        Dim filePath As String = "example.txt"

        ' ファイルが存在することを確認
        If System.IO.File.Exists(filePath) Then
            Console.WriteLine($"'{filePath}' から読み込みます。")

            ' --- 1行ずつ読み込み ---
            Console.WriteLine("--- 1行ずつ読み込み (ReadLine) ---")
            Using reader As New StreamReader(filePath, System.Text.Encoding.UTF8)
                Dim line As String
                Do
                    line = reader.ReadLine()
                    If line IsNot Nothing Then
                        Console.WriteLine(line)
                    End If
                Loop While line IsNot Nothing
            End Using

            ' --- 全体を一度に読み込み ---
            Console.WriteLine("--- 全体を一度に読み込み (ReadToEnd) ---")
            Using reader As New StreamReader(filePath, System.Text.Encoding.UTF8)
                Dim fileContent As String = reader.ReadToEnd()
                Console.WriteLine(fileContent)
            End Using

        Else
            Console.WriteLine($"エラー: ファイル '{filePath}' が見つかりません。")
        End If
    End Sub
End Module

この例では、まずSystem.IO.File.Existsでファイルが存在するか確認しています。

最初の読み込みでは、ReadLineメソッドを使ってファイルを1行ずつ読み込み、Nothingが返されるまでループを続けています。
これにより、ファイルの内容を1行ずつ処理できます。

2番目の読み込みでは、ReadToEndメソッドを使ってファイルの内容すべてを一度に読み込み、fileContent変数に文字列として格納しています。
これは、ファイル全体をメモリに読み込んでから処理したい場合に便利です。

どちらの操作もUsingステートメントを使用しており、ブロックの終了時にStreamReaderオブジェクトが自動的に閉じられ、リソースが適切に解放されます。

実際に実行してみると、下記のように出力されました。
1行ずつでも全体を一度に読み込む方法でも、しっかり内容が読めていることが確認できました。

'example.txt' から読み込みます。
--- 1行ずつ読み込み (ReadLine) ---
これは最初の行です。
これは2番目の行です。
これは改行なしのテキストです。これは改行ありのテキストです。
--- 追記された行 ---
これは追記された新しい行です。
--- 全体を一度に読み込み (ReadToEnd) ---
これは最初の行です。
これは2番目の行です。
これは改行なしのテキストです。これは改行ありのテキストです。
--- 追記された行 ---
これは追記された新しい行です。

Usingステートメントの重要性

ファイル操作を行う上で、Using ステートメントは非常に重要です。

リソースの自動解放

StreamReaderStreamWriter のようなファイル操作オブジェクトは、内部でファイルハンドルなどのシステムリソースを使用します。
これらのリソースは、使用後に明示的に解放しないと、ファイルがロックされたままになったり、メモリリークの原因になったりする可能性があります。

Usingステートメントは、IDisposableインターフェースを実装するオブジェクトに対して、ブロックの終了時に自動的にDisposeメソッドを呼び出すことを保証します。
これにより、開発者が手動で CloseDisposeを呼び出す手間を省き、リソースの解放忘れを防ぐことができます。

なぜ重要か

  • リソースリークの防止: ファイルハンドルやネットワーク接続など、OSレベルのリソースは有限です。解放されないまま放置されると、システム全体のパフォーマンスに影響を与えたり、他のアプリケーションが同じファイルにアクセスできなくなったりします。
  • コードの簡潔性: Try...Finally ブロックで手動で Close を呼び出すよりも、はるかに簡潔に記述できます。
  • 例外安全性: Usingブロック内で例外が発生した場合でも、Disposeメソッドは確実に呼び出されます。

実際に使ってみる

Module UsingStatementExample
    Sub Main()
        Dim filePath As String = "log.txt"

        Try
            ' Usingステートメントを使用する例
            Using writer As New StreamWriter(filePath, True) ' 追記モード
                writer.WriteLine($"ログエントリ: {DateTime.Now}")
                ' ここで何らかのエラーが発生しても、writerは確実に閉じられる
                ' 例: Throw New Exception("意図的なエラー")
            End Using
            Console.WriteLine("ログエントリが書き込まれました。")

        Catch ex As Exception
            Console.WriteLine($"エラーが発生しました: {ex.Message}")
        End Try

        ' Usingステートメントを使わない場合の例 (非推奨)
        ' Dim reader As StreamReader = Nothing
        ' Try
        '     reader = New StreamReader(filePath)
        '     Console.WriteLine(reader.ReadToEnd())
        ' Catch ex As Exception
        '     Console.WriteLine($"エラー: {ex.Message}")
        ' Finally
        '     If reader IsNot Nothing Then
        '         reader.Close() ' 手動で閉じる必要がある
        '     End If
        ' End Try
    End Sub
End Module

この例では、StreamWriterUsingステートメント内で使用しています。
Usingブロック内で例外が発生した場合でも、ブロックを抜ける際にwriter.Dispose(そしてClose)が自動的に呼び出されるため、ファイルハンドルが確実に解放されます。

コメントアウトされた非推奨の例と比較すると、Usingステートメントがコードを簡潔にし、リソース管理を安全にするかがわかります。

エラーハンドリング

ファイル操作は、ファイルが見つからない、アクセス権がない、ディスクがいっぱい、などの理由でエラーが発生しやすい処理です。
そのため、適切なエラーハンドリングが非常に重要です。

Try...Catch ブロック

Try...Catch ブロックを使用して、ファイル操作中に発生する可能性のある例外を捕捉し、適切に処理します。

Module ErrorHandlingExample
    Sub Main()
        Dim nonExistentFilePath As String = "non_existent_file.txt"
        Dim readOnlyFilePath As String = "read_only.txt" ' 適切な権限を設定したファイルパスに置き換えてください

        ' --- 読み込み時のエラーハンドリング ---
        Try
            Using reader As New StreamReader(nonExistentFilePath)
                Console.WriteLine(reader.ReadToEnd())
            End Using
        Catch ex As System.IO.FileNotFoundException
            Console.WriteLine($"エラー: ファイル '{nonExistentFilePath}' が見つかりません。")
        Catch ex As System.IO.IOException
            Console.WriteLine($"エラー: ファイルの読み込み中にIOエラーが発生しました: {ex.Message}")
        Catch ex As Exception
            Console.WriteLine($"予期せぬエラーが発生しました: {ex.Message}")
        End Try

        ' --- 書き込み時のエラーハンドリング ---
        Try
            ' 存在しないディレクトリへの書き込みや、読み取り専用ファイルへの書き込みなどでエラーをシミュレート
            Using writer As New StreamWriter(readOnlyFilePath)
                writer.WriteLine("テスト書き込み")
            End Using
        Catch ex As System.UnauthorizedAccessException
            Console.WriteLine($"エラー: ファイル '{readOnlyFilePath}' へのアクセスが拒否されました。")
        Catch ex As System.IO.IOException
            Console.WriteLine($"エラー: ファイルの書き込み中にIOエラーが発生しました: {ex.Message}")
        Catch ex As Exception
            Console.WriteLine($"予期せぬエラーが発生しました: {ex.Message}")
        End Try
    End Sub
End Module

この例では、Try...Catchブロックを使って、ファイルが見つからない場合(FileNotFoundException)や、アクセス権がない場合(UnauthorizedAccessException)、その他の一般的なIOエラー(IOException)を捕捉しています。
具体的な例外を先に捕捉し、最後に一般的なExceptionを捕捉することで、より詳細なエラー処理が可能です。

まとめ

VB.NETでテキストファイルを読み書きするには、StreamReaderStreamWriterクラスを使用します。
これらのクラスは、行単位、文字単位、またはファイル全体を一度に処理する柔軟な方法を提供します。

最も重要なのは、Usingステートメントを使ってこれらのオブジェクトを適切に管理し、ファイルハンドルなどのシステムリソースが確実に解放されるようにすることです。
また、ファイル操作はエラーが発生しやすい性質を持つため、Try...Catchブロックによる適切なエラーハンドリングを常に実装するようにしましょう。
これらのポイントを押さえることで、堅牢で信頼性の高いファイル処理をVB.NETアプリケーションに組み込むことができます。

コメント