JavaScript
Bash
Node.js
promise

NodejsでBashのsplitコマンドっぽい処理を書く

はじめに

Node.jsで重たいファイルを扱う際に、bashのsplitコマンドっぽく、
ファイルを行ごとに分割したかったので作ったものを備忘録として残す。
Bashのコマンドとオプションを合わせたので、Bashっぽく使えるのがポイント。

コード

bashのsplitコマンド

split.sh
$ split [OPTION]... [FILE [PREFIX]]

オプション(一部)

  • -l, --lines=NUMBER
    • 分割するファイルの行単位
  • -d, --numeric-suffixes
    • 指定あり: [PREFIX000, PREFIX001, PREFIX002...]
    • 指定なし: [PREFIXaaa, PREFIXaab, PREFIXaac...]
  • -a, --suffix-length=N
    • 出力ファイルに付加する文字列の長さ

Nodejs版

split.js
const fs = require('fs');
const readline = require('readline');

function createAlphabetSuffix(num, length) {

    let i = num;
    let str = '';

    while (i > 0) {
        str = String.fromCharCode(97 + (i % 26)) + str;
        i = Math.floor(i / 26);
    }

    return str.padStart(length, 'a');

}

function createNumericSuffix(num, length) {
    return String(num).padStart(length, '0');
}

module.exports = function split(file, options = {}) {

    return new Promise((resolve) => {

        let {
            prefix = 'x',
            lines = 100,
            suffixLength = 3,
            numericSuffixes = false
        } = options;

        const rs = fs.createReadStream(file);
        const rl = readline.createInterface(rs);

        let index = 0;
        let ws;

        rl.on('line', (line) => {

            let i = index++;

            if (i % lines === 0) {

                ws && ws.close();

                const suffixIndex = Math.floor(i / lines);
                const suffix = numericSuffixes
                    ? createNumericSuffix(suffixIndex, suffixLength)
                    : createAlphabetSuffix(suffixIndex, suffixLength);

                ws = fs.createWriteStream(`${prefix}${suffix}`);

            }

            ws.write(line + '\n');

        });

        rl.on('close', () => {
            ws && ws.close();
            resolve();
        });

    });

};

オプション

オプション 初期値 説明
prefix x 出力するファイルのベース名
lines 100 出力するファイルの行数
suffixLength 3 出力ファイルに付与する文字列の長さ
numericSuffixes false 出力ファイルに付与する文字列を数値にするか

サンプル

useSplit.js
const split = require('./split');

(async () => {

    await split('./largeFile.txt', {
        prefix: 'smallFile',
        lines: 10,
        suffixLength: 4,
        numericSuffixes: true
    });

})();
result
$ node useSplit.js
$ ls | grep smallFile
# smallFile0000
# smallFile0001
# smallFile0002
# ...

最後に

意外に探しても見つからなかったので作ってみました。
他に良い方法があればご指摘ください。