Hey, Scripting Guy!

Hey, Scripting Guy!

TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。

Hey, Scripting Guy! アーカイブも忘れずにチェックしてください。

今日の質問 : テキスト ファイルを照会し、特定の日に発生したレコードを取得する方法はありますか


テキスト ファイルを照会し、特定の日に発生したレコードを取得する方法はありますか

Q

Scripting Guy さん、よろしくお願いします。ファイルの行ごとにある種のレコードまたはイベントを表しているテキスト ファイルが大量にあります。スクリプトを使用して特定の日に発生したレコードまたはイベントを取得する方法はありますか。

-- TW

A

TW さん、こんにちは。あのですね、"ええ、テキスト ファイルではなくデータベースを使用すべきなのは百も承知しています" と電子メールにあるとおり、テキスト ファイルを使用していることを弁解されていますね。TW さん、どうぞ私たちを信じてください。弁解する必要などまったくありませんよ。ご使用のテキスト ファイルで必要な処理が行えるのであれば、引き続きテキスト ファイルを使用してください。確かに、データベースが一番適切なツールであることもあります。その反面、テキスト ファイルについて寄せられるたくさんの質問からすると、多数のユーザーが旧式のログ ファイルがたいへん便利であると考えていることは明白です。諺にも、壊れていないものを修理するな (さわらぬ神にたたりなし) とありますよ。

実を言うと、心配する必要のないことを心配することはよくあることです。私たちのもとにはシステム管理者からよく次のような手紙が届きます。"申し分のない働きをするバッチ ファイルがありますが、バッチ ファイルにすぎません。このファイルをスクリプトに変換すべきでしょうか"。そうですね。必要ならばそうしてもよいと思います。でも、機能しているのなら (しかも申し分なく機能しているのであれば)、わざわざ変換する必要はないのではないでしょうか。Scripting Guys と同業の方であれば、本当に修正しなければならないものがたくさんあります。それなのに、修正する必要のないものを修正してまわるなんておかしいです。

おっしゃるとおり、長い哲学的な話であるばかりでなく、野球についてもまったく触れていませんね。ちょっと待ってください。これは、Hey, Scripting Guy! のコラムであるはずです。どういうわけか心理アドバイザーの Dr. Phil の領域に迷い込んでいました。

でも、Dr. Phil であれば次のようなコードをアドバイスすることは決してありません (ほとんどないでしょう)。

Const adOpenStatic = 3 
Const adLockOptimistic = 3 
Const adCmdText = &H0001 
 
Set objConnection = CreateObject("ADODB.Connection") 
Set objRecordSet = CreateObject("ADODB.Recordset") 
 
strPathtoTextFile = "C:\Scripts" 
 
objConnection.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ 
    "Data Source=" & strPathtoTextFile & ";" & _ 
        "Extended Properties=""text;HDR=YES;FMT=Delimited""" 
 
strHireDate = #3/1/2006# 
strFile = "Employees.txt" 
 
objRecordset.Open "Select * FROM " & strFile & " where HireDate = #" & strHireDate & "#", _ 
    objConnection, adOpenStatic, adLockOptimistic, adCmdText 
 
Do Until objRecordset.EOF 
    Wscript.Echo objRecordset.Fields.Item("LastName") 
    Wscript.Echo objRecordset.Fields.Item("FirstName")    
    Wscript.Echo objRecordset.Fields.Item("Department") 
    Wscript.Echo objRecordset.Fields.Item("HireDate")    
    objRecordset.MoveNext 
Loop

説明を始める前に指摘しておく必要がありますが、TW さんが使用しているのは一連のコンマ区切りの値 (CSV) ファイルで、各ファイルの最初の行がファイルのフィールドを表すヘッダー行です。たとえば、TW さんが次のようなファイルを使用しているとします (なお、例を少しわかりやすくするために、フィールドの一部を削除しました)。

LastName,FirstName,Department,HireDate 
Myer,Ken,Finance,3/1/2006 
Ackerman,Pilar,Finance,3/1/2006 
Smith,Joe,Resarch,4/1/2006

テキスト ファイルがこのような形式であることが大切なのでしょうか。大切なのではなく、この形式でなくてはならないのです。ファイルから情報を取得するデータベース技術を使用するつもりなので、そのためにはファイルがなんらかの方法で区切られている必要があります (この場合は、区切り文字としてコンマを使用)。理想としては、ご使用のファイルにもヘッダー行があるとよいでしょう。テキスト ファイルがこのようになっていれば、本題に入ることができます。

: テキスト ファイルがこのようになっていない場合はどうすればよいでしょうか。そうですね。それでも場合によっては、データベース技術を使用してファイルを照会することができる可能性があります。詳細については、MSDN コラム「Much ADO About Text Files」(英語) を参照してください。

ここでは、2 つのことに注意しなければなりません。まず、コードの各行を詳しくは説明しません。その点についてはこの MSDN コラムで既に詳しく説明したからです。次に、スクリプトのコードの一部が不可解であるからといってしりごみしないでください。これからわかりますが、コードのほとんどの部分はお決まりのパターンです。心配する必要も、コードを変更もする必要もありません。そこにあればよい単なるコードです。

このスクリプトは、まず、adOpenStatic、adLockOptimistic、adCmdText という 3 つの定数を定義しています。これらの定数は "データベース" (テキスト ファイル) クエリを構成するために使用します。定数を定義した後は、ADODB.Connection オブジェクトと ADODB.Recordset オブジェクトのインスタンスを作成します。では、次のブロックに移りましょう。

strPathtoTextFile = "C:\Scripts" 
 
objConnection.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ 
    "Data Source=" & strPathtoTextFile & ";" & _ 
        "Extended Properties=""text;HDR=YES;FMT=Delimited"""

ご覧のとおり、ここでは 2 つの処理を実行しています。まず、変数 strPathToTextFile にパスを代入します。このパスは、テキスト ファイルが置かれたフォルダを表します。C:\Scripts\Employees.txt のような実際のテキスト ファイル自体のパスではありません。単なるフォルダへのパスです。

次に、Open メソッドを呼び出し、フォルダ C:\Scripts への ADO (ActiveX Data Objects) 接続を作成します。これはこのスクリプトのお決まりのパターンを示すうってつけの例です。テキスト ファイルが正しく書式設定され、フォルダ パスを strPathToTextFile に代入済みであると仮定した場合、このコードをまったくそのまま使用することができます。変更する必要はありません。

人生がすべてこんなに単純だとどんなによいでしょうね。

接続を作成したら、2 つの変数に値を代入します。

strHireDate = #3/1/2006# 
strFile = "Employees.txt"

このスクリプトでは、2006 年 3 月 1 日に雇われた従業員全員についての情報を取得する必要があるので、変数 strHireDate にこの日付を代入します。なぜ日付を # で囲んだのでしょうか。その理由は簡単です。VBScript が算数の問題 (つまり、3 ÷ 1 ÷ 2006) ではなく、日付として値を処理するようにするためです。一方で、テキスト ファイルの名前 (Employees.txt) を strFile という変数に割り当てます。

これはどういう意味でしょうか。これでクエリを発行する準備が整ったということです。

objRecordset.Open "Select * FROM " & strFile & " where HireDate = #" & strHireDate & "#", _ 
    objConnection, adOpenStatic, adLockOptimistic, adCmdText

このクエリは実際きわめて簡単です。テキスト ファイルのフィールドの 1 つは HireDate という名前です。どうしてそんなことがわかるのでしょうか。それは、次のファイル ヘッダー行に列挙されているフィールド名の 1 つだからです。

LastName,FirstName,Department,HireDate

クエリを発行するときは、HireDate フィールドが #3/1/2006# に等しいすべてのレコード (つまり、テキスト ファイルのすべての行) を単に要求します。なお、変数 strFile (テキスト ファイルの名前を含む) をクエリのこの箇所で使用することに注意してください。ここは通常、データベース テーブル名を挿入する場所です。

"Select * FROM " & strFile & "

これが基本的な処理です。ADO のマジックで、雇用日が 3/1/2006 に等しいすべてのレコード (テキスト ファイルのすべての行) で構成されるレコードセットが返されます。そのときに、次のようにレコードセットを 1 件ずつ処理して、値をエコー バックするだけです。

Do Until objRecordset.EOF 
    Wscript.Echo objRecordset.Fields.Item("LastName") 
    Wscript.Echo objRecordset.Fields.Item("FirstName")    
    Wscript.Echo objRecordset.Fields.Item("Department") 
    Wscript.Echo objRecordset.Fields.Item("HireDate")    
    objRecordset.MoveNext 
Loop

データベースにデータを格納した場合と同じ結果が得られるだけでなく、コードもほぼ同じスクリプト コードを使用します。このスクリプトが問題なく機能すれば、TW さん、テキスト ファイルを引き続き使用することをお勧めします。おわかりのように、Scripting Guys は単にかっこわるいというだけの理由で誰か、いえ "何か" を排除するよう勧めることは決してありません (Scripting Guys がかっこよくないという理由からではありません。一応念のため付け加えておきます...)。


関連情報

Hey, Scripting Guy! - アーカイブもチェックしてください。

ページのトップへページのトップへ