node實現檔案屬性批量修改(時間屬性)

磨蹭先生發表於2020-06-17

前言

在預設情況下,一個檔案的建立時間修改時間是系統自己設定的,我們不能修改該的。但我們有時為了某種特殊需要,為了不讓別人一眼看出檔案已經給修改了,我們又需要修改檔案的建立時間修改時間。那麼如何修改資料夾時間,如何修改檔案的建立時間,如何批量修改檔案的建立時間修改時間訪問時間呢?彆著急,接下來就帶你自己修改他們。所以,閒話不多說啦,開始寫我們的程式碼啦~~

ps:小工具推薦NewFileTime,以上簡述摘抄於NewFileTime

簡單的搭建一下

  • 新建一個 files 目錄

  • 初始化一個node專案工程

    npm init -y
    

看到這裡你會發現,其實我沒有安裝依賴,是因為原生的庫有這個自帶的功能嗎?說是也行,說不是也行。原生的utimes目前支援修改檔案的修改時間訪問時間,不支援修改檔案的建立時間,所以我們需要藉助一個第三方庫來修改。

為什麼不直接安裝這個第三方庫呢?

因為這個庫有些許特殊,分兩種情況,一個是低版本Node可以直接安裝,在我本機的Node13上執行則會失敗。具體原因嘛,可以看看下方的連結

ps: 原因 + 解決方案

所以,在低版本的Node我們可以直接npm install @ronomon/utimes,而在版本相對較高的則需要npm i https://github.com/Jule-/utimes.git#napi-migration

這裡也提一嘴,如果@ronomon/utimes安裝失敗的話,是因為這些原生Node擴充是需要編譯的,所以我們可能需要安裝windows-build-tools,即以管理員身份啟動PowerShell並執行:

npm install --global windows-build-tools

安裝完依賴之後就可以正式寫我們的程式碼啦,其實這個程式碼相對簡單,就是直接呼叫它的api就好了。

簡單的使用一下

  • 新建一個test-files資料夾

  • test-files資料夾新建1.txt檔案供我們測試

    1.txt檔案

  • 編寫如下程式碼:

    // 匯入 utimes
    const { utimes } = require("@ronomon/utimes");
    utimes(
      "./test-files/1.txt",
      // 建立時間
      +new Date("2010/01/01"),
      // 修改時間
      +new Date("2010/01/02"),
      // 訪問時間
      +new Date("2010/01/03"),
      (err) => {
        //  修改成功的回撥
        console.log(`success`);
      }
    );
    
  • 執行程式碼,node app.js,是都發現日期發生了改變呢?

    1.txt檔案

看到這裡你以為是不是寫完了,其實也差不多了 ?,不過我當然不會讓你收穫這麼少的,至少我們可以看看我們這個最最最簡單的例子的缺點,比如程式碼沒有Promise化,那麼我們就封裝一下utimes

/**
 *
 * @param {String} path => 路徑
 * @param {Number} btime => 建立時間,不傳即不修改
 * @param {Number} mtime => 修改時間,不傳即不修改
 * @param {Number} atime => 訪問時間,不傳即不修改
 */
const utimesPromise = (path, btime, mtime, atime) => {
  return new Promise((resolve, reject) => {
    utimes(path, btime, mtime, atime, (err) => (err ? reject(err) : resolve()));
  });
};

當然- -,因為我們使用的是Node,所以我們不需要常規的用new Promise封裝,可以直接使用內建的util這個工具中的promisify方法封裝即可

util.promisify 是在 node.js 8.x 版本中新增的一個工具,用於將老式的 Error first callback 轉換為 Promise 物件,讓老專案改造變得更為輕鬆。在官方推出這個工具之前,民間已經有很多類似的工具了,比如 es6-promisifythenifybluebird.promisify。以及很多其他優秀的工具,都是實現了這樣的功能,幫助我們在處理老專案的時候,不必費神將各種程式碼使用 Promise 再重新實現一遍。

所以,我們的封裝又變得更加簡單了,程式碼如下:

const { promisify } = require("util");
const utimesPromise = promisify(utimes);

之前的程式碼就可以改寫成之前我們那樣的自執行Async Function了,程式碼如下:

// ...
(async () => {
  await utimesPromise(
    "./test-files/1.txt",
    // 建立事件
    +new Date("2010/01/01"),
    // 修改時間
    +new Date("2010/01/02"),
    // 訪問時間
    +new Date("2010/01/03")
  );
})();

寫到這裡,你會發現其實我們根本沒有做批量修改,是因為有了之前的經驗,我們可以直接通過glob這個工具獲取所有的路徑,根本不要我們操心,寫起來也十分簡單,所以我打算最後再來寫

  • 安裝glob

    npm i glob -S
    
  • 多建幾個檔案用於測試我們的程式碼

    建立檔案

    得出下面列表:

    建立檔案

  • 修改我們的程式碼:

    const { utimes } = require("@ronomon/utimes");
    const glob = require("glob");
    const { promisify } = require("util");
    
    /**
     *
     * @param {String} path => 路徑
     * @param {Number} btime => 建立時間,不傳即不修改
     * @param {Number} mtime => 修改時間,不傳即不修改
     * @param {Number} atime => 訪問時間,不傳即不修改
     */
    const utimesPromise = promisify(utimes);
    
    (async () => {
      const paths = glob.sync("./test-files/**");
      const len = paths.length;
      for (let i = 0; i < len; i++) {
        await utimesPromise(
          paths[i],
          +new Date("2010/01/01"),
          +new Date("2010/01/02"),
          +new Date("2010/01/04")
        );
      }
    })();
    
  • 得出結果

    執行結果

這樣子就遞迴了我們所有的資料夾跟子檔案了進行修改了,本來想著在載入名字修改的,但苦於- -沒有介面,篇幅也過長,就留著過幾天再寫了。

gitee 地址,github 地址

最後

感謝各位觀眾老爺的觀看 O(∩_∩)O 希望你能有所收穫 ?

相關文章