DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

DOBON.NET

ファイルをバイト型配列に読み込む、バイト型配列をファイルに書き込む

ファイルをバイト型配列に読み込む

テキストファイルを読み込んでその内容を文字列として取得する方法はこちらで紹介しました。ここでは、ファイルの内容をバイト型配列に読み込む方法を紹介します。

次の例では、FileStreamクラスのReadメソッドを使って、ファイルの内容を一度にすべて読み込んでいます。

[VB.NET]
'読み込むファイルの名前
Dim fileName As String = "C:\test.txt"
'ファイルを開く
Dim fs As New System.IO.FileStream(fileName, _
    System.IO.FileMode.Open, _
    System.IO.FileAccess.Read)
'ファイルを読み込むバイト型配列を作成する
Dim bs(fs.Length - 1) As Byte
'ファイルの内容をすべて読み込む
fs.Read(bs, 0, bs.Length)
'閉じる
fs.Close()
[C#]
//読み込むファイルの名前
string fileName = @"C:\test.txt";
//ファイルを開く
System.IO.FileStream fs = 
    new System.IO.FileStream(fileName, 
        System.IO.FileMode.Open,
        System.IO.FileAccess.Read);
//ファイルを読み込むバイト型配列を作成する
byte[] bs = new byte[fs.Length];
//ファイルの内容をすべて読み込む
fs.Read(bs, 0, bs.Length);
//閉じる
fs.Close();

バイト型配列をファイルに書き込む

次は、バイト型配列をファイルに書き込む方法です。なお、文字列をテキストファイルに書き込む方法はこちらで紹介しています。

次の例では、FileStreamクラスのWriteメソッドを使って、バイト型配列("bs")をファイルに書き込んでいます。

[VB.NET]
'ファイルに書き込むバイト型配列が"bs"であるとする
'Dim bs() As Byte

'書き込み先のファイルの名前
Dim fileName As String = "C:\test.txt"
'ファイルを開く
Dim fs As New System.IO.FileStream(fileName, _
    System.IO.FileMode.Create, _
    System.IO.FileAccess.Write)
'バイト型配列の内容をすべて書き込む
fs.Write(bs, 0, bs.Length)
'閉じる
fs.Close()
[C#]
//ファイルに書き込むバイト型配列が"bs"であるとする
//byte[] bs;

//書き込み先のファイルの名前
string fileName = @"C:\test.txt";
//ファイルを開く
System.IO.FileStream fs =
    new System.IO.FileStream(fileName,
        System.IO.FileMode.Create,
        System.IO.FileAccess.Write);
//バイト型配列の内容をすべて書き込む
fs.Write(bs, 0, bs.Length);
//閉じる
fs.Close();

補足:ここではファイル全体を一度で読み込み、書き込みを行っているため、サイズの大きいファイルではかなり重くなります。サイズの大きいファイルの場合は、少しずつ読み込み、書き込みを行うのがよいでしょう。

上記の例では、FileStreamコンストラクタの2番目のパラメータに「FileMode.Create」を指定していますが、これはファイルが存在しない時は新たに作成し、存在する時は上書きすることを意味します。

以下にFileMode構造体のメンバを表で説明します。

FileModeのメンバ 説明
Append ファイルが存在する場合は、末尾に追加する(ファイルの末尾をシーク)。存在しない場合は、新たに作成する。書き込み時にのみ使用できる。
Create ファイルが存在する場合は、上書きする。存在しない場合は、新たに作成する。
CreateNew ファイルが存在する場合は、エラーとなる。存在しない場合は、新たに作成する。
Open ファイルが存在する場合は、ファイルを開く。存在しない場合は、エラーとなる。
OpenOrCreate ファイルが存在する場合は、ファイルを開く。存在しない場合は、新たに作成する。
Truncate ファイルが存在する場合は、ファイルを開いて、サイズを0に切り捨てる(上書きする)。存在しない場合は、エラーとなる。書き込み時にのみ使用できる。

さらに上記の例では、FileStreamコンストラクタの3番目のパラメータに「FileAccess.Write」を指定していますが、これはファイルを書き込みアクセスで開くことを意味します。これを「FileAccess.ReadWrite」にすることにより、読み込みもできるようになります。FileAccessを指定しなかった場合は、FileModeがAppendならばWrite、それ以外はReadWriteとなります。

非同期でのファイルの書き込み、読み込み

上で紹介してきた方法は同期でファイルの読み込み、書き込みを行うため、処理に時間のかかる大きいサイズのファイルを扱う場合は、その間アプリケーションがフリーズしたようになります。これを防ぐ一つの方法が、非同期メソッドを使って処理を行うことです。ファイルの読み込みでは、BeginReadとEndReadメソッドを、書き込みではBeginWriteとEndWriteメソッドを使用します。

非同期メソッドを使うことにより、大きなファイルの処理は通常速くなります(場合によっては逆にパフォーマンスが著しく低下する恐れもあります)。ただし、このような非同期の方法は危険性も高く、マルチスレッドプログラミングの知識がない方にはお勧めできません。マルチスレッドプログラミングと非同期メソッドについては、こちらで説明しています。

非同期でファイルを読み込む例を以下に示します。フォームにButton1というボタンが配置されているものとします。

[VB.NET]
Private readBytes As Byte() = Nothing

'Button1のClickイベントハンドラ
Private Sub Button1_Click(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles Button1.Click
    readBytes = New Byte(1023) {}

    '読み込むファイルの名前
    Dim fileName As String = "C:\file.txt"
    'ファイルを開く
    Dim fs As New System.IO.FileStream(fileName, _
        System.IO.FileMode.Open, _
        System.IO.FileAccess.Read, _
        System.IO.FileShare.Read, _
        &H1000, _
        True)
    '非同期の読み込みを開始する
    fs.BeginRead(readBytes, 0, readBytes.Length, _
        New AsyncCallback(AddressOf ReadBytesCallback), fs)
End Sub

Private Sub ReadBytesCallback(ByVal ar As IAsyncResult)
    'FileStreamの取得
    Dim fs As System.IO.FileStream = _
        CType(ar.AsyncState, System.IO.FileStream)
    '読み込んだサイズを取得
    Dim readSize As Integer = fs.EndRead(ar)

    If readSize > 0 Then
        '読み込めたとき
        'readBytesにreadSizeだけ読み込めている
        'readBytesを使用した何らかの処理を行う
        'ここではなにもしない
        '残りの読み込みを行う
        fs.BeginRead(readBytes, 0, readBytes.Length, _
            New AsyncCallback(AddressOf ReadBytesCallback), fs)
    Else
        'すべて読み込んだときは終了
        fs.Close()
    End If
End Sub
[C#]
private byte[] readBytes = null;

//Button1のClickイベントハンドラ
private void Button1_Click(object sender, System.EventArgs e)
{
    readBytes = new byte[1024];

    //読み込むファイルの名前
    string fileName = "C:\\file.txt";
    //ファイルを開く
    System.IO.FileStream fs = 
        new System.IO.FileStream(fileName, 
            System.IO.FileMode.Open,
            System.IO.FileAccess.Read,
            System.IO.FileShare.Read,
            0x1000,
            true);
    //非同期の読み込みを開始する
    fs.BeginRead(readBytes, 0, readBytes.Length,
        new AsyncCallback(ReadBytesCallback), fs);
}

private void ReadBytesCallback(IAsyncResult ar)
{
    //FileStreamの取得
    System.IO.FileStream fs =
        (System.IO.FileStream) ar.AsyncState;
    //読み込んだサイズを取得
    int readSize = fs.EndRead(ar);

    if (readSize > 0)
    {
        //読み込めたとき
        //readBytesにreadSizeだけ読み込めている
        //readBytesを使用した何らかの処理を行う
        //ここではなにもしない

        //残りの読み込みを行う
        fs.BeginRead(readBytes, 0, readBytes.Length,
            new AsyncCallback(ReadBytesCallback), fs);
    }
    else
    {
        //すべて読み込んだときは終了
        fs.Close();
    }
}

.NET Framework 2.0以降で、ストリームを使わずに簡単に読み込む

.NET Framework 2.0からは、File.ReadAllBytesメソッドにより、ファイルの内容をすべてバイナリ配列に読み込むことができます。以下のとおり、非常に簡単です。

[VB.NET]
'読み込むファイル
Dim fileName As String = "C:\text.txt"

'fileNameの内容をByte配列にすべて読み込む
Dim bs As Byte() = System.IO.File.ReadAllBytes(fileName)
[C#]
//読み込むファイル
string fileName = "C:\\text.txt";

//fileNameの内容をByte配列にすべて読み込む
byte[] bs = System.IO.File.ReadAllBytes(fileName);

VB.NETでは、My.Computer.FileSystem.ReadAllBytesメソッドで同じことができます。さらにMy.Computer.FileSystem.WriteAllBytesメソッドを使えば、Byte配列を書き込むことができます。

  • 履歴:
  • 2006/11/20 「開いているファイルへの他のプロセスからのアクセスを制限する」、「非同期のファイルの書き込む、読み込み」の追加など。
  • 2007/1/25 ReadAllBytesメソッドに関する記述を追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。