ファイル操作

ここからいきなり高度になるかもしれません。つーか、多分なります。 とりあえず、書いてみれば動くので難しいことは動いてから考えて行きましょう。 うん、そうしよう。(納得)

スクリプトで何かしようとすると、ファイル操作が必要になってくることが 結構あります。と言うわけでとりあえず、簡単なファイル操作をやってみましょう。

File Read

基礎の基礎

とりあえず、ファイル読み込みをやってみましょう。 C:\meso.txtを開いて中身を1行ずつ読み込んで表示するにはこんな感じ。

Option Explicit
 
Dim FSO        'File System Object
Dim objFile    '読み込み対象ファイル
 
'FileSystemObject取得
Set FSO = CreateObject("Scripting.FileSystemObject")
 
'読み込みファイルオブジェクト作成
Set objFile = FSO.OpenTextFile("C:\meso.txt")
 
'全部読み込み
Do Until objFile.AtEndOfLine
    MsgBox objFile.ReadLine    '1行づつ表示
Loop
 
objFile.Close    'ファイルを閉じる
 
'終了処理
Set objFile = Nothing
Set FSO = Nothing

どうですか?前章までに出てきてないものがかなりあります。 が、なんとなーく分かりますよね?とりあえず、説明していきます。

Option Explicit

これ重要です。今まで定数は宣言する必要がありましたが、 変数は特に宣言しなくても使えていました。 この行を最初に書くとどうなるかと言うと、 変数も宣言しないとエラーが出るようになります

不便ぢゃん!!(;゚Д゚)

と、思うかもしれませんが、これを書いておいたほうが後で楽です。宣言せざるを得なくなるので、

  • 初期化処理が分かりやすくなる
  • 変数名を間違うことがなくなる

と言ったメリットがあります。最初に変数を宣言し、用途を書いておいたほうが明らかに後で見たときに分かりやすいですし、 strMesoをスクリプト中に間違ってstrNesoとやってしまってもエラーが出るのですぐに分かります。

Set FSO = CreateObject("Scripting.FileSystemObject")

実はWSHの基本機能だけでは大して何も出来ません。 WSHから利用できる沢山のオブジェクトを利用することにより 様々な作業が可能となります。 「オブジェクトって何?」って事になりますが、 超簡単に説明すると、

目的別の関数、変数、定数のかたまり

です。ちょっと誤解を受けかねない説明ですが、こんな感じで捕らえておいて、 詳しくなってきたら本質を学べばいいと思います。

この「オブジェクト」。関数、定数は静的な情報ですが、変数は動的な情報です。 プログラム内で同じ種類のオブジェクトを絶対に使わなければ問題ないのですが、 やってみるとそうも行かないのです。 同じプログラム内で「違う状況」にて同じ種類のオブジェクトを使用したいと思うと 1つの変数にそれぞれの状況に応じて違う値を設定したい場合がでてきます。 このままだとそれが出来ませんので、 オブジェクトと言うのは「設計図」のみの定義にしておいて、 必要になった場所でその設計図から何個でも「作成」出来るような仕組みになっています。 イメージで言うと、たいやきの金型が「設計図」でたいやき自体が「実体」となります。この設計図のことをオブジェクトまたはクラス,実体のことをインスタンスと呼びます。また、オブジェクトに備わっている関数のことをメソッド,変数、定数のことをプロパティ,フィールドと呼びます。

で、どうやって「作成」するのかと言うと、3通りあります。

  1. CreateObject関数
  2. Newキーワード
  3. 関数の戻り値がインスタンス

この行では最初の「CreateObject関数」を使用してます。 「オブジェクトを作成しる!」っちゅーことです。そのまんまですね。 引数には作りたいオブジェクトに応じた文字列を指定します。ここに指定できる文字列にはOSや環境によって色々なものがありますが、これは基本的には覚えるしかありません。 他の2つは出てきたら説明します。 こんな感じで作成するとインスタンスが作られますので変数にそれを設定します。インスタンスを変数に設定する場合にはSetとキーワードを使います。 これはもうルールなので「へー」と思うしかないです。

長くなってしまいましたが、まとめると、この1行は

FSOという変数に"Scripting.FileSystemObjecgt"オブジェクトのインスタンスを設定しろ

っちゅー事です。このFileSystemObjectっつーのはファイルの入出力関連の機能をまとめたオブジェクトです。これを使うと普段エクスプローラでやっているようなことがスクリプトから自動的に出来るわけです。

Set objFile = FSO.OpenTextFile("C:\meso.txt")

長くなっちゃったのでサクッと行きましょう。ここで早速FSOを使ってます。 インスタンスのメソッドやプロパティを使用するにはドット(.)で区切った後に指定します。 つまり、FSOのOpenTextFileメソッドを使っているわけです。 もう、名前そのまんまなんで分かりますね?引数に指定したテキストファイルを開いているんです。 で、この行にもSetが付いているって事は・・・、そう、このメソッドもインスタンスを返します。何のインスタンスを返すのかっつーのTextStreamオブジェクトのインスタンスを返します。これまた「何それ」って感じですが、まあ、テキストファイル用のオブジェクトみたいなもんです。メモ帳でやっているようなことが自動化できます。 この場合は、meso.txtをメモ帳で開いたみたいな感じです。

Do Until objFile.AtEndOfLine
  MsgBox objFile.ReadLine    '1行づつ表示
Loop

で、読み込みです。

Do Until (条件)
	'処理
Loop

で、条件が成立するまで処理を繰り返し実行します。 AtEndOfLineプロパティもそのまんまです。今カーソルのある位置が最終行かどうかを返します。メモ帳で開いている場合は見ればそんなのすぐ分かりますが、スクリプトでやっている場合はGUIには表示されないのでプログラムから判断します。

と、ここまで理解できましたか?ハイ、と言うわけでまたウソです。 実際には判断するのは最終行かどうかではありません。 ここ、ちょっとプログラム的な考え方なんですが、テキストファイルには1行目の前と最終行の後にそれぞれ仮想行が存在すると言うことになっています。 1行目の前がBeforeOfLineで最終行の後がEndOfLineです。こんな感じ。

BeforeOfLine
1行目
2行目
3行目
EndOfLine

でAtEndOfLineは最終行ではなくEndOfLineに達したかどうかを判断するプロパティです。EndOfLineは仮想行なので読み込むことができません。つまり、ここの行に来たらもう読むのをやめるわけです。最終行に着た時に読むのをやめちゃうと最終行が読まれずに終わっちゃいますから。

で、ほぼもう分かってると思いますがReadLineが1行読み込むメソッドです。行の文字列が返されます。正確に言うと、

一行読み込んで次の行にカーソルを移動

するメソッドです。 要するにこの工程では、

開いたファイルの内容を1行ずつ全部読み込んでいる

と、言うことです。

objFile.Close
 
Set objFile = Nothing
Set FSO = Nothing

メモ帳も開いた後は必ず閉じますよね。 と、言うことでCloseメソッドで閉じて終わりです。 その後の2行はインスタンスを開放する処理です。まあ、要するに使わなくなったインスタンスを空にするって事ですね。Nothingを指定すると変数の中身が空になります。 実はこの処理はしなくてもスクリプトが終了するとスクリプト内で使用されていたインスタンスは(基本的には)自動的に開放されるのですが、状況によっては完全に保障できるものではないですし、コーディングのマナーから言っても記述しておいたほうがいいでしょう。

こんな感じです。説明が長くなっちゃいましたねー・・・。

汎用化

で、ここまでがファイル読み込みの基本です。これだと、余り汎用的ではありませんので、テンプレートとして使うにはノムハムニダ(あんまりです)。 で、もう少し汎用的にしてみると・・・

Option Explicit
 
Dim FSO        'File System Object
Dim objFile    '読み込み対象ファイル
Dim strPath    '読み込み対象ファイルパス
 
'引数チェック
If WScript.Arguments.Count > 0 Then
    strPath = WScript.Arguments(0)
Else
    WScript.Quit
End If
 
'FileSystemObject取得
Set FSO = CreateObject("Scripting.FileSystemObject")
 
'読み込みファイルオブジェクト作成
If FSO.FileExists(strPath) Then
    Set objFile = FSO.OpenTextFile(strPath)
Else
    MsgBox "そんなファイルあるかーー!!(;゚Д゚)",vbCritical,"わかめ"
    WScript.Quit
End If
 
With objFile
 
'全部読み込み
Do Until .AtEndOfLine
    MsgBox .ReadLine    '1行づつ表示
Loop
 
.Close    'ファイルを閉じる
 
End With
 
'終了処理
Set objFile = Nothing
Set FSO = Nothing

わかめ。ハジャーン

少し長くなりました。何が変わったのかと言うと、 「スクリプト内に記述された固定のファイル名を開く」 から 「スクリプトの引数に与えられたファイルパスのファイルを開く」 になっています。 スクリプトに引数を指定する方法ですが、最も簡単なのは、

「スクリプトファイルの上に対象ファイルをドラッグアンドドロップする」

です。これで引数がスクリプトに渡されます。 じゃあ、どーやってその引数をスクリプト内で使うのかっつーと、

WScript.Arguments(0)

で取得できます。さあ、また色々出てきました。まず、WScript。コイツ突然出てきました。 大体変数宣言もしてねーぞ、見たいな感じですが、この方はエリート官僚なので今までのルールは全部無視できます。そう、事件は会議室で起きているのです。 ウソです。違います。全然違います。でも一部あってます(どっちやねん)。 コイツは後ろに"."がある事からも分かるようにオブジェクトのインスタンスです。 このWScriptオブジェクトは実行されているWSH自体に関する機能をまとめたオブジェクトです。ちょっと分かりにくいですかね?例えば、

Version プロパティ
WSHのバージョンを返す
Path プロパティ
WSH自体(wscript.exe or cscript.exe)のパスを返す
ScriptFullName プロパティ
現在実行しているスクリプトのフルパスを返す
Quit メソッド
現在実行しているスクリプトを終了する
Arguments プロパティ
現在実行されているスクリプトに与えられた引数を返す

見たいな感じです。WSH自体って言う意味がちょっと分かりましたかね? で、このオブジェクトはスクリプトが実行された瞬間にWSHの方で自動的にWScriptと言う変数名でインスタンス化されます。要するに勝手に作られちゃうんです。拒否はできません。つまり、WScriptオブジェクトの機能を使いたい場合は特に何もせずともいきなりWScriptと言う変数を使用すればいい事になります。

で、上記最後の部分で説明してしまいましたが、Argumentsは与えられた引数を返します。 引数は実は複数個与えることができるのでArgumentsはコレクションとして返されます。 今回は1つだけ与えられることを前提としていますので、素直に引数の1つ目だけをとればいい事になります。(2つ以上指定してあっても2つ目以降は無視) で、1つ目を取るにはArguments(0)とします。コレクション内のアイテムのインデックスは0から始まります。3つあればそれぞれ、0つ目、1つ目、2つ目となる訳です。

上記を踏まえたうえで、もう一度スクリプトを見てみると、

If WScript.Arguments.Count > 0 Then
    strPath = WScript.Arguments(0)
Else
    WScript.Quit
End If

この部分が、引数の処理をしていることが分かりますよね。引数の数を確認して1つ以上であればその引数を変数に格納。引数が無ければスクリプト自体を終了。と言うわけです。

はい、引数が取れたところで次。

If FSO.FileExists(strPath) Then
    Set objFile = FSO.OpenTextFile(strPath)
Else
    MsgBox "そんなファイルあるかーー!!(;゚Д゚)",vbCritical,"わかめ"
    WScript.Quit
End If

引数が渡されたからといってそれがファイルパスである保障はありません。 ええ、ありませんとも。なので確かめないといかんわけです。

FileExistsはFileSystemObjectに実装されている 「指定したファイルがあるかどうか」 を返す関数です。フォルダ版のFolderExistsと言うのもあります。

で、ファイルがあれば開くし、開かなかったらフーミンに突っ込まれる訳です。 引数に「モッチャン.txt」とかを渡してみると突っ込まれる雰囲気が伝わりやすいかもしれません。(実感する必要全く無し)

汎用化その2

今までのは、引数に渡された任意のファイルを読み込む処理ですが、もう1つのパターンとしてよくあるのが、

スクリプトと同じフォルダの指定されたファイルを必ず読み込む

と、言うパターンです。この場合はファイル名は固定で決まっていますが、フォルダはスクリプトと一緒に動くので固定的に記述することはできません。 で、どーするかと言うと、こんな感じ。

Option Explicit
 
Const FILE_NAME = "meso.txt"
 
Dim FSO        'File System Object
Dim objFile    '読み込み対象ファイル
Dim strPath    '読み込み対象ファイルパス
 
'FileSystemObject取得
Set FSO = CreateObject("Scripting.FileSystemObject")
 
'読み込みファイルオブジェクト作成
strPath = FSO.BuildPath( _
        FSO.GetParentFolderName(WScript.ScriptFullName), _
        FILE_NAME)
 
If FSO.FileExists(strPath) Then
''以下同様
ScriptFullName
スクリプトのフルパスを取得
GetParentFolderName
指定したパスの親フォルダのパスを取得
BuildPath
フォルダ名、ファイル名を指定してフルパスを構築

と、言う具合で、全くメソッド名そのまんまって感じですね。 「BuildPathなんか使わなくても別に"\"で繋げるだけでいいじゃない?」 と、思うかもしれませんが、実はファイルがドライブルートにある場合など、 色々と面倒な場合があるので、BuildPathで構築したほうが確実です。

あ、後、BuildPathメソッドは引数2つで1行で書く必要があるのですが、 1行がながーくなっちゃうので、折り返してあります。 プログラムを途中で折り返すには行の最後に" _"と入れます。 すると、「次の行に続きます」っつー意味になって途中で改行してもエラーになりません。 うまく使うと見やすくなるので長くなりそうなら積極的に使っていきましょう。

と、言うわけでFileReadだけでこんなに長くなってしまいました。。。 とりあえず、この章はここまでと言うことでFileWrite等は次の章と言うことで。

この記事は訳に立ちましたか?

選択肢 投票
はい 51  
いいえ 17  

このページ、長くなりすぎちゃってて色々問題あると思うので、指摘があれば是非。


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