Node.jsでフォルダを再帰的にコピーする:ベストプラクティスとトラブルシューティング

2024-04-15

Node.js でフォルダーを再帰的にコピーする方法

fs モジュールとコールバックを使用する

Node.js の標準モジュールである fs を使用して、フォルダーを再帰的にコピーすることができます。ただし、この方法は非同期処理のため、コールバックを使用して処理の完了を知らせる必要があります。

const fs = require('fs');

function copyFolder(source, dest, callback) {
  fs.mkdir(dest, { recursive: true }, (err) => {
    if (err) return callback(err);
    fs.readdir(source, (err, files) => {
      if (err) return callback(err);
      files.forEach((file) => {
        const srcPath = `${source}/${file}`;
        const destPath = `${dest}/${file}`;
        fs.stat(srcPath, (err, stats) => {
          if (err) return callback(err);
          if (stats.isDirectory()) {
            copyFolder(srcPath, destPath, callback);
          } else {
            fs.copyFile(srcPath, destPath, callback);
          }
        });
      });
    });
  });
}

copyFolder('source', 'dest', (err) => {
  if (err) console.error(err);
  else console.log('コピー完了');
});

fs-extra モジュールを使用する

fs-extra は、fs モジュールを拡張したサードパーティ製モジュールです。fs-extra を使用すると、copy 関数を使用してフォルダーを再帰的にコピーすることができます。この関数は Promise を返すため、非同期処理をより簡単に処理できます。

const fsExtra = require('fs-extra');

(async () => {
  try {
    await fsExtra.copy('source', 'dest');
    console.log('コピー完了');
  } catch (err) {
    console.error(err);
  }
})();

補足

  • 上記のコード例はあくまでも基本的な例です。実際の使用状況に応じて、エラー処理やオプション設定などを追加する必要があります。
  • フォルダーをコピーする前に、宛先フォルダーが存在しないことを確認する必要があります。
  • ファイルの権限や所有権もコピーされます。
  • シンボリックリンクはコピーされません。



const fs = require('fs');

function copyFolder(source, dest, callback) {
  fs.mkdir(dest, { recursive: true }, (err) => {
    if (err) return callback(err);
    fs.readdir(source, (err, files) => {
      if (err) return callback(err);
      files.forEach((file) => {
        const srcPath = `${source}/${file}`;
        const destPath = `${dest}/${file}`;
        fs.stat(srcPath, (err, stats) => {
          if (err) return callback(err);
          if (stats.isDirectory()) {
            copyFolder(srcPath, destPath, callback);
          } else {
            fs.copyFile(srcPath, destPath, callback);
          }
        });
      });
    });
  });
}

copyFolder('source', 'dest', (err) => {
  if (err) console.error(err);
  else console.log('コピー完了');
});

説明

  1. fs モジュールを require します。
  2. copyFolder 関数を作成します。この関数は、ソースフォルダーと宛先フォルダー、および処理完了時に呼び出されるコールバック関数を引数として受け取ります。
  3. fs.mkdir 関数を使用して、宛先フォルダーが存在しない場合は作成します。
  4. fs.readdir 関数を使用して、ソースフォルダー内のファイルをすべて読み取ります。
  5. 各ファイルに対して、次の処理を行います。
    • fs.stat 関数を使用して、ファイルのステータスを取得します。
    • ファイルがディレクトリの場合は、copyFolder 関数を使用して再帰的にコピーします。
    • ファイルの場合は、fs.copyFile 関数を使用してファイルをコピーします。
  6. すべての処理が完了したら、コールバック関数を呼び出します。

使い方

このコードを使用するには、以下の手順を実行します。

  1. コードを保存します。
  2. ターミナルを開き、コードのあるディレクトリに移動します。
  3. 以下のコマンドを実行します。
node index.js



Node.js でフォルダーを再帰的にコピーするその他の方法

Promise を使用する

fs モジュールの非同期処理を Promise で処理する方法もあります。

const fs = require('fs');

async function copyFolder(source, dest) {
  await fs.mkdir(dest, { recursive: true });
  const files = await fs.readdir(source);
  await Promise.all(files.map(async (file) => {
    const srcPath = `${source}/${file}`;
    const destPath = `${dest}/${file}`;
    const stats = await fs.stat(srcPath);
    if (stats.isDirectory()) {
      await copyFolder(srcPath, destPath);
    } else {
      await fs.copyFile(srcPath, destPath);
    }
  }));
}

copyFolder('source', 'dest')
  .then(() => console.log('コピー完了'))
  .catch(err => console.error(err));

ロループを使用する

再帰処理を明示的に記述するために、ループを使用する方法もあります。

const fs = require('fs');

function copyFolder(source, dest) {
  fs.mkdir(dest, { recursive: true }, (err) => {
    if (err) throw err;
    const files = fs.readdirSync(source);
    for (const file of files) {
      const srcPath = `${source}/${file}`;
      const destPath = `${dest}/${file}`;
      const stats = fs.statSync(srcPath);
      if (stats.isDirectory()) {
        copyFolder(srcPath, destPath);
      } else {
        fs.copyFileSync(srcPath, destPath);
      }
    }
  });
}

copyFolder('source', 'dest');
console.log('コピー完了');

サードパーティ製ライブラリを使用する

fs-extra 以外にも、フォルダーのコピーを容易にするサードパーティ製ライブラリがいくつかあります。

これらのライブラリは、それぞれ異なる機能や利点を提供しているため、プロジェクトのニーズに合わせて選択することができます。

選択のヒント

どの方法を選択するかは、プロジェクトの要件と開発者の好みによって異なります。

  • コードの簡潔性と読みやすさを重視する場合は、Promise を使用する方が良いでしょう。
  • 処理の制御をより細かく行いたい場合は、ループを使用する方法が適しています。
  • 既存のライブラリを利用して開発時間を短縮したい場合は、サードパーティ製ライブラリを使用することを検討しましょう。

いずれの方法を選択する場合も、エラー処理とオプション設定を適切に行うことが重要です。


javascript node.js fs


JavaScriptで特定の範囲のランダムな数値を生成する関数を作成する方法

Math. random() を使用する方法最も簡単な方法は、 Math. random() 関数を使用する方法です。Math. random() は、0から1までの擬似乱数を生成します。1から10までのランダムな数値を生成するには、Math...


初心者でも安心!JavaScriptとjQueryで疑似要素を操るチュートリアル

CSS疑似要素(::before、::after)は、要素の前後にコンテンツを追加する強力なツールです。JavaScriptやjQueryを使って、これらの要素を選択・操作することで、より複雑なデザインやインタラクションを実現できます。JavaScriptで疑似要素を選択するには、以下の2つの方法があります。...


Node.jsでrequire()モジュールを使ってJSONファイルを読み込む

最も簡単な方法は、require()モジュールを使う方法です。この方法を使う場合は、JSONファイルが同じディレクトリにあるか、パスが正しく設定されている必要があります。fsモジュールを使う方法は、より柔軟性があります。この方法を使う場合は、ファイルのエンコーディングを指定する必要があります。...


JavaScript、jQuery、React.jsでAPI呼び出しをマスター:初心者向けチュートリアル

Fetch APIは、ブラウザのネイティブAPIであり、非同期でHTTPリクエストを行うためのシンプルな方法を提供します。構文が分かりやすく、使いこなせるようになると強力なツールとなります。利点:軽量で使いやすいPromiseベースで非同期処理を扱いやすい...


【初心者向け】Node.jsでファイルシステム操作をマスター!非同期処理をAsync/Awaitで楽々実現

本記事では、Async/Awaitを用いたNode. jsにおけるファイルシステム操作について、具体的なコード例を用いて分かりやすく解説します。Async/Awaitは、Promiseと呼ばれる非同期処理を扱うための構文糖です。Promiseは、処理完了後に結果を返すオブジェクトであり、Async/Awaitを用いることで、まるで同期処理のように非同期処理を記述することができます。...