2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WSHでファイル操作など

Last updated at Posted at 2020-12-07

前置き

長いログファイルを元に大量のCSVのデータチェックを行う必要があり、手作業ではあまりに辛い。やる気が微塵も起きない。自動化が急務である。
データを扱いやすいよう対象のCSVをDB取込などするのもありだが、何十本ものCSVを取り込むだけでも手間だ。嫌だ、働きたくないでござる。

真面目にコツコツ成果物を出せる人間は称賛されるべきだ。それに異論を述べるつもりはないし、僕も心から尊敬する。だが労働意欲のない不真面目な僕にだって、称賛されたい気持ちだけは人並みにある。ついでに言うと、コンパイルはしたくないし読み書きやすい文法でどこでも使えるやつでお願いします。

やれやれ、僕は検索した。

WSHをやってみる

WSH JScriptを使いこなそう

WSH(Windows Script Host)を用いることで、Windows環境下であればたいていデフォルトで動くスクリプトが作れるようだ。しかもVBだけでなくJScript(ほぼほぼJavascript)で書ける。もちろんコンパイル不要だ。最高だ。Write once, run anywhereの精神である。

書き方はおおむね、みんな大好きJavascriptでよい。
注意点として、最新のJavascriptと比べて多少差異がある。たとえば変数の型は全てvarで、letconstはエラーとなる。

hoge.js
var hoge = "hoge";  // これはOK
const hogege = "hogege";  // これはNG

文字列中の変数展開もNGだ。

hoge.js
`こんにちは! ${hoge} さん`

ささいな問題である。

また、Windows上で動作するので、日本語を扱うならばスクリプトはSJISで書く必要がある。極東島国のWindowsユーザにとってUTF-8は不要なエンコーディング方式であるから、やはりささいな問題である。GHQの偉い人もそう言うてはる。

UTF-8で書いた場合

hoge.js
WScript.Echo("おひゃらひゃら");
console.log
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

縺翫・繧・i縺イ繧・i

まあ化ける。

テキストファイル操作

通常のテキストファイルを操作したい場合は、ファイルオブジェクトを作成して読み書きすればよい。簡単だ。熟練のエンジニアなら目をつぶってても書けるだろう。僕は熟練ではないのでどっかからコピペしました。

1行読み込んで表示してみる

hoge.js
var fs = new ActiveXObject("Scripting.FileSystemObject");
var file = fs.OpenTextFile(filePath, 1, true, 0);
while(!file.AtEndOfStream) {
  WScript.Echo(file.ReadLine());
}
file.Close();
fs = null;

末尾に書き込んでみる

hoge.js
var fs = new ActiveXObject("Scripting.FileSystemObject");
var file = fs.OpenTextFile(filePath, 8, true, 0);
file.WriteLine("あいうえお");
file.Close();
fs = null;

CSV操作

CSVファイルをDB的にSQL検索することも可能だ。はじめは単にCSVを効率よく読み込みたいだけのつもりだったが、調べた結果予想以上に手軽であり、今回一番感動したところである。

WSHサンプル集

hoge.js
var con = new ActiveXObject("ADODB.Connection");
con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\hoge\\csvDir;Extended Properties=\"text;HDR=NO;FMT=Delimited;\";";
con.Open();
var rs = con.Execute("SELECT * FROM `hoge#csv` ORDER BY F1");
if (rs) {
  while (!rs.EOF) {
    WScript.Echo(rs.Fields("F1").Value);
    rs.MoveNext();
  }
}
rs.Close();
con.Close();

上記コードでいうと、HDR=NOでヘッダなしとして読み込んでいる。するとカラム名はF1,F2...と自動的に認識される。ファイル中にヘッダ行を含んでいる場合はデータと混じってしまうが、そのあたりは使いみちに合わせて検討して頂きたい。
一行目の値をカラム名とする場合はHDR=YESとすればよろし。F1,F2形式はできなくなるので注意。

実行

実行に際しては作成したファイルをコマンドプロンプトから呼び出してもいいのだが、堕落した民がそんなことをする道理がない。道理のないところに処理は動かぬとは孔子の言であるが、現代にも通ずる。したがって.batファイルを作れば面倒さを憂う前に実行できる。Write once, run anytimeの精神である。

64bitならこのような呼び出しをおすすめする。最後のjsファイル名だけ変えてあげればよい。

hoge.bat
C:\Windows\SysWOW64\cscript /E:jscript ./hoge.js
pause

なぜかというと、上述のCSV操作をするにあたって用いるADODBは、これでないと下記エラーを吐く。

console.log
ADODB.Connection: プロバイダーが見つかりません。正しくインストールされていない可能性があります。

CSV操作とか特殊なことしないのであれば、これでも動く。

hoge.bat
CScript /E:jscript ./hoge.js
pause

実行引数

実行引数を取りたい場合はこのあたりが参考になるかと思う。やってない。
https://daybydaypg.com/2017/12/22/post-868/
https://ooo.iiyudana.net/htm/js_chp3frame.htm

サンプル

テスト用にこういったディレクトリ構成を作成してみる。

C:\hoge\
   ├─ hoge.bat
   ├─ hoge.js
   ├─ csvDir\hoge.csv
   └─ textDir\

あとはテキストエディタでそれぞれコピペしてみてください。

注意:csvファイルのエンコードはSJISで。

hoge.csv
"ID","NAME","TEXT"
"1","AAABBBCCC","あべべのべ"
"2","BBBCCCDDD","なのなのな"
"3","CCCDDDEEE","おひょひょのひょ"
hoge.bat
C:\Windows\SysWOW64\cscript /E:jscript ./hoge.js
pause

注意:jsファイルのエンコードはSJISで。

hoge.js
// オープンモード
var FORREADING      = 1;    // 読み取り専用
var FORWRITING      = 2;    // 書き込み専用
var FORAPPENDING    = 8;    // 追加書き込み

// 開くファイルの形式
var TRISTATE_TRUE       = -1;   // Unicode
var TRISTATE_FALSE      =  0;   // ASCII
var TRISTATE_USEDEFAULT = -2;   // システムデフォルト

var CSV_DIR = "C:\\hoge\\csvDir";
var TEXT_DIR = "C:\\hoge\\textDir";

main();

function main() {
  // 2列目に「AAA」を含むデータを検索する
  checkCSV(CSV_DIR, "hoge.csv", "AAA");

  // テキストファイル内容をチェックする
  checkText(TEXT_DIR);
}

function checkCSV(dir, fileName, keyword) {
  // ファイル名の.を#に置換する
  fileName = fileName.split('.').join('#');

  var con = new ActiveXObject("ADODB.Connection");
  con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dir + ";Extended Properties=\"text;HDR=NO;FMT=Delimited;\";";
  con.Open();
  var rs = con.Execute("SELECT * FROM `" + fileName + "` WHERE F2 LIKE '%" + keyword + "%' ORDER BY F1");
  if (rs) {
    while (!rs.EOF) {
      var tmpMsg = [rs.Fields("F1").Value,
                    rs.Fields("F2").Value,
                    rs.Fields("F3").Value];

      WScript.Echo(tmpMsg);
      writeToTextFile(TEXT_DIR, "hoge.txt", tmpMsg[2]);
      rs.MoveNext();
    }
  }
  rs.Close();
  con.Close();
}

function writeToTextFile(dir, fileName, value) {
  // ファイルを追記で開く
  var fs = new ActiveXObject("Scripting.FileSystemObject");
  var file = fs.OpenTextFile(dir + "\\" + fileName, FORAPPENDING, true, TRISTATE_FALSE);
  // テキストに書き出し
  file.WriteLine(value);
  // ファイルを閉じる
  file.Close();
  fs = null;
}

function checkText(textDirPath) {
  // ファイル操作オブジェクト
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  // 対象ディレクトリの全ファイル取得
  var files = fso.GetFolder(textDirPath).Files;

  // 1ファイルずつ読込
  var e = new Enumerator(files);
  for (;!e.atEnd();e.moveNext()) {
    var file = e.item();
    // 読む
    readFromTextFile(file.Path);
  }
}

function readFromTextFile(filePath) {
  // ファイルを読み取り専用で開く
  var fs = new ActiveXObject("Scripting.FileSystemObject");
  var file = fs.OpenTextFile(filePath, FORREADING, true, TRISTATE_FALSE);

  while(!file.AtEndOfStream) {
    // 1行読み込んで表示
    WScript.Echo(file.ReadLine());
  }
  // ファイルを閉じる
  file.Close();
  fs = null;
}

実行結果

hoge.batをダブルクリックすると、コンソールにはこのように出るはずです。

console.log
1,AAABBBCCC,あべべのべ
あべべのべ

textDir/hoge.txtを開くと「あべべのべ」と書き出され、バッチを叩くたびに「あべべのべ」が増殖する。Run once, write onceの精神である。

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?