トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

ドラッグ&ドロップされたファイルにまとめて何かする。

[カテゴリ:Windows]
[カテゴリ:WSH]

これは何?

ドラッグ&ドロップされたファイルにまとめて何かしたい。
ってときに使えるスクリプト。
WindowsXPで動作確認済。
WSHを使ってるので、他の何かをインストールしたりする必要はない。

スクリプトソース

このスクリプトにファイル又はフォルダをドラッグ&ドロップすると log.txt が作られる。

スクリプトなので、やろうと思えばファイル名を変更できたりもするが、あえてやってない。(log.txt を *.bat にリネームして実行すれば済むので)
Callbacks.prototype を書き換えればいろいろ処理追加できる。

filelist.wsf

<?xml version="1.0" encoding="Shift_JIS" standalone="yes" ?>
<package>
<job>
<?job error="True" debug="False" ?>
<script language="jscript">
/*
 * ドラッグ&ドロップされたファイルに対して何かする。
 * フォルダが指定されたとき、サブフォルダも処理する。
 */


//
// WScript.Shell.Exec() で jhead.exe を実行すると、毎回コンソールが開く。
// これを非表示にする為の細工
// http://scripting.cocolog-nifty.com/blog/2007/05/wscriptshellexe_6e22.html
//
// 副作用について。
// この細工の影響で、エラーが発生してもエラーメッセージが見えない。
// コマンドラインから「cscript //job:exec このjsファイル名」とすればよい。
//
var args = ['CScript.exe //job:exec', '"' + WScript.ScriptFullName + '"'];
for (var arg = new Enumerator(WScript.Arguments); !arg.atEnd(); arg.moveNext()) {
  args.push('"' + arg.item() + '"');
}
var shell = WScript.CreateObject('WScript.Shell');
//WScript.Echo(args.join(' '));
shell.Run(args.join(' '), 1, true);
WScript.Quit(0);
</script>
</job>

<job id="exec">
<script language="jscript">
/*
 * Exifの読み込みクラス
 */

var Exif = function(file_path) {

  this._file_path = file_path;
  this._item = [];
  this._fso = WScript.CreateObject('Scripting.FileSystemObject');

  // jhead.exe を実行した結果得ておく。
  this._jhead = '';
  if (!this._fso.FileExists(file_path)) {
    throw 'Exif: file_path(' + file_path + ') err!';
  }
  var shell = WScript.CreateObject('WScript.Shell');
  var current_dir = this._fso.GetParentFolderName(WScript.ScriptFullName);
  var exe_path = this._fso.BuildPath(current_dir, 'jhead.exe');
  var wk = '"' + exe_path + '" -v "' + file_path + '"';
//  WScript.Echo(wk);
  var jhead = shell.Exec(wk);
  var out = '';
  while (jhead.Status == 0) {
    while (!jhead.StdOut.AtEndOfStream) {
      out += jhead.StdOut.ReadAll();
    }
    WScript.Sleep(10);
  }
  out += jhead.StdOut.ReadAll();
  this._jhead = out;
}

Exif.prototype = {

  //
  // exifデータを持つか?
  //
  exist : function() {
    var key = 'exist';
    if (typeof(this._item[key]) != 'undefined') {
      return this._item[key];
    }
    var m = this._jhead.match(/^Exif header /);
    ret = m ? true : false;
    this._item[key] = ret;
    return ret;
  },

  //
  // exif の 指定項目 の値を取得
  //
  get : function(key) {
    if (typeof(this._item[key]) != 'undefined') {
      return this._item[key];
    }
    var ret = '';
    switch (key) {
      case 'File name':
        var m = this._jhead.match(/\nFile name *: ([^\n]*)\n/);
        ret = m ? m[1] : '';
        break;
      case 'File size':
        var m = this._jhead.match(/\nFile size *: (\d+)/);
        ret = m ? m[1] : '';
        break;
      case 'Date':
        var m = this._jhead.match(/\nDate\/Time *: (\d{4}:\d{2}:\d{2}) /);
        ret = m ? m[1] : '';
        break;
      case 'Time':
        var m = this._jhead.match(/\nDate\/Time *: \d{4}:\d{2}:\d{2} (\d{2}:\d{2}:\d{2})/);
        ret = m ? m[1] : '';
        break;
      case 'Resolution X':
        var m = this._jhead.match(/\nResolution *: (\d+)/);
        ret = m ? m[1] : '';
        break;
      case 'Resolution Y':
        var m = this._jhead.match(/\nResolution *: \d+ x (\d+)/);
        ret = m ? m[1] : '';
        break;
    }
    this._item[key] = ret;
    return ret;
  },

  //
  // 文字列化
  //
  toString : function() {
    var out = '';
    out += 'File name   :' + this.get('File name') + "\n";
    out += 'File size   :' + this.get('File size') + "\n";
    out += 'Date        :' + this.get('Date') + "\n";
    out += 'Time        :' + this.get('Time') + "\n";
    out += 'Resolution X:' + this.get('Resolution X') + "\n";
    out += 'Resolution Y:' + this.get('Resolution Y') + "\n";
    return out;
  }
}

/*
 * ファイル名変更の処理エンジンクラス
 */

var ChangeNameEngine = function(callback) {
  this._fso = WScript.CreateObject('Scripting.FileSystemObject');
  this._callback = callback;
  var current_dir = this._fso.GetParentFolderName(WScript.ScriptFullName);
  this._log_filepath = this._fso.BuildPath(current_dir, 'log.txt');
  this._log_stream = this._fso.CreateTextFile(this._log_filepath);
}

ChangeNameEngine.prototype = {

  log : function(msg) {
    this._log_stream.WriteLine(msg);
    WScript.Echo(msg);
  },

  run : function(target_name) {
    this._run(target_name);
    this._close();
  },

  runDandD : function() {
    for (var arg = new Enumerator(WScript.Arguments); !arg.atEnd(); arg.moveNext()) {
      this._run(arg.item());
    }
    this._close();
  },

  openLogFile : function() {
    WScript.Echo('ログファイル(' + this._log_filepath + ')を開きます。');
    var shell = WScript.CreateObject('WScript.Shell');
    shell.Run('"' + this._log_filepath + '"', 1, true);
  },

  _close : function() {
    this._log_stream.Close();
  },

  _run : function(target_name) {
    if (this._fso.FileExists(target_name)) {
      this._call(this._fso.GetFile(target_name));
    } else if (this._fso.FolderExists(target_name)) {
      var folder = this._fso.GetFolder(target_name);
      for (var files = new Enumerator(folder.Files); !files.atEnd(); files.moveNext()) {
        this._call(files.item());
      }
      for (var folders = new Enumerator(folder.SubFolders); !folders.atEnd(); folders.moveNext()) {
        this._run(folders.item().Path);
      }
    }
  },

  _call : function(file) {
    var msg = this._callback(file);
    this.log(msg);
  }
}

/*
 * Date型を文字列にして返す。
 */

function getDate2String(date) {
  return date.getFullYear()
  + "/"
  + ('0' + (date.getMonth() + 1)).slice(-2)
  + "/"
  + ('0' + date.getDate()).slice(-2)
  + " "
  + ('0' + date.getHours()).slice(-2)
  + ":"
  + ('0' + date.getMinutes()).slice(-2)
  + ":"
  + ('0' + date.getSeconds()).slice(-2);
}

/*
 * コールバック関数を集めたクラス
 */

var Callbacks = function() {}

Callbacks.prototype = {

  //----------------------------------------------------------
  'exif2filename' : function(file) {

    var description  = 
      "exif date/time => yyyymmddhhmmss-nnnnn.jpg      \n" +
      "exif date/time と ファイル名(dsc?????.jpg)より、\n" +
      "ファイル名を yyyymmddhhmmss-?????.jpg に変更    \n" ;
    if (file == null) return description;

    var m = file.Name.match(/^dsc(.....)\.jpg$/i);
    if (!m) {
      return 'rem ' + file.Path + ' 対象外(ファイル名)';
    }

    // exif date/time を取得
    var ei = new Exif(file.Path);
    var datetime = (ei.get('Date') + ei.get('Time')).replace(/:/g,'');
    if (datetime.length != 14) {
      return 'rem ' + file.Path + ' 対象外(' + datetime + ')';
    }

    var from = file.Path;
    var to   = datetime + '-' + m[1] + '.jpg';
    return 'rename "' + from + '" "' + to +'"';
  },

  //----------------------------------------------------------
  'filename2exif' : function(file) {

    var description  = 
      "yyyymmddhhmmss*.jpg => exif date/time     \n" +
      "ファイル名から exif date/time に書き込む。\n" ;
    if (file == null) return description;

    var m = file.Name.match(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).*\.jpg$/i);
    if (!m) {
      return 'rem ' + file.Path + ' 対象外(ファイル名)';
    }
    var yyyy = m[1];
    var mm   = m[2];
    var dd   = m[3];
    var hh   = m[4];
    var mi   = m[5];
    var ss   = m[6];
    var ts_option = yyyy + ':' + mm + ':'+ dd + '-'+ hh + ':'+ mi + ':'+ ss;
    if (ts_option.length != 19) {
      return 'rem ' + file.Path + ' 対象外(' + ts_option + ')';
    }

    var mkexif_option = '';
    var ei = new Exif(file.Path);
    if (ei.exist()) {
      var m_date = ei.get('Date').match(/^(\d{4}):(\d{2}):(\d{2})$/);
      var m_time = ei.get('Time').match(/^(\d{2}):(\d{2}):(\d{2})$/);
      var exif_datetime = new Date(m_date[1], m_date[2], m_date[3], m_time[1], m_time[2], m_time[3]);
      var flnm_datetime = new Date(yyyy, mm, dd, hh, mi, ss);
      var dif = ((flnm_datetime.getTime() - exif_datetime.getTime()) / 1000);
//WScript.Echo('exif:' + exif_datetime + ' flnm:' + flnm_datetime + ' dif:' + dif);
      if (dif == 0) {
        return 'rem ' + file.Path + ' 対象外(同時刻)';
      }
      if (20 > Math.abs(dif)) {
        // ファイル更新日時とexifの日時があり、そこからファイル名を作っているとき、
        // 両者に微妙なずれが生じるので、数秒のずれは同時刻と判断する。
        return 'rem ' + file.Path + ' 対象外(ほぼ同時刻) exif date/time = ' + ei.get('Date') + ' ' + ei.get('Time') + ' dif = ' + dif;
      }
    } else {
      mkexif_option = ' -mkexif';
    }

    return 'jhead' + mkexif_option + ' -ts' + ts_option + ' "' + file.Path + '"';
  },

  //----------------------------------------------------------
  'filelist' : function(file) {

    var description  = 
      "フルパスでファイル一覧を出力 \n" ;
    if (file == null) return description;

    return getDate2String(new Date(file.DateLastModified)) + "\t"
    + file.Size + "\t"
    + '"' + file.Path + '"';
  }
}

function main()
{
  var stdin = WScript.StdIn;
  var clbk = new Callbacks();

  // メニュー表示&選択
  var select_type = '';
  {
    var types = Array();
    for (var type in clbk) {
      if (select_type == '') select_type = type;
      types.push(type);
      WScript.Echo(types.length + ')' + type);
      WScript.Echo(clbk[type](null));
    }
    WScript.Echo('1-' + types.length + ' を入力してください。(default 1)');
    var input_no = parseInt(stdin.ReadLine());
    if (input_no > 0) {
      if (types.length >= input_no) {
        select_type = types[input_no - 1];
      }
    }
  }

//  WScript.Echo('完了後ログファイルを開きます。');
//  WScript.Echo('Enter を押してください。');
//  stdin.ReadLine();
  WScript.Echo('-- start');
  if (typeof(clbk[select_type]) == 'undefined') {
    WScript.Echo('err! 存在しないtype(' + select_type + ')です。');
    WScript.Echo('Enter を押してください。');
    stdin.ReadLine();
    WScript.Quit();
  }
  var cne = new ChangeNameEngine(clbk[select_type]);
  cne.runDandD();
  WScript.Echo('-- finish');
  cne.openLogFile();
}
main();
</script>
</job>

</package>

参考

以下参考にさせてもらいました。

[WScript]フォルダの中のファイルに一括でコールバック関数を適用 / 文系大学的IT系の悲哀
http://liosk.blog103.fc2.com/blog-entry-20.html

Office TANAKA - FileSystemObjectの解説(目次)
http://officetanaka.net/excel/vba/filesystemobject/index.htm

Windows Script Programming: WScript.ShellのExec()でコンソールアプリを非表示で実行する。
http://scripting.cocolog-nifty.com/blog/2007/05/wscriptshellexe_6e22.html

最終更新時間:2009年01月31日 20時56分28秒