nodejs學習之使用nodejs實現rm/cp/mv命令

shellingfordly發表於2022-03-10

閒來無事,本著學習nodejs的心態寫點小東西,使用nodejs的api實現rm、cp和mv簡單的刪除/複製/移動檔案/資料夾。

rm刪除檔案

其實也很簡單,如果是檔案就直接用fs.unlinkSync刪除,如果是資料夾就遞迴一個個刪除。

const fs = require("fs");
const { join } = require("path");

module.exports = async function deleteFiles(path) {
  // 判斷一下路徑是否真實存在
  if (!fs.existsSync(path)) {
    console.warn(new Error("路徑不存在。"));
    return;
  }

  const file = fs.lstatSync(path);

  // 是檔案,直接刪除
  if (file.isFile()) {
    fs.unlinkSync(path);
    return;
  }

  // 是資料夾,遍歷下面的所有檔案
  if (file.isDirectory()) {
    const files = await fs.readdirSync(path);
    if (files && files.length) {
      for (const fileName of files) {
        // 因為我之前專案使用的時候不想刪除隱藏檔案,所以在此過濾了.開頭的檔案
        if (fileName.startsWith(".")) {
          continue;
        }
        const p = join(path, fileName);
        const f = fs.lstatSync(p);
        // 是檔案,直接刪除
        if (f.isFile()) {
          fs.unlinkSync(p);
        }
        // 是資料夾,遞迴呼叫 deleteFiles
        if (f.isDirectory()) {
          await deleteFiles(p);
          // 資料夾內部檔案刪除完成之後,刪除資料夾
          fs.rmdirSync(p);
        }
      }
    }
    return;
  }
};Ï

cp複製檔案

複製檔案稍微比刪除複製一點,需要判斷oldPath是檔案還是資料夾,newPath是檔案還是資料夾,再對不同的情況來生成可用的路徑。

const fs = require("fs");
const { join, dirname, basename } = require("path");

module.exports = async function copyFiles(oldPath, newPath) {
  // 判斷路徑是否存在,有一個不存在則丟擲錯誤
  if (!fs.existsSync(oldPath) || !fs.existsSync(newPath)) {
    console.warn(new Error("路徑不存在。"));
    return;
  }
  const oldFile = fs.lstatSync(oldPath);
  const newFile = fs.lstatSync(newPath);

  // 如果 oldPath 是檔案,則直接複製 oldPath
  if (oldFile.isFile()) {
    // 需要考慮 newPath 是檔案還是目錄
    // 如果是檔案路徑,則可以直接使用進行復制
    // 如果是目錄路徑,則需要拼接上 oldPath 的檔名
    if (newFile.isDirectory()) {
      newPath = join(newPath, basename(oldPath));
    }
    fs.copyFileSync(oldPath, newPath);
    return;
  }

  // 如果 oldPath 是目錄,則 newPath 應該也使目錄
  // 若 newPath 目標路徑是檔案,則預設複製到檔案的目錄下
  if (newFile.isFile()) {
    console.warn(new Error("引數2應為路徑。"));
    newPath = dirname(newPath);
  }

  if (oldFile.isDirectory()) {
    const files = await fs.readdirSync(oldPath);
    if (files && files.length) {
      // 遍歷目錄下的所有檔案,並將 fileName 拼接上目錄路徑
      files.forEach(async (fileName) => {
        const oPath = join(oldPath, fileName);
        const oFile = fs.lstatSync(oPath);
        // 如果拼接後的路徑為檔案,則直接複製
        if (oFile.isFile()) {
          // 當然,新檔案也需要拼接上 fileName
          const newFile = join(newPath, fileName);
          fs.copyFileSync(oPath, newFile);
        }
        // 如果是目錄,則遞迴呼叫 moveFiles
        if (oFile.isDirectory()) {
          const oldDir = join(oldPath, fileName);
          const newDir = join(newPath, fileName);
          // 需要判斷拼接後的 newDir 是否存在此目錄,如果不存在則建立
          if (!fs.existsSync(newDir)) {
            await fs.mkdirSync(newDir);
          }
          moveFiles(oldDir, newDir);
        }
      });
    }
    return;
  }
};

mv移動檔案

移動檔案可以偷個懶,先呼叫 copyFiles 函式複製檔案,再呼叫 deleteFiles 刪除檔案就是移動了哈哈哈哈。

const copyFiles = require("./copy");
const deleteFiles  = require("./delete");

module.exports = async function moveFiles(oldPath, newPath) {
  copyFiles(oldPath, newPath).then((res) => {
    deleteFiles(oldPath);
  });
};

使用yarn命令呼叫

當然,為了更逼真一些,可以再package.json裡面配置一下rm/mv/cp,這樣就更像了。

"scripts": {
  "rm": "node ./rm.js",
  "mv": "node ./mv.js",
  "cp": "node ./cp.js"
}

直接這樣配置肯定是不行的,我們還需要讀取一下命令時的輸入,使用node自帶的process讀取命令傳的引數

// cp.js
const copyFiles = require("./copy");
copyFiles(process.argv[2], process.argv[3]);

// mv.js
const moveFiles = require("./move");
moveFiles(process.argv[2], process.argv[3]);

// rm.js
const deleteFiles= require('./delete')
deleteFiles(process.argv[2])

最後就可以使用yarn rm/cp/mv xxx xxx的形式像模像樣的使用啦。

# 刪除檔案
yarn rm ./a.js
# 刪除目錄
yarn rm ./a

# 移動單個檔案
yarn mv ./a.js ./b.js
# 第二個引數為目錄時自動取a.js檔名
yarn mv ./a.js ./b
# 移動目錄所有檔案
yarn mv ./a ./b

# 複製檔案
yarn cp ./a/a.js ./b/b.js
# 第二個引數為目錄時自動取a.js檔名
yarn cp ./a/a.js ./b
# 複製目錄所有檔案
yarn cp ./a ./b

相關文章