File読み込み(その1)

とりあえず、よく分からんが、プロジェクトの新規作成。 GUIに出力する必要は全然無い為、「コンソールアプリケーション」を選択。

すると、Module1.vbっつーファイルが勝手に作成される。 これでは余りにもかっちょ悪いので、とりあえず、名称を変更。 Moduleって要するにVB6で言うところの「標準モジュール」なんだと思うので、 stdFileReader.vbとする。

で、とりあえず、動作確認。

Module stdFileReader
    Sub Main()
        Console.Write("TEST")
    End Sub
End Module

うむ。動く。めでたい。

で、ファイル読み込みなんだが、VB6だとFileSystemObjectを使うことになるわけだが、.NETでは System.IOネームスペースにそれっぽいものが盛りだくさんらしい。Javaっぺーね。 最初から.NET Frameworkに存在するものなのでいわゆる「参照設定」は不要。そのまま使える。

で、それをどうやって使用するかっつーと、

[プロジェクト] - [...のプロパティ] - [共通プロパティ] - [インポート]

にて別のプロジェクトをインポートすることができるので、ここに

System.IO

を追加。すると、System.IOのクラスが使用できるようになる。 と、言うか、使用する単純にネームスペースを登録できるだけであって、 ここに登録しなくても、ネームスペースを毎回フルで書けばそのまま使える。

が、今回はこの[インポート]の部分には設定しない。(しねーのかよ)
基本的にVB.NETではほとんど全ての事がテキスト(ソース)から設定できる。 インポートも例外ではなく、ソースの先頭に

Imports System.IO

とするだけで使用できる。この方がどのクラスがどれをインポートしているのかが分かりやすいし、 後で、任意のクラスだけ抜き出して使用するときにファイル単体で機能するようにしておいたほうがめんどくさくない。

と、ゆーわけでこんな感じになる。

Imports System.IO

Module stdFileReader
    Sub Main()
        Dim objFile As StreamReader = New StreamReader("C:\test\test.txt")

        Do While objFile.Peek <> -1
            Console.WriteLine(objFile.ReadLine())
        Loop

        objFile.Close()
        objFile = Nothing

        Console.ReadLine()
   End Sub
End Module

どうやら、FileSystemObjectで言うところのTextStreamStreamReaderにあたるっぽい。 しかも、直接Newできてしまう。ラクだ。 最後にReadLine()しているのは、単純に開発環境上での実行時にコンソールが閉じるのを防ぐ為。

が、プログラム書くときには対象ファイルの場所は動的に変わる。 設定ファイル等を読むときなんかは大抵実行ファイルと同じフォルダがそれより下位のフォルダになる。 と言うわけで、VB6で言うところのApp.Pathが無いかと思って調べると、

Application.StartupPath

で取れるらしい。が、Applicationオブジェクトなんて無いと言うエラーが出て取得できない。 どーやら、これはWindowのあるGUIプログラムで使用するようだ。と言うか、Applicationオブジェクトの正式名称(?)は、 System.Windows.Forms.Applicationらしい。しかも、よく分からんのだが、 このStartupPathは実行ファイルのフォルダとは意味的に微妙に異なるらしい。

で、結局どーやって取るのかと言うと、プログラムの環境に関する情報は全てSystem.Refrection以下にあるらしい。 結果から言うと、

Reflection.Assembly.GetExecutingAssembly().Location

で、取れる。SystemはデフォルトでImportされてるので省略可能。が、これはフォルダではなく、ファイル名も含んだフルパス。 FileSystemObjectだと、GetParentFolderNameなんつーメソッドがあるが、.NETの場合はまず、 FileInfoと言うクラスをファイルパスから作成し、そこから情報を得るらしい。 それらを全部一行で書いて、最初のプログラムを書き直すと、こうなる。

Imports System.IO

Module stdFileReader
    Sub Main()
        Dim strDir As String = _
            New FileInfo(Reflection.Assembly.GetExecutingAssembly().Location).DirectoryName  '実行フォルダ
        Dim objFile As StreamReader = New StreamReader(strDir & "\test.txt")

        Do While objFile.Peek <> -1
            Console.WriteLine(objFile.ReadLine())
        Loop

        objFile.Close()
        objFile = Nothing

        Console.ReadLine()
   End Sub
End Module

FileInfoクラスを作ってそのDirectoryNameを取得している。が、ここで指し示すのは、 ソースファイルのあるフォルダではない事に注意したい。VB.NETは既に完全なコンパイル言語になっているので、 実行するたびにコンパイルが行われ、ソースファイルフォルダの下のbinフォルダに実行ファイルが作成され、 それが実行される。つまり、実行フォルダはbinフォルダとなる。

で、やっと出たかと思ったら文字化けしてる・・・。調べると、StreamReaderはデフォルトではUTF-8として、 読み込むらしく、こうやるとよいらしい。

Imports System.IO

Module stdFileReader
    Sub Main()
        Dim strDir As String = _
            New FileInfo(Reflection.Assembly.GetExecutingAssembly().Location).DirectoryName  '実行フォルダ
        Dim objFile As StreamReader = New StreamReader(strDir & "\test.txt", Text.Encoding.Default)

        Do While objFile.Peek <> -1
            Console.WriteLine(objFile.ReadLine())
        Loop

        objFile.Close()
        objFile = Nothing

        Console.ReadLine()
    End Sub
End Module

Text.Encodeing.Defaultで 現在の環境のデフォルト文字コード(Shift_JIS)を取れると言うことみたいですな。

今更だが、Pathクラスというものがあるらしく、Pathの操作に関する幾つものStaticメソッドを持っているようで、 上記のstrDirの取得は

strDir = Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location)

と、してもいけるらしい。VB6の時に比べて全ての物に沢山の解法がありそう。

ちなみに、一行ずつではなく、一気に読みたい場合には ReadLine() ではなく、 ReadToEnd() があるみたい。

最終的にobjFileをWithでまとめたり、ファイルが無かったときの例外処理を入れるとこんな感じ。

Imports System.IO

Module stdFileReader
    Sub Main()
        Const FILE_NAME As String = "test.txt"  '対象ファイル

        Dim strDir As String = _
            Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location)  '実行フォルダ
        Dim objFile As StreamReader

        Try
            objFile = New StreamReader(strDir & "\" & FILE_NAME, Text.Encoding.Default)

            With objFile
                Do While .Peek <> -1
                    Console.WriteLine(.ReadLine())
                Loop

                .Close()
            End With
        Catch ex As FileNotFoundException
            Console.WriteLine("ファイルがありません")
        Catch ex As Exception
            Console.WriteLine(ex.ToString())
        End Try

        objFile = Nothing
        Console.ReadLine()
    End Sub
End Module

以下のようにして先にファイルが存在するかを確認しちゃうって手もある。

If File.Exists("c:\tmp\test.txt") Then
    '実際の処理
End If


URL B I U SIZE Black Maroon Green Olive Navy Purple Teal Gray Silver Red Lime Yellow Blue Fuchsia Aqua White