WSH(JavaScript)によるファイル操作を詳しく解説


WSH(JavaScript)によるファイル操作を詳しく解説

前回、Windowsのコマンドプロンプト上でJScript(マイクロソフト版JavaScript)を実行するWSHの基本的な流れを試してみました。今回は、ローカルのファイルシステムにアクセスするFileSystemObjectを使ってファイルパスの処理とファイル操作を行ってみることにします。

目次
  1. WSHでWindowsのオブジェクトを使う
  2. ファイルパスの処理
  3. ファイルとディレクトリの存在確認
  4. ファイル操作(コピー・削除)

WSHでWindowsのオブジェクトを使う

WSHでは、COM(ActiveX)などWindowsが持っている様々なオブジェクトを利用することができます。COMは、Windows上で再利用可能なオブジェクト(他のプログラムから利用できる機能をまとめたコンポーネント)を実現する仕組みです。COMオブジェクトとして作成されているオブジェクトは、各種プログラムやWSHなどから呼び出して利用することができます。

Windowsには多様な機能を実現するCOMが標準搭載されているほか、自分で独自のCOMを作成してインストールすることもできるため、WSHを使うとWSHの入出力やJavaScriptの処理能力とCOMの独自機能を組み合わせて「Windowsのシステムにアクセスするスクリプト」を作成することができるわけですね。

中でも、FileSystemObject(Scripting.FileSystemObject)は、ファイルシステムにアクセスする機能を提供するオブジェクトなので使用する機会も多くなるでしょう。

今回は、FileSystemObjectを通してWindowsのファイルシステムを扱うWSHを試してみたいと思います。

FileSystemObjectを使用するには、まずActiveXObjectコンストラクタでオブジェクトの参照を取得します。

var fso = new ActiveXObject("Scripting.FileSystemObject");

としてFileSystemObjectを作成すると、以降オブジェクトの参照を格納した変数fsoを通してFileSystemObjectの関数やプロパティにアクセスできるようになります。

ファイルパスの処理

まず、FileSystemObjectでファイルパスに関する情報を取得してみましょう。

FileSystemObjectには、パスの文字列からファイル名やディレクトリを分離したり逆に部分的なファイル名や相対パスから絶対パスを取得する機能があります。

cscriptで起動されたWSH環境では、

WScript.ScriptFullName

にスクリプトのパスが格納されていますので、手始めにこのパスを「分解」してみましょうか。

FileSystemObjectには、渡されたファイルパスのディレクトリ/ファイル名全体/拡張子なしのファイル名/拡張子を得る関数があります。これらを順次呼び出して表示してみましょう。

以下のファイルをtest.jsなど適当な名前で作成しcscriptで実行してみてください。

var fso = new ActiveXObject("Scripting.FileSystemObject");

var script_path = WScript.ScriptFullName;
var script_dir = fso.GetParentFolderName(script_path);
var script_file_name = fso.GetFileName(script_path);
var script_base_name = fso.GetBaseName(script_path);
var script_ext = fso.GetExtensionName(script_path);

WScript.Echo("WScript.ScriptFullName=" + script_path + "\n");

WScript.Echo("GetParentFolderName=" + script_dir);
WScript.Echo("GetFileName=" + script_file_name);
WScript.Echo("GetBaseName=" + script_base_name);
WScript.Echo("GetExtensionName=" + script_ext);

実行すると、jsファイルの絶対パスに続いてディレクトリ/ファイル名/ファイル名の名前部分/拡張子が順次表示されました。

image

GetParentFolderName()は、渡されたパスの親ディレクトリを得る関数なので、ファイルのパスを渡すと「ファイルが存在するディレクトリ」を取得することができます。GetFileName()は、ファイル名全体、GetBaseName()はファイル名の拡張子を除いた名前部分、GetExtensionName()は拡張子を取得する関数です。

これらの関数は実際にファイルがあるかに関係なくパスの文字列として処理するだけなので、ファイルやディレクトリとして実在しないパスを渡すことも可能です。

たとえば、架空のパスを渡す形で

WScript.Echo(fso.GetParentFolderName("x:\\aaa\\bbb\\c.txt"));

とすると、ディレクトリ部分の「x:\aaa\bbb」が返されます。

ドライブやディレクトリを含む絶対パスからディレクトリパスやファイル名の構成要素を取得できたので、次は相対パスから絶対パスを生成してみましょう。

FileSystemObjectのGetAbsolutePathName()にパスを渡すと、相対パスから絶対パスを作成することができます。たとえば、現在のカレントディレクトリがd:\testなら

fso.GetAbsolutePathName("test.txt");

とすることで

d:\test\test.txt

という文字列が得られるわけです。

相対パスには実在しないファイルを指定することもできるので、現在のディレクトリに新規作成したいファイルの名前をGetAbsolutePathName()に渡して絶対パスを作成し、それを(絶対パスを必要とする)他のプログラムに渡す、といったこともできます。

また、そうしたパスの生成にはBuildPath()を使うこともできます。

BuildPath()は、親ディレクトリとファイル・ディレクトリ名を指定するとファイル・ディレクトリの絶対パスを返す関数で、末尾の\なども自動で処理されます。

つまり

fso.BuildPath('d:\\aaa\\bbb', "ccc.txt")
fso.BuildPath('d:\\aaa\\bbb\\', "ccc.txt")

この2つは、いずれも同じ文字列(d:\aaa\bbb\ccc.txt)を返すわけです。ディレクトリ文字列の\が混在する場合には、BuildPath()を使うことで\の有無などで振り分ける手間を省くことができます。

以上、WSH(JScript)でパスの文字列を処理する方法をいくつか見てきました。

絶対パスからディレクトリを特定しそのディレクトリに対して何らかの処理を行う、拡張子を判別して処理を振り分ける、ファイル名の拡張子を変更して処理結果のファイルを作成する……パス周りの処理が必要になる場面はかなり多いと思うので、JScriptからパスの文字列を処理する流れをしっかりつかんでおきたいところですね。

これまで使用してきたパス関数では、存在しないファイルのパスでも扱うことができました。ただ、実際にWSHを使用する場面では、「ファイルの存在確認」を行う機会も多くなるかもしれません。

ファイルとディレクトリの存在確認

続いて、ファイルやディレクトリの存在確認を試してみましょう。

FileSystemObjectには、ファイルの存在確認を行うFileExists()とディレクトリの存在確認を行うFolderExists()があるので、これらを使ってみましょう。

まず、コマンドプロンプトで適当なディレクトリに移動(cd)したら、test.txtなど適当なファイルを新規作成し配置してください。

続いて以下のjsファイルを作成し、cscriptで実行してみましょう。

この例では、FileExists()の引数に相対パスで指定しているため、「現在のディレクトリ内にtest.txtがあるか」判定することになります。

var fso = new ActiveXObject("Scripting.FileSystemObject");

if (fso.FileExists("test.txt")) {
    WScript.Echo("file exists");
} else {
    WScript.Echo("file not exists");
}

ファイルが存在するのでFileExists()がtrueを返し「file exists」と表示されたはずです。

image

続いて、test.txtを削除して実行してみてください。

今度は、ファイルが存在したいためFileExists()がfalseとなり「file not exists」と表示されたと思います。

ファイルの存在確認ができたら、FileExists()をFolderExists()に置き換え、適当なディレクトリ名でディレクトリの存在確認も試してみてください。

testというディレクトリを作成してFileExists()の引数にtestという文字列を渡してみましょう。さらに、作成したtestディレクトリ内にtest.txtを新規作成してFileExists("test\test.txt")を実行するとどうなるかも、試してみましょう。

ファイル操作(コピー・削除)

最後に、コピーや削除などディレクトリやファイルの操作を試してみたいと思います。実際にファイル操作を行うことになるので、以下の例は新しく実験用のディレクトリを作成して、そのディレクトリ内でWSHスクリプトを実行するようにしてください。

まず、ファイルやディレクトリのコピーはFileSystemObjectのCopyFile()/CopyFolder()で行うことができます。

いずれも、引数にコピー元、コピー先を順に指定し、上書を禁止したいときは3つめの引数としてfalseを指定します。

実験用に適当なディレクトリを作成したら、そのディレクトリに移動して1.txtの名で何か文字列を入れたテキストファイルを作成してください。

その状態で以下のjsファイルを作成して実行してみましょう。

var fso = new ActiveXObject("Scripting.FileSystemObject");

fso.CopyFile("1.txt", "2.txt");

dirコマンドでファイルを見てみると、2.txtが作成されているのが確認できると思います。ファイルができているのを確認したら、エクスプローラーでディレクトリを開いて2.txtをテキストエディタで見て内容もコピーされていることを確認してください。

image

この状態で1.txtを変更して再度先ほどのjsファイルを実行するとどうなるか、見てみましょうか。

1.txtをテキストエディタで開いて文字列を変更し、再度jsファイルを実行してみると……2.txtの内容も1.txtの内容になっていますね。つまり「上書コピー」されたわけです。

次に、3番目の引数に「false」を指定して試してみましょう。1.txtの内容を変更、さらにjsファイルのCopyFile()呼び出しを

fso.CopyFile("1.txt", "2.txt", false);

に変更してから実行すると……今度は、「既に同名のファイルが存在しています」というエラーメッセージが出て、コピーが行われませんでした。ちゃんと上書き禁止になっているようです。

ファイルに続いてディレクトリをコピーしてみましょう。

実験ディレクトリ内にaなどの名でディレクトリを作成し、1.txtをコピーしてください。

その状態で以下のjsファイルを実行してみましょう。

var fso = new ActiveXObject("Scripting.FileSystemObject");

fso.CopyFolder("a", "b");

実行後にディレクトリ内を見てみると、bが作成されbの中には1.txtがコピーされていることが確認できると思います。

ファイル・ディレクトリの削除は、FileSystemObjectのDeleteFile()/DeleteFolder()で行うことができます。

これまでの例でいくつかファイルを作成・コピーしてきましたが、まずは適当なファイルのファイル名をDeleteFile()に渡して削除してみましょう。

削除できたことを確認したら、別のファイルに「読み取り専用」の設定を行って削除してみてください。今度は、「書き込みできません」というエラーが出て削除できないと思います。

読み取り専用のファイルを削除するには、DeleteFile()の第二引数にtrueを設定します。実際にtrueを追加して試してみましょう。

以上、FileSystemObjectによるファイル操作をざっと見てみました。JavaScriptにはかなり充実した文字列処理能力があるので、うまく活用すれば複雑な条件でパスを生成しファイル処理を行うようなシステムも手軽に実現できるようになるでしょう。

宍戸輝光
この記事を書いた人
宍戸輝光
\無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp