あるディレクトリの中にあるファイルたちの名前をまとめて変更したいなぁ、というときがあり、node.jsでやってみました。
要件
- node.js がインストールされている
- 特定のフォルダ内のファイルを一括リネームしたい
- 対象のファイルを種類(拡張子)で抽出したい(フィルタリングしたい)
例
- ディレクトリ「textBox」内にある「●●●.txt」ファイルをリネームします(他の拡張子は無視)
- リネームの内容:ファイル名の先頭にディレクトリ名を追加します(「ディレクトリ名_ファイル名」にする)
- 実行するjsファイル名は「changeName.js」にしています(任意のものでOK)
手順
1)jsファイルの作成
const fs = require("fs");
const path = require("path");
const dir = "./textBox"; // ← 変更してね
const addHead = "textBox_"; // ← 変更してね
const fileNameList = fs.readdirSync(dir);
const targetFileNames = fileNameList.filter(RegExp.prototype.test, /.*\.txt$/); // ← 変更してね
// console.log(targetFileNames);
targetFileNames.forEach(fileName => {
// console.log(fileName)
const filePath = {};
const newName = addHead + fileName;
filePath.before = path.join(dir, fileName);
filePath.after = path.join(dir, newName);
// console.log(filePath);
fs.rename(filePath.before, filePath.after, err => {
if (err) throw err;
console.log(filePath.before + "-->" + filePath.after);
});
});
-
const dir = "./textBox"
にはchangeName.js
のあるカレントディレクトリからのパスを入力 -
const addHead = "textBox_";
にはファイル名の先頭に付与する文字列を入力 -
const targetFileNames = fileNameList.filter(RegExp.prototype.test, /.*\.txt$/);
の後半部の.txt
で抽出したいファイルの拡張子を指定
2)jsファイルの実行
$ node changeName.js
以上です。
解説
const fs = require("fs"); // nodeのfsモジュール読み込み
const path = require("path"); // nodeのpathモジュール読み込み
const dir = "./textBox"; // 対象のディレクトリを指定
const addHead = "textBox_"; // ファイル名に付与したい文字列を入力
const fileNameList = fs.readdirSync(dir); // 対象ディレクトリからファイル名一覧を取得
console.log(fileNameList); // [ 'textBox_aaa.txt', 'textBox_bbb.txt', 'textBox_ccc.txt', 'xxx.jpg' ]
const targetFileNames = fileNameList.filter(RegExp.prototype.test, /.*\.txt$/); // ファイル名一覧から、拡張子で抽出
console.log(targetFileNames); // [ 'textBox_aaa.txt', 'textBox_bbb.txt', 'textBox_ccc.txt' ]
/* 拡張子で抽出したファイル名一覧「targetFileNames」を forEach で回す */
targetFileNames.forEach(fileName => {
console.log(fileName); // textBox_aaa.txt
const filePath = {}; // ファイル名の前後を入れる箱(連想配列)
const newName = addHead + fileName; // 元のファイル名の先頭に、文字列「addHead」を加える
filePath.before = path.join(dir, fileName); // 変更前のフルパス(ディレクトリパス+ファイル名)を箱に入れる
filePath.after = path.join(dir, newName); // 変更後のフルパスを箱に入れる
console.log(filePath); // { before: 'textBox/aaa.txt', after: 'textBox/textBox_aaa.txt' }
/* リネーム処理 */
fs.rename(filePath.before, filePath.after, err => {
if (err) throw err;
console.log(filePath.before + "-->" + filePath.after); // textBox/aaa.txt-->textBox/textBox_aaa.txt
});
/* END リネーム処理 */
});
/* END forEach */
require
本件は、node.jsの組み込みモジュール(標準モジュール)だけで実施可能です。
公式ドキュメント → File System Path
const fs = require("fs"); // nodeのfsモジュール読み込み
const path = require("path"); // nodeのpathモジュール読み込み
fs.readdirSync(path)
指定フォルダ(path)内のファイル・サブフォルダ名を取得します(詳細)。
フィルタリングする前なので「xxx.jpg」も含まれています。
const fileNameList = fs.readdirSync(dir); // 対象ディレクトリからファイル名一覧を取得
console.log(fileNameList); // [ 'textBox_aaa.txt', 'textBox_bbb.txt', 'textBox_ccc.txt', 'xxx.jpg' ]
Array.filter()
filter() メソッドは、引数として与えられたテスト関数を各配列要素に対して実行し、それに合格したすべての配列要素からなる新しい配列を生成します。(詳細)
ようは、「●●●.txt」だけを抽出するフィルタとして使っています。
もしフィルタが不要でしたら .filter(RegExp.prototype.test, /.*\.txt$/)
を除去すればOKです。
(もしくは forEach()
にはフィルタ前の fileNameList
を渡すようにする)
const targetFileNames = fileNameList.filter(RegExp.prototype.test, /.*\.txt$/); // ファイル名一覧から、拡張子で抽出
console.log(targetFileNames); // [ 'textBox_aaa.txt', 'textBox_bbb.txt', 'textBox_ccc.txt' ]
Array.forEach()
forEach() メソッドは与えられた関数を、配列の各要素に対して一度ずつ実行します。(詳細)
拡張子で抽出したファイル名一覧「targetFileNames」からファイル名を1つずつ取り出して、リネームの処理を実行していきます。
targetFileNames.forEach(fileName => {
console.log(fileName); // textBox_aaa.txt
// 〜省略〜
});
連想配列にリネーム前後のファイル名を入れる
const filePath = {};
const newName = addHead + fileName;
filePath.before = path.join(dir, fileName);
filePath.after = path.join(dir, newName);
console.log(filePath); // { before: 'textBox/aaa.txt', after: 'textBox/textBox_textBox_aaa.txt' }
filePath
という連想配列の箱を用意して、その中にリネーム前とリネーム後のファイル名を入れています。
リネームするときはフルパス(ディレクトリパス+ファイル名)が必要なので、 path.join
でフルパスにしています(詳細)。
fs.rename(oldPath, newPath, callback)
リネーム処理をする部分です。第一引数に変更前のファイルのフルパス、第二引数には変更後のファイルのフルパスを入れます(詳細)。
fs.rename(filePath.before, filePath.after, err => {
if (err) throw err;
console.log(filePath.before + "-->" + filePath.after); // textBox/aaa.txt-->textBox/textBox_aaa.txt
});
あとがき
【注意!】 本件を試す際は、どうかリネーム前にフォルダ(ファイル)のコピーを作成ください。リネーム後に戻すのは大変ですよ!
本件はファイル名の先頭に文字を足すだけでしたが、文字列を検出して置換したり、連番を振ったり...処理を足して色々と応用できると思います。
お役に立てば幸いです。
リスペクトな記事
本件のために参照させていただきました記事です。