23 ก.ย. 2023 เวลา 09:32 • ไอที & แก็ดเจ็ต

คัดลอกไฟล์ข้าม folder ด้วย apps script

เวลาที่เพื่อนแชร์โฟลเดอร์มาให้ หรือเวลาเราใช้บริการถ่ายภาพ แล้วช่างภาพแชร์โฟลเดอร์ภาพมาให้เรา แชร์มาที ไฟล์มีหลายร้อยไฟล์ จะดาวน์โหลดทั้งหมดก็กว่าจะไล่เลื่อนลงมาเห็นไฟล์ครบก็เสียเวลามาก
วันนี้ขอเสนอวิธีคัดลอกไฟล์ข้าม folder ในไดรฟ์ด้วย apps script
สิ่งที่เราต้องเตรียมมี 2 อย่างเท่านั้นคือ ID ของโฟลเดอร์ต้นทางและปลายทาง
1) apps script คัดลอกไฟล์
โดยการกด "+ ใหม่" ➜ "เพิ่มเติม" ➜ "สคริปต์ของ Google Apps" ดังภาพ
ภาพที่ 1
ตั้งชื่อโครงการเป็น "CopyFilesBetweenFolder"
และสร้างฟังก์ชัน
function copyFilesBetweenFolders() {
const sourceFolderId = 'ID โฟลเดอร์ต้นทาง' // ใส่ ID โฟลเดอร์แหล่งข้อมูล
const destinationFolderId = 'ID โฟลเดอร์ปลายทาง' // ใส่ ID โฟลเดอร์ปลายทาง
const sourceFolder = DriveApp.getFolderById(sourceFolderId)
const destinationFolder = DriveApp.getFolderById(destinationFolderId)
}
โดยนำ ID ของโฟลเดอร์ต้นทางและปลายทางมาใส่
ID ของโฟลเดอร์หาได้จากท้าย URL เมื่อเราเปิดโฟลเดอร์ เช่น ถ้า URL คือ "https://drive.google.com/drive/u/1/folders/1fwjQp4sUwj3edYQfoHWiwChWApX-XwkN" เราจะได้ ID ของโฟลเดอร์ คือ "1fwjQp4sUwj3edYQfoHWiwChWApX-XwkN"
ถ้ายังไม่มีโฟลเดอร์ปลายทางก็สร้างเพิ่มแล้วเอา ID มาใส่ไว้ในสคริปต์นะ
ภาพที่ 2
  • DriveApp คือ เรียกใช้สคริปต์ที่เกี่ยวกับไดรฟ์
  • .getFolderById() คือ เรียกโฟลเดอร์โดยใส่ ID
จากนั้นเราจะลองตรวจว่า ในโฟลเดอร์ต้นทางของเรามีไฟล์อะไรอยู่บ้างให้เราเพิ่มสคริปต์เข้าไป
var files = sourceFolder.getFiles()
while (files.hasNext()){
var file = files.next()
console.log(file.getName())
}
บันทึก กดเรียกใช้ อนุญาตสิทธิ์ เราจะเห็นชื่อไฟล์ทั้งหมดในโฟลเดอร์ต้นทางถูกแสดงออกมา
ภาพที่ 3
  • var files = sourceFolder.getFiles() คือ กำหนดตัวแปร files ให้เป็นไฟล์ทั้งหมดจากโฟลเดอร์ต้นทาง
  • while(เงื่อนไข){ดำเนินการ} คือให้ "ดำเนินการ" ไปเรื่อย ๆ ตราบที่ "เงื่อนไข" ยังเป็นจริง
  • files.hasNext() คือตรวจเงื่อนไขว่ายังมีไฟล์ที่ยังไม่ดำเนินการอยู่ไหม ถ้ามีไฟล์ที่ยังไม่ดำเนินการจะได้ค่า true ถ้าไม่มีไฟล์แล้วจะได้ค่า false
  • var file = files.next() คือ กำหนดตัวแปร file เป็นไฟล์ถัดไปที่ยังไม่ได้ดำเนินการ
  • .getName() คือ รับค่าชื่อไฟล์นั้นมา
จะเห็นว่าในตัวอย่าง จะมีไฟล์อยู่ 4 ไฟล์
ทีนี้ให้เราเปลี่ยนฟังก์ชันใน while บรรทัดสุดท้ายใหม่ เป็น
file.makeCopy(file.getName(), destinationFolder)
console.log('คัดลอกไฟล์ ' + file.getName() + ' สำเร็จแล้ว')
ภาพที่ 4
เมื่อกัดเรียกใช้ฟังก์ชัน ฟังก์ชันก็จะดำเนินการคัดลอกไฟล์จากโฟลเดอร์ต้นทางไปสู่โฟลเดอร์ปลายทาง (มีการขออนุญาตคัดลอกไฟล์เพิ่มเติม)
ภาพที่ 5 - 6
2) ปัญหาเมื่อไฟล์มีจำนวนมาก
เมื่อไฟล์มีจำนวนมาก สคริปต์ก็ย่อมใช้เวลาดำเนินการมาก อย่างตัวอย่างข้างบน คัดลอกไฟล์ภาพ 4 ไฟล์ ใช้เวลาดำเนินการ 9 วินาที แต่ถ้าไฟล์มีสัก 500 ไฟล์ล่ะ
ภาพที่ 7
ตามข้อกำหนดการให้บริการของ google ไม่ว่าจะเป็นแอคเคาท์ฟรีหรือแบบ google workspace ก็มีจำกัดการทำงานสคริปต์ไว้ที่ 6 นาทีต่อการดำเนินการ 1 ครั้ง
หมายความว่าสคริปต์คัดลอกไฟล์ที่เราทำไว้ ถ้าครบ 6 นาทีเมื่อไร สคริปต์ก็จะหยุดทำงาน แถมถ้ากดเรียกใช้สคริปต์อีกที สคริปต์ก็จะเริ่มคัดลอกตั้งแต่ไฟล์แรกใหม่
แต่เรามีทางแก้มาให้
ให้เราเปลี่ยนตัวฟังก์ชันตั้งแต่บรรทัดที่ 7 ไปเป็น
const userProperties = PropertiesService.getUserProperties()
var continuationToken = userProperties.getProperty('CONTINUATION_TOKEN')
const start = new Date()
var end = new Date()
const maxTime = 1000*60*5.5 // ระยะปลอดภัย 5.5 นาที
if (continuationToken == null) {
// คัดลอกรอบแรก
var files = sourceFolder.getFiles()
} else {
// ไม่ใช่รอบแรก ทำต่อจากที่ค้างไว้
var files = DriveApp.continueFileIterator(continuationToken)
}
while (files.hasNext() && end.getTime() - start.getTime() <= maxTime) {
var file = files.next()
file.makeCopy(file.getName(), destinationFolder)
console.log('คัดลอกไฟล์ ' + file.getName() + ' สำเร็จแล้ว')
end = new Date()
}
if(files.hasNext()){
continuationToken = files.getContinuationToken()
userProperties.setProperty('CONTINUATION_TOKEN', continuationToken)
} else {
console.log('คัดลอกไฟล์ทั้งหมดแล้ว')
PropertiesService.getUserProperties().deleteProperty('CONTINUATION_TOKEN')
}
เพิ่ม 3 ส่วนย่อยนี้เข้าไป ก่อนที่จะปิดฟังก์ชันด้วย } สคริปต์จะออกมาดังภาพ
ภาพที่ 8
เรียกได้ว่าเพิ่มขึ้นมาเยอะพอสมควรเลยนะ
  • มีการเรียกใช้ PropertiesService ซึ่งจะเป็นตัวที่จำไว้ว่าเราคัดลอกถึงไฟล์ไหนแล้ว
  • [8] var continuationToken คือ ตัวแปร token ที่เราสั่งให้สร้างไว้หากใกล้หมดเวลาทำงานของสคริปต์
  • start = new Date() และ end = new Date() จะเป็นตัวแปรสำหรับคำนวณว่าสคริปต์ทำงานไปนานเท่าไรแล้ว
  • [11] maxTime = 1000*60*5.5 คือเวลาสูงสุดที่เราอนุญาตให้สคริปต์ทำงาน 1000 คือ 1 วินาที, 1000*60 คือ 1 นาที, 1000*60*5.5 จึงเป็น 5 นาทีครึ่ง ถ้ามีการคัดลอกไฟล์ขนาดใหญ่มากครึ่งนาทีอาจทำเสร็จไม่ทัน ก็ปรับเป็น 4.5 หรือน้อยกว่านั้นก็ได้
  • if (เงื่อนไข) {ดำเนินการเมื่อเงื่อนไขจริง} else {ดำเนินการเมื่อไม่จริง}
  • [13] เวลาเราเรียกใช้สคริปต์รอบแรกสุด continuationToken จะเป็นค่าว่างหรือ null ดังนั้นเราจึงตั้งเงื่อนไขไว้ว่า ถ้า continuationToken == null ก็ให้ใช้ files = sourceFolder.getFiles() เหมือนดังสคริปต์แรกที่เราสร้างได้เลย
  • [18] แต่ถ้า continuationToken ถูกสร้างไว้ก็ให้เรียกมาใช้จาก var files = DriveApp.continueFileIterator(continuationToken)
  • [20] while (files.hasNext() && end.getTime() - start.getTime() <= maxTime) เราก็ตรวจ 2 เงื่อนไข คือยังมีไฟล์ที่ยังไม่ได้ดำเนินการอยู่และ เวลาดำเนินการยังไม่เกิน maxTime
  • [24] ถ้าเวลายังไม่เกินก็คัดลอกไฟล์และปรับ end ใหม่ให้เป็นเวลาปัจจุบันด้วย end = new Date()
  • แต่ถ้าเวลาเกินแล้วก็จะข้ามไปส่วนสุดท้ายไปสร้าง CONTINUATION_TOKEN เลย
  • และกดเรียกใช้สคริปต์ซ้ำ สคริปต์ก็จะคัดลอกไฟล์ต่อจากที่ทำงานค้างไว้
เพื่อให้เข้าใจการทำงานให้เราปรับ maxTime ให้เหลือแค่ 5 วินาที
const maxTime = 1000*5
ภาพที่ 9
เมื่อกดเรียกใช้ สคริปต์จะดำเนินการคัดลอกได้แค่ 3 ไฟล์ เพราะหมดเวลา 5 วินาทีก่อน
ภาพที่ 10
ให้เรากดเรียกใช้สคริปต์อีกครั้ง
ภาพที่ 11
สคริปต์จะทำงานโดยคัดลอกต่อจากไฟล์ที่ทำงานค้างไว้เลย และเมื่อคัดลอกครบทุกไฟล์ ก็จะมีข้อความแจ้งว่า "คัดลอกไฟล์ทั้งหมดแล้ว" ถ้าดำเนินการถึงขึ้นตอนนี้ token สำหรับเป็นจุดเช็คพอยต์ก็จะถูกลบออกไป
หากไม่ต้องการคัดลอกจนเสร็จ และต้องการลบ token เช็คพอยต์ออก ให้ใช้ฟังก์ชัน
function deleteProperty(){
PropertiesService.getUserProperties().deleteProperty('CONTINUATION_TOKEN')
}
เมื่อเรียกใช้ token ก็จะถูกลบออก ไว้สำหรับรีเซ็ท token เท่านั้น
จะกี่ร้อยไฟล์ก็มาเลย เราจะมากดสคริปต์ใหม่ในทุก ๆ 5 นาทีครึ่งเอง
หากเห็นว่าบทความนี้เป็นประโยชน์ กดไลค์กดแชร์เพื่อเป็นกำลังใจให้ผู้เขียนด้วยนะฮับ
โฆษณา