System.IO に関する FAQ


System.IO クラスに関してよく寄せられる質問とその回答です。このクラスには、File、Directory、FileInfo、DirectoryInfo、FileStream、StreamReader、StreamWriter などがあります。

  • バイトと文字の間で変換を行うには、どうすればよいですか。また、エンコード処理はどのように行われますか。
  • テキスト ファイルのエンコード方式を調べる方法はありますか。
  • IO クラスの API では、パス内の空白文字が興味深い方法で処理されていると聞きました。決まった処理パターンがありますか。また、このように処理されるのはなぜですか。
  • Version 1.0 および Version 1.1 には、なぜドライブ情報を表示する機能がないのですか。

お客様からのご質問、ご意見、ご要望などをお待ちしております。たとえば、なぜこのような設計になっているのか、ある問題を解決するための最善の方法は何か、なぜコードが思ったとおりに動作しないのかなどの疑問点がありましたら、ぜひお寄せください。また、.NET Framework の将来のリリースに対するご提案がありましたら、遠慮なく BCL チームにお寄せください。たとえば、追加してほしいクラス (そのクラスが必要になる場面に関する説明を添えていただければ助かります) や、既存クラス用に追加してほしい API などがありましたらお知らせください。

ご質問は、BCL チーム (bclpub@microsoft.com) (英語) まで電子メールでお送りください。


バイトと文字の間で変換を行うには、どうすればよいですか。また、エンコード処理はどのように行われますか。

ご存じのように、String 型値は各種のエンコード方式で表現可能な Unicode コード ポイントです。

String クラスの内部では、エンコード方式 (文字をバイトで表現する方式) として UTF-16 LE (Unicode Transformation Format、16 ビット、リトル エンディアン) が使用されます。ユーザーは、String 型値、つまり文字をバイトに変換してファイルに書き込む際、さまざまなエンコード方式を選択できます。初期のエンコード方式の 1 つである ASCII では、128 個の文字値が定義されています。その後、さまざまな ANSI コード ページが追加されました。上位 128 個のバイトに割り当てられている値は、コード ページごとに異なります。複数のバイトを使用して Unicode コード ポイントを表現するコード ページもあります。この点は、テキスト ファイルに関して多くの人々が考えることです。C 言語では 1 文字は 1 バイトで表現されます。このことは、テキスト ファイルを概念化する方法に影響を及ぼしました。ただし、これらの ANSI コード ページでは、すべての Unicode 文字を表現することはできません。また、各コンピュータにはすべての ANSI コード ページがインストールされているわけではありません。既定でインストールされる ANSI コード ページは、OS のローカライズ版ごとに異なります。したがって、たとえば、メモ帳で作成したファイルが、日本語版 OS がインストールされているコンピュータ上では読めても、米国英語版 OS がインストールされているコンピュータ上では読めない場合があります。

この問題を解決するには、UTF-16 (System.Text.UnicodeEncoding) や UTF-8 (System.Text.UTF8Encoding) などのエンコード方式を使用します。これらのエンコード方式では、1 文字が 1 バイトまたは複数バイトに変換され、また、1 バイトまたは複数バイトが 1 文字に変換されます。これにより、Unicode コード ポイントを完全に表現できます。サロゲートと呼ばれる Unicode コード ポイントも表現できます。サロゲートとは、基本多言語面 (BMP) 外にある 100 万個の追加 Unicode コード ポイントです。


テキスト ファイルのエンコード方式を調べる方法はありますか。

任意の ANSI コード ページを簡単に検出する方法はありません。ただし、テキスト内に特定のバイト列が存在する蓋然性に基づいて検出を試みる方法はあります。StreamReader クラスでは、このような検出処理は行われません。XML や HTML など一部のファイル形式では、ファイルの先頭行で文字セットを指定する方法が採用されています。このため、Web ブラウザ、データベース、XmlTextReader クラスなどは、これらのファイルを正しく読み取ることができます。ただし、多くのテキスト ファイルにはこのような情報が組み込まれていません。

Unicode 規格では、文字セットを指定する代わりに、1 つのコード ポイント (U+FEFF) を Unicode バイト オーダー マーク (BOM) として定義しています。あるテキスト ファイルの先頭の 2 バイトが FE FF または FF FE である場合 (バイト オーダーはビッグ エンディアンでもリトル エンディアンでも可)、そのファイルは UTF-16 である蓋然性が高いと言えます。また、そのテキスト ファイルのバイト オーダーも特定できます。UTF-8 では、UTF-16 のようなバイト オーダーに関する問題はありませんが、Unicode BOM を使用して、そのファイルが UTF-8 であることを示すことができます。他のエンコード方式でも、理論上は既知のプレフィックスを定義できます。このプレフィックスを表現するには、Encoding::GetPreamble() メソッドで必要なバイトを返します。

ファイル内の先頭文字を読み取る際、StreamReader クラスによってこれらのバイト列が自動検索され、エンコード方式が調整されます。このため StreamReader クラスには、Encoding ではなく CurrentEncoding という名前のプロパティがあります。この処理を無効にするには、適切なコンストラクタを呼び出し、detectEncodingFromByteOrderMarks に false を渡します。

StreamWriter クラスも Encoding::GetPreamble() メソッドを呼び出し、テキスト ファイルの先頭にこのバイト列を書き込みます。これは優れた機能です。ユーザーがテキスト ファイルのエンコード方式をはっきり特定できるからです。ただし、弊社の多くの開発者は C 言語の知識を持っているため、テキスト ファイルの先頭に UTF-8 の Unicode BOM があると混乱してしまいました。また、Unicode に対応していないエディタ (vi、以前のバージョンの Emacs など) では扱いにくいこともあります。このため、StreamWriter クラスで既定で使用される UTF8Encoding では、GetPreamble メソッドから空のバイト列が返されます。UTF-8 ファイルに Unicode BOM を書き込むには、コード内で Encoding.UTF8 を明示的に指定します。


IO クラスの API では、パス内の空白文字が興味深い方法で処理されていると聞きました。決まった処理パターンがありますか。また、このように処理されるのはなぜですか。

先頭と末尾にある空白文字、および、文字列内の無意味な空白文字は除去されます。完全修飾パスの先頭および末尾にある空白文字は無効であるからです。また、特定の位置にある空白文字も無効です。API でパスが適切に処理されるようにするため、これらの空白文字は除去されます。

除去される空白文字は次のとおりです。

  • (char) 0x9、(char) 0xA、(char) 0xB、(char) 0xC、(char) 0xD、(char) 0x20、(char) 0xA0、(char) 0x2000、(char) 0x2001、( char) 0x2002、(char) 0x2003、(char) 0x2004、(char) 0x2005、(char) 0x2006、(char) 0x2007、(char) 0x2008、(char) 0x2009、(char) 0x200A、(char) 0x200B、(char) 0x3000、(char) 0xFEFF

次のコードは、c:\Windows\System32 という適切なパスを得るために余分な空白文字を除去する例です。このコードでは、次の規則が適用されます。

  • 指定されたパスの先頭にある空白文字は、除去されます。
  • 指定されたパスの末尾にある空白文字は、除去されます。
  • コロンの後ろにあり、パス区切り文字の前にある空白文字は、除去されます。
  • ディレクトリ名またはファイル名の末尾にある空白文字は、除去されます。

注 : ディレクトリ名またはファイル名の先頭にある空白文字は、除去されません。

[C#]
using System;
using System.IO;

class Test { 
  public static void Main() {
    Console.WriteLine( Directory.Exists(@"C: \Windows\system32") );     // prints True
    Console.WriteLine( Directory.Exists(@" C:\Windows\system32") );    // prints True
    Console.WriteLine( Directory.Exists( @"C: \Windows\system32") );    // prints True
    Console.WriteLine( Directory.Exists(@"C:\ Windows\system32") );    // prints False
    Console.WriteLine( Directory.Exists(@"C:\Windows \system32") );    // prints True
    Console.WriteLine( Directory.Exists(@"C:\Windows\ system32") );    // prints False
    Console.WriteLine( Directory.Exists(@"C:\Windows\system32 ") ) ;    // prints True
  }
}

Version 1.0 および Version 1.1 には、なぜドライブ情報を表示する機能がないのですか。

Version 1.0 および Version 1.1 の開発スケジュールの制約により、これらの製品には一部の機能が組み込まれませんでした。この機能は、Visual Studio 2005 (Whidbey) に組み込まれる予定です。

ページのトップへ