フォルダ内のファイルを、ファイル作成日で昇順にソートして、ファイル名に連番を付けるプログラムを作ります。
image01.jpg、image02.jpg、image03.jpg、、、みたいにします。
データを消して飛び飛びになった番号を振り直したい時に使えます。
元のファイル名はバラバラでもかまわないので、ファイル名を統一したい時にも使えます。
ファイル名を変更する前に、変更内容を表示して、実行するか確認します。コマンドライン(ターミナル)で1度Yes/Noを聞くだけですが、一応対話型の処理です。
今回行う処理は、全て標準モジュールだけで作成しています。
使用環境
- Mac OS X El Capitan Version 10.11.6
- Node.js Version 7.2.1
- Visual Studio Code Version 1.8.0
対話型処理
対話型処理とは、実行中にコマンドライン(ターミナル)でユーザーに入力を求めて、入力値によって実行する内容を変更する処理です。
標準モジュールのReadline APIを使用します。
対話型処理は、下記のコードのように記述します。
ちなみにプロンプトとは、ユーザーの入力待ち状態を示す記号です。デフォルトは"> "です。『rli.setPrompt('> ');』で途中で変更することも出来ます。
var rl = require('readline'); // Readline(Node API):読み込み可能なストリームから1行ずつデータを読み込む // コマンドライン(ターミナル)の入出力の設定 var rli = rl.createInterface({ // readline.Interfaceの設定 input: process.stdin, // 読み込み可能なストリームに標準入力を設定 output: process.stdout, // 書き込み可能なストリームに標準出力を設定 prompt: 'y/n?: ' // プロンプトを設定 }); rli.prompt(); // プロンプトを表示 // 'line'イベント // コマンドライン(ターミナル)で『return』が押された時に発生 // 引数のlineに入力された文字が入る rli.on('line', function(line){ switch(line.trim().toLowerCase()) { // 空白文字を除去し、小文字に変換 case 'y': // (ここに'y'が入力された時の処理を書く) rli.close(); // 対話終了 break; case 'n': // (ここに'n'が入力された時の処理を書く) rli.close(); // 対話終了 break; default: // (ここに上記以外が入力された時の処理を書く) rli.prompt(); // 再度プロンプトを表示 break; } }); // 'close'イベント(下記の場合に発生) // rl.close()が呼び出された時 // コマンドライン(ターミナル)で『control + c』が押された時 // コマンドライン(ターミナル)で『control + d』が押された時 rli.on('close', function(){ // (ここに終了時の処理を書く) process.exit(0); // プログラムを終了 });
作成したファイル名連番付けプログラム
指定フォルダ内の複数のファイルを、作成日で昇順にソートして、ファイル名に連番を付けます。
拡張子は、元ファイルのまま変更しません。
注意!:思わぬ動作をした時に、複数のファイル名を元に戻すのは大変なので、使用する前に、オリジナルはコピーして残しておいて下さい。
var fs = require('fs'); // File System(Node API):ファイル操作 var path = require('path'); // Path(Node API):パスの文字列操作 var rl = require('readline'); // Readline(Node API):読み込み可能なストリームから1行ずつデータを読み込む var dirTarget = '/Users/ユーザ名/Desktop/Images'; // 処理対象のフォルダ // コマンドライン(ターミナル)の入出力の設定 var rli = rl.createInterface({ // readline.Interfaceの設定 input: process.stdin, // 読み込み可能なストリームに標準入力を設定 output: process.stdout, // 書き込み可能なストリームに標準出力を設定 prompt: 'y/n?: ' // プロンプトを設定 }); var files = fs.readdirSync(dirTarget); // 指定フォルダ内のファイル、サブフォルダのリストを取得 var arFileData = []; // ファイル情報保持用の配列 files.forEach(function(file){ var fullPath = path.join(dirTarget, file); // フルパスを取得 var stats = fs.statSync(fullPath); // ファイル情報の取得 var fileData = {}; fileData.name = file; // ファイル名 fileData.fullPath = fullPath; // ファイルのフルパス fileData.birthtime = stats.birthtime; // ファイル作成日 // ファイル作成日を表示用に成形(YYYY/MM/DD-hh:mm:ss) fileData.birthtimeFormat = stats.birthtime.getFullYear() // 年 + '/' + ('0' + (stats.birthtime.getMonth() + 1)).slice(-2) // 月 + '/' + ('0' + stats.birthtime.getDate()).slice(-2) // 日 + '-' + ('0' + stats.birthtime.getHours()).slice(-2) // 時 + ':' + ('0' + stats.birthtime.getMinutes()).slice(-2) // 分 + ':' + ('0' + stats.birthtime.getSeconds()).slice(-2); // 秒 arFileData.push(fileData); // 配列に追加 }); // ファイル作成日で昇順にソート arFileData.sort(function(a, b){ if(a.birthtime < b.birthtime) return -1; // -1を返す=a→bの順にする if(a.birthtime > b.birthtime) return 1; // 1を返す=b→aの順にする return 0; // 0を返す=入れ替えなし }); // 新しいファイル名を作成 var count = 1; // 最初の番号 arFileData.forEach(function(fileData){ var ext = path.extname(fileData.name).toLowerCase(); // 拡張子を取得(小文字にする) var newName = 'image' + ('0' + count ++).slice(-2) + ext; // 新しいファイル名、連番は2桁 console.log(fileData.birthtimeFormat + ' ' + fileData.name + '==>' + newName); // ファイル名を表示 fileData.newFullPath = path.join(dirTarget, newName); // 新しいファイル名のフルパスを保持 fileData.tempFullPath = path.join(dirTarget, 'temp_' + fileData.name); // 一時退避用の名前 }); rli.prompt(); // プロンプトを表示 // 'line'イベント // コマンドライン(ターミナル)で『return』が押された時に発生 // 引数のlineに入力された文字が入る rli.on('line', function(line){ switch(line.trim().toLowerCase()) { // 空白文字を除去し、小文字に変換 case 'y': // 一度別名を付けて退避 arFileData.forEach(function(fileData){ fs.renameSync( // ファイル名を変更 fileData.fullPath, // 元ファイル名(フルパス) fileData.tenpFullPath // 一時退避用の名前(フルパス) ); }); // 新しい名前に変更 arFileData.forEach(function(fileData){ fs.renameSync( // ファイル名を変更 fileData.tenpFullPath, // 一時退避用の名前(フルパス) fileData.newFullPath // 新しい名前(フルパス) ); }); console.log('complated!'); // 完了を表示 rli.close(); // 対話終了 break; case 'n': console.log('canceled!'); // キャンセルを表示 rli.close(); // 対話終了 break; default: rli.prompt(); // 再度プロンプトを表示 break; } }); // 'close'イベント(下記の場合に発生) // rl.close()が呼び出された時 // コマンドライン(ターミナル)で『control + c』が押された時 // コマンドライン(ターミナル)で『control + d』が押された時 rli.on('close', function(){ console.log('exit!'); // 完了を表示 process.exit(0); // プログラムを終了 });
使い方
使い方は、下記の通りです。
- 連番を付けるファイルを1つのフォルダに配置する
- (元に戻せるようにコピーしてオリジナルを取っておく)
- 『var dirTarget = '/Users/ユーザ名/Desktop/Images';』を1のフォルダのパスに書き換える
- プログラムを実行
<実行後にFinder上で一部のファイルが表示されない場合>
DockのFinderアイコンをOptionキーを押しながら右クリックし、『再度開く』をクリックしてFinderを再起動します。
あとがき
最初はファイル名を変更する部分だけ作りましたが、ファイル名がどう変わるか見比べるのが面倒でした。
調べたところ、Node.jsで対話型処理が作れることが分かったので取り入れてみました。
ファイル名に連番付けするソフトは探せばあると思いますが、自分で作ると色々とカスタマイズ出来るのでやっぱり便利です。