拡張子での識別(?)について への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 MMTRS  (社会人) 投稿日時 2010/8/12 14:32:48
こんにちは。MMTRSと申します。

ファイル/ディレクトリ操作に関してはあまり触ったことがないので見当違いだったら申し訳ないのですが、
My.Computer.FileSystem.GetFilesメソッドを使用して、wildcardsに拡張子を指定するというのはどうでしょうか。

(例)
Dim files As System.Collections.ObjectModel.ReadOnlyCollection(Of String)
files = My.Computer.FileSystem.GetFiles( _
        "パス", FileIO.SearchOption.SearchAllSubDirectories, "*.jpg""*.tiff")


この場合、filesは文字列型の配列ではなくコレクションとなるのでその後の処理を多少変える必要が出てくるかもしれませんが、
必要な拡張子のファイルのみ抽出できるので「配列がいっぱいになる」可能性は低くなるかと思います。

参考になれば幸いです。
投稿者 k-z  (社会人) 投稿日時 2010/8/12 11:40:04
>よねKENさん
>魔界の仮面弁士さん

早速の回答、ありがとうございます!

返事を整理して投稿したいので、帰宅後に返信します。

どうもありがとうございます!(。・ω・。)♪
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/8/11 14:01:21
ちなみに、IndexOf メソッドで大文字小文字を区別しない比較をするためには、
引数に StringComparison.OrdinalIgnoreCase を指定すれば OK です。
http://dobon.net/vb/dotnet/string/stringequals.html


> 'jpegかjpgかtifかtiffか?
今回のように、.GetFiles("パス", "*",IO.SearchOption.AllDirectories) として
全ファイル列挙する場合は問題ありませんが、拡張子指定で取得しようとする場合には、
「8文字+拡張子3文字」のショートファイル名の存在に注意が必要ですね。
(Sample.tiff ファイルのショートファイル名は、SAMPLE~1.TIF となります)


> Dim jpgCount As Integer = files(何行目か).IndexOf(".jpg")
> で、jpgCountに0より大きい数字が入った場合に処理を行っています
その手法には問題があります。

提示されたコードですと、たとえば、
 files(0) = "C:\開発資料\Microsoft.usguide\image1.jpg"
 files(1) = "C:\開発資料\Microsoft.jpguid\readme.txt"
 files(2) = "C:\開発資料\Samples\VB2010\Project1\LOGO.JPG"
のようなパスがあった場合、files(0) だけではなく、
files(1) もが jpg と誤解されてしまうことになりますし、
files(2) は jpg ファイルと認識されないことになります。
(大文字小文字の件は、既によねKENさんも指摘されていますね)

拡張子を拾う場合には、System.IO.Path.GetExtension メソッドを使ってみてください。
もしくは、IndexOf の代わりに EndsWith メソッドを使うという手もあります。


> やり方がおかしい気がしてなりません。
考え方としては間違ってはいないと思いますが、ある程度の条件が付く事に注意して下さい。

まず、GetFiles メソッド + AllDirectories 指定が使えるのは、指定したパス以下の
すべてのディレクトリに対してアクセス許可があることが確実にわかっている場合だけです。

一部のディレクトリに対してアクセス権限が不足している場合、
メソッド全体が失敗し、ディレクトリ情報は返されません。
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=9716
http://msdn.microsoft.com/ja-jp/library/bb513869.aspx

もうひとつ。AllDirectories は、指定したパス配下の全ディレクトリを走査するため、
ディレクトリ数が多い場合、それらすべてを調査するまでメソッドは戻ってきません。

そのためアプリケーションによっては、AllDirectories に頼ることなく、
ディレクトリ ツリーを自分で反復処理した方が都合が良い場合もあります。
(もちろん、それらが問題にならない場合は AllDirectories で充分です)


> 配列の中が?でいっぱいになります。
配列の中身を、どのようにして確認されていますか?

取得したパスに含まれている文字によっては、出力方法によっては
文字コードの違いから "?" などに化ける可能性がありますので
注意してください。

たとえばコンソール出力する場合には、Unicode コンソールを使わないと
Shift_JIS で表現できない文字が、"?" に化けてしまいます。同様に、
クリップボード、ファイル、ASP.NET のレスポンスなどとして
出力する場合も要注意です。

もうひとつ。その "?" となった文字が、具体的にどのような値なのか
コードポイントを調べてみて下さい。たとえば、"?" になった文字列が
files(n) に含まれているのであれば、その内容を
 For Each c As Char In files(n)
  Console.WriteLine("{0:x4} [{1}]", AscW(c), c)
 Next
として調べる事ができます。



> そうして、エラーが出ないはずの画像に対しての処理がエラーになってしまいます。
可能であれば、化けてしまうパス名も提示してもらえると、こちらでも評価しやすいです。
よねKENさんの発言に被りますが、.NET のバージョンや使用 OS についても教えて下さい。

GetFiles メソッドの動作は、.NET Framework のバージョンによって多少の差異があります。
たとえば初期のバージョンでは、フォルダ名の末尾に全角空白が含まれていた場合、
正しく処理できないという問題がありました。
投稿者 よねKEN  (社会人) 投稿日時 2010/8/10 09:52:29
> 'jpegかjpgかtifかtiffか?
> Dim jpgCount As Integer = files(何行目か).IndexOf(".jpg")

> で、jpgCountに0より大きい数字が入った場合に処理を行っています
> これ以外に良い方法ありませんか?やり方がおかしい気がしてなりません。

大文字小文字を区別しないための工夫さえしておけば、上記のようなやり方でもいいと思います。
私なら以下のようにします。

Public Function IsMatchFileExtention(ByVal fileName As String, ParamArray extentions As String()) As Boolean
    Dim lowerfileName As String = fileName.ToLower()
    For Each extention  As String in extentions
        If lowerfileName.EndsWith(extention.ToLower()) Then
            Return True
        End If
    Next
    Return False
End Function

のようなメソッドを作成すれば、以下のように判定できます。

If IsMatchFileExtention(files(何行目か), ".jpg", ".jpeg") Then
     ' jpegファイルの拡張子でした。
End If

> あと、Directory.GetFilesでデスクトップを選択すると、配列の中が?でいっぱいになります。
> そうして、エラーが出ないはずの画像に対しての処理がエラーになってしまいます。(その画像が入っているフォルダを直接選択するとエラーがでません)
> これはデスクトップを選ぶことで何かWindows特有の不具合が起きるのでしょうか?そもそも、プログラムの仕方が悪いのでしょうか?

具体的にどんなコードを書いて、検索を行った実際のパスがどうなっていて、
配列の中に入った実際の値がどうなのか?ともう少し詳しく聞かないと何とも言えません。
後、使用しているOSのバージョンなどの情報も必要だと思います。
投稿者 k-z  (社会人) 投稿日時 2010/8/10 09:23:35
おはようございます。k-zといいます!投稿は2回目になります!

早速ですが質問です!

今、選択したフォルダのなかのファイルを全部取得して、そのなかからJpegとTIFFを区別して、処理をしようとしています。

'選択したフォルダの中身を取得
Dim files() As String = System.IO.Directory.GetFiles("パス", "*",IO.SearchOption.AllDirectories)

そのあと

'jpegかjpgかtifかtiffか?
Dim jpgCount As Integer = files(何行目か).IndexOf(".jpg")

で、jpgCountに0より大きい数字が入った場合に処理を行っています

これ以外に良い方法ありませんか?やり方がおかしい気がしてなりません。

あと、Directory.GetFilesでデスクトップを選択すると、配列の中が?でいっぱいになります。
そうして、エラーが出ないはずの画像に対しての処理がエラーになってしまいます。(その画像が入っているフォルダを直接選択するとエラーがでません)これはデスクトップを選ぶことで何かWindows特有の不具合が起きるのでしょうか?そもそも、プログラムの仕方が悪いのでしょうか?

よろしくお願いします。