C#のDirectory.GetFilesで意図しないファイル名まで取得される?

DirectoryクラスのGetFilesメソッドは、指定したフォルダにあるファイル一覧を取得する事が出来ます。

* や ? のワイルドカードを使って目的のファイルだけを取ってくることが出来ます。

 

 

しかし、指定の拡張子をもつファイルだけを取得しようとしてもうまくいかない場合があるので注意が必要です。


余計なファイルまで取ってきてしまう例

拡張子が .xls のファイルだけを取得しようと思った場合は以下のような記述になるかと思います。

 

//拡張子が「.xls」のファイル一覧を取得したい
var fileList = Directory.GetFiles("c:\\test", "*.xls");
//結果はこのようになる事がある
c:\test\test1.xls
c:\test\test2.xls
c:\test\test3.xlsx

拡張子が「.xls」のファイルだけでなく「.xlsx」のファイルまで取ってきてしまう場合があります。

 

厄介なのは余計なファイルが含まれてしまうケースと含まれないケースが実行するPCによって異なるという事です。


なぜこのような事が起こるのか?

 

GetFilesメソッドのリファレンスを見ると以下のような記述があります。

注意

".Txt" などのでアスタリスクのワイルドカード文字を使用すると、 searchPattern * 指定した拡張機能の文字数が検索に影響します。次に例を示します。
  • 指定された拡張子の長さが完全に3文字である場合、メソッドは、指定された拡張子で始まる拡張子を持つファイルを返します。たとえば、" * .xls" は "book.xls" と "book.xlsx" の両方を返します。
  • それ以外の場合、メソッドは、指定された拡張子と完全に一致するファイルを返します。たとえば、" * ai" は "file.ai" を返しますが、"file. aif" は返しません。
疑問符のワイルドカード文字を使用すると、このメソッドは、指定されたファイル拡張子に一致するファイルだけを返します。たとえば、ディレクトリに "file1.txt" と "その他の file1.txt" という2つのファイルがある場合、"file?" という検索パターンがあります。txt "は最初のファイルだけを返し、" file.txt "の検索パターンは * 両方のファイルを返します。

注意

このメソッドでは、ファイル名の形式が8.3 で、長いファイル名の形式であるファイル名がチェックされるため、"1 .txt" のような検索パターンでは、 * * 予期しないファイル名が返されることがあります。 たとえば、"1 .txt" という検索パターンを使用する * * と、8.3 ファイル名の形式が "longfi ~1.TXT" であるため、"longfilename.txt" が返されます。

8.3形式のファイル名というのが原因となります。

MS-DOSやWindows3.1などの古いOSでは、ファイル名は「名前8文字まで拡張子3文字まで」しか使えませんでした。

その仕様と互換性を保つため、現在でも通常のファイル名(長いファイル名形式)とは別に8.3形式のファイル名を持たせる事が出来るようになっています。

 

さらに、この8.3形式のファイル名を有効にするか無効にするかは各PCの設定による事になります。


対処方法

3文字の拡張子を指定した場合はファイル名の拡張子をもう一度確認するようにしましょう。

var files = System.IO.Directory.GetFiles("c:\\test", "*.xls");
foreach (var name in files)
{
  var ext = System.IO.Path.GetExtension(name).ToLower();
  if (0 == ".xls".CompareTo(ext))
  {
     // 拡張子をチェックした後に目的の処理をしよう
     
     
  }
}