連載
» 2008年02月14日 05時00分 公開

.NET TIPS:オープン中のファイルにアクセスするには?[C#、VB]

.NET Frameworkで他のプロセスがオープン中のファイルを読み書きするには、FileStreamクラスで詳細なパラメータ設定を指定する必要がある。C#およびVBでの使い方を解説する。

[岸本真二郎,デジタルアドバンテージ]
「.NET TIPS」のインデックス

連載目次

 .NET Frameworkで、テキスト・ファイルを読み書きする場合は、StreamReaderクラスやStreamWriterクラス(ともにSystem.IO名前空間)を利用するのが一般的だ。オンライン・ヘルプにあるように、テキスト・ファイルの内容を読む場合、次のように記述できる。

using System;
using System.IO;

class Test
{
  public static void Main()
  {
    try
    {
      // Create an instance of StreamReader to read from a file.
      // The using statement also closes the StreamReader.
      using (StreamReader sr = new StreamReader("TestFile.txt"))
      {
        string line;
        // Read and display lines from the file until the end of
        // the file is reached.
        while ((line = sr.ReadLine()) != null)
        {
          Console.WriteLine(line);
        }
      }
    }
    catch (Exception e)
    {
      // Let the user know what went wrong.
      Console.WriteLine("The file could not be read:");
      Console.WriteLine(e.Message);
    }
  }
}

Imports System
Imports System.IO

Class Test
  Public Shared Sub Main()
    Try
      ' Create an instance of StreamReader to read from a file.
      Dim sr As StreamReader = New StreamReader("TestFile.txt")
      Dim line As String
      ' Read and display the lines from the file until the end
      ' of the file is reached.
      Do
        line = sr.ReadLine()
        Console.WriteLine(Line)
      Loop Until line Is Nothing
      sr.Close()
    Catch E As Exception
      ' Let the user know what went wrong.
      Console.WriteLine("The file could not be read:")
      Console.WriteLine(E.Message)
    End Try
  End Sub
End Class

StreamReaderクラスを使ったファイルの読み込み(上:C#、下:VB)
StreamReaderクラスのオンライン・ヘルプから転載したコード。

 このコードでは、StreamReaderクラスのコンストラクタにファイル名を指定してStreamReaderのインスタンスを作成し、ファイルの内容を読み込んでいる。

 通常のファイルの読み込みならこれで問題はないのだが、ほかのプロセスがオープン中のファイルをStreamReaderクラスを使ってアクセスしようとすると例外が発生してファイルがオープンできないことがある。その際、

「別のプロセスで使用されているため、プロセスはファイル“TestFile.txt”にアクセスできません」


というメッセージが例外情報として返される場合があるが、これは別のプロセスがファイルをオープンしているため、自プロセスからは『無条件に』オープンできないのではなく、

「ファイル・オープン時の“パラメータ指定が条件にマッチしない”のでファイルにアクセスできません」


と解釈した方がよい。この場合、StreamReaderクラスではなくFileStreamクラス(System.IO名前空間)を使ってファイルをオープンする際に詳細なパラメータ設定を指定することでファイルをオープンできることがあるためだ。

FileStreamクラスによるファイルのオープン

 FileStreamのコンストラクタにはさまざまなパラメータの組み合わせがあり、どれを使うべきか迷ってしまうかもしれないが、ここではファイル名の指定に加えて、FileMode型、FileAccess型、FileShare型の3つのパラメータを使用するコンストラクタを使う。このコンストラクタは、次のように宣言されている

public FileStream(
  string path,
  FileMode mode,
  FileAccess access,
  FileShare share
)

Public Sub New ( _
  path As String, _
  mode As FileMode, _
  access As FileAccess, _
  share As FileShare _
)

FileStreamクラスのコンストラクタの1つ(上:C#、下:VB)

 FileModeパラメータは、ファイルを開く方法を指定するもので、既存ファイルの読み取りでオープンするなら「FileMode.Open」を指定する。次のFileAccessパラメータは、アクセスの種類を示すもので、今回は内容を読むことしかしないので「FileAccess.Read」を指定する。

 そして3番目のFileShareパラメータだが、これは対象のファイルに対する共有方法指定するもので、これには、「FileShare.None」「FileShare.Read」「FileShare.Write」「FileShare.ReadWrite」「FileShare.Delete」「FileShare.Inheritable」が指定できる。StreamReaderクラスはどうやら、ファイル・オープン時に「FileShare.Read」しか与えていないようなので、ここで「FileShare.ReadWrite」を指定すれば、すでに書き込みでオープン中のファイルをオープンすることができる。

 具体的には次のようにパラメータを指定して読み込む。

using System;
using System.IO;
using System.Text;

class Test
{
  public static void Main()
  {
    try
    {
      using (FileStream fs = new FileStream("TestFile.txt",
          FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
        using (TextReader sr = new StreamReader(fs,
            Encoding.GetEncoding("shift-jis"))) {
          String line;
          // Read and display lines from the file until the end of
          // the file is reached.
          while ((line = sr.ReadLine()) != null) {
            Console.WriteLine(line);
          }
        }
      }
    }
    catch (Exception e)
    {
      // Let the user know what went wrong.
      Console.WriteLine("The file could not be read:");
      Console.WriteLine(e.Message);
    }
  }
}

Imports System
Imports System.IO
Imports System.Text

Class Test
  Public Shared Sub Main()
    Try
      Using fs As New FileStream("tmp.vb", FileMode.Open, _
          FileAccess.Read, FileShare.ReadWrite)
        Using sr As TextReader = New StreamReader(fs, _
            Encoding.GetEncoding("shift-jis"))
          Dim line As String
          ' Read and display lines from the file until the end of
          ' the file is reached.
          Do
            line = sr.ReadLine()
            Console.WriteLine(Line)
          Loop Until line Is Nothing
        End Using
      End Using
    Catch E As Exception
      ' Let the user know what went wrong.
      Console.WriteLine("The file could not be read:")
      Console.WriteLine(E.Message)
    End Try
  End Sub
End Class

FileStreamクラスを使ったファイルの読み込み(上:C#、下:VB)

 ここではFileStreamクラスを使ってファイル・アクセスの条件をしてオープンして得られたストリーム・オブジェクトをStreamReaderのコンストラクタに渡している。エンコードを指定する必要はないのだが、実際にはShift-JISでファイルを読み込むことが多いと思う。

 FileStreamクラスのインスタンスをさらにStreamReaderクラスのコンストラクタに渡しているのは、想定しているファイルがテキスト・ファイルで、行単位の読み込みを行うことを前提にしているからだ。バイナリ・ファイルでエンコードなども特に必要がないなら、FileStreamクラスのインスタンスを直接使うが手っ取り早い。

 もちろん、ここで紹介した「FileShare.ReadWrite」のパラメータ設定だけでどんなオープン中のファイルでも読み込みが行えるわけではない点を了承していただきたい。複数のプロセスで1つのファイルを同時にオープンすることはあまり考えられないが、IISのアクセス・ログを読み込んだり、デバッグ用に出力しているログ・ファイルをトレースしたりすることもあるだろう。

 共有するファイルのアクセス設定などがあらかじめ分かっている場合は特に問題ないが、ファイルを共有する状況によってはFileStreamクラスを使って適切なパラメータを選択することでファイルがオープンできる場合がある。

カテゴリ:クラス・ライブラリ 処理対象:テキスト・ファイル
使用ライブラリ:StreamReaderクラス(System.IO名前空間)
使用ライブラリ:FileStreamクラス(System.IO名前空間)
使用ライブラリ:FileShare列挙体(System.IO名前空間)


「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。