ย้ายไฟล์จำนวนมากเข้าโฟลเดอร์ย่อย แบบมีเงื่อนไข

โจทย์ คือต้องการย้ายไฟล์สแกน จำนวนมาก เข้าไปเก็บตาม folder เพื่อทำ sharding storage ซึ่งการสร้าง directory สำหรับจัดเก็บ และการกระจายไฟล์ไปยัง folder นั้นคือหลักสำคัญในการดำเนินการครั้งนี้

Create Directory

ด้วย brief ที่เก็บไฟล์แยกด้วยตัวเลขล้วนๆ ทำให้ง่ายต่อการสร้าง folder โดยหลักการก็คือ แบ่ง folder เป็นเลข 00-99 และในแต่ละ folder ก็สร้าง 00-99 ไว้ด้วย ตามแบบด้านล่าง

storage/
├── 00/
│   ├── 00
│   ├── 01
│   ├── ..
│   └── 99
├── 01/
│   ├── 00
│   ├── 01
│   ├── ..
│   └── 99
├── ..
└── 99/
    ├── 00
    ├── 01
    ├── ..
    └── 99

วิธีสร้าง folder ตามแบบฉบับ “ความขี้เกียจเกิดก่อนวัตกรรม” ก็คือเขียนคำสั่งให้มันนั้นเอง โดยใช้ batch ง่ายๆ สร้าง folder เพื่อเก็บขึ้นมาก่อน โดยการวน loop 2 รอบ และให้มันสร้าง folder ตั้งแต่ 1 – 100

FOR /L %N IN (1,1,100) DO ( FOR /L %M IN (1,1,100) DO md "%N\%M" )

พอ run เสร็จก็จะได้ folder 1 – 100 ขึ้นมา เท่านี้ก็เหลือแค่ rename ชื่อ เลข 1 ให้เป็น 01 เลข 100 ให้เป็น 00 เท่านั้น

Move File with nodejs

หลังจากสร้าง folder เสร็จแล้ว เราก็มาย้ายไฟล์สแกนทั้งหมดเข้าไปเก็บตาม folder ของมันได้เลย โดยเงื่อนไขก็คือ ชื่อไฟล์จะเป็นตัวเลข 9 หลัก 000000000.pdf

  • สีเหลือง = storage/xx
  • สีเขียว = storage/xx/xx

โดยวิธีเก็บแบบนี้จะใช้ 2 หลักท้าย มาเป็น folder แรก และ 2 หลักต่อมา เป็น sub-folder นั่นเอง สมมุติ ชื่อไฟล์คือ 000123456.pdf ก็จะได้ path เก็บไฟล์แบบนี้ storage/56/34/000123456.pdf

เมื่อรู้เงื่อนไขแล้วก็มาเขียน code สำหรับโยนไฟล์กันได้แล้ว เลือกใช้ nodejs เนื่องจากมันค่อนข้างง่าย และ server ที่เก็บไฟล์ก็เป็น Linux ด้วย จะตั้ง cronjob ให้มันโยนไฟล์ตอนไหนก็ทำได้

const fs = require("fs");
const mv = require('mv');
const path = require("path");
const dotenv = require("dotenv").config();

const srcFolder = process.env.SOURCE_PATH;
const descFolder = process.env.DESTINATION_PATH;

// read all files in the directory
let files = fs.readdirSync(srcFolder);

// Loop through array and rename all files
files.forEach((file, index) => {

  let fullPath = path.join(srcFolder, file);

  if (path.extname(file) == ".pdf") {
    let fname = path.basename(file, ".pdf");
    if (fname.length == 9) {
      let folder = `${fname.slice(7, 9)}/${fname.slice(5, 7)}/${file}`;

      try {
        mv(fullPath, path.join(descFolder, folder), () => {
          console.log(index, fullPath, path.join(descFolder, folder));
          // console.log(err);
        })
      } catch (error) {
        console.error(error)
      }
    }
  }

});

ไฟล์ .env

#Development Env
NODE_ENV = 'development'
SOURCE_PATH = '/path_of/source'
DESTINATION_PATH = '/path_of/destination'

package.json

{
  "name": "@service/nodejs-sharding-storage",
  "version": "1.0.0",
  "description": "nodejs file sharding storage",
  "main": "src/app.js",
  "scripts": {
    "start": "node ./src/app.js",
    "dev": "nodemon --watch src ./src/app.js"
  },
  "dependencies": {
    "dotenv": "^8.2.0",
    "mv": "^2.1.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.6"
  }
}

สรุป

วิธีการข้างต้นนั้น ทำแต่การโยนไฟล์ไปเก็บเท่านั้น ตัวโปรแกรมก็ยังสามารถเพิ่มความสามารถในการบันทึกข้อมูลลงใน database ได้ ว่าไฟล์ไหนเก็บไปแล้วบ้าง เก็บเมื่อไหร่ และสามารถใช้ node-cron เพื่อสั่งให้มันทำงานเองอัตโนมัติ ตามเวลายิ่งสะดวกเข้าไปใหญ่