วิธีแก้ปัญหาสำหรับข้อยกเว้นสคริปต์ของ Google App: FILENAME.csv เกินขนาดไฟล์สูงสุดหรือไม่

ฉันกำลังสร้างแอปพลิเคชัน Google App Maker ที่รับไฟล์สเปรดชีต Excel CSV ที่ผู้ใช้อัปโหลดเป็นอินพุต ฉันคิดถึงวิธีแก้ปัญหาที่เป็นไปได้หลายประการในการอ่านข้อมูลจากไฟล์นี้ แต่ฉันพบข้อผิดพลาดนี้: "ข้อยกเว้น: FILENAME.csv มีขนาดไฟล์เกินขนาดสูงสุด" ในแต่ละครั้ง ฉันได้ลองแยกข้อมูลผ่าน parseCSV() ไปยัง Google Cloud SQL โดยอ่านเป็นสตริงเดียวผ่าน .getBlob().getDataAsString() และแยกด้วย "\n" และเขียนข้อมูลทั้งหมดลงใน Google Docs และพยายามอ่าน จากที่นั่น อย่างไรก็ตาม วิธีการทั้งหมดนี้ทำให้เกิดข้อผิดพลาดเดียวกัน

มีวิธีแก้ไขปัญหาขนาดไฟล์สูงสุดนี้หรือไม่

ฉันคิดว่าจะแยกไฟล์ออกเป็นไฟล์ CSV ขนาดเล็ก แต่ฉันไม่แน่ใจว่าต้องทำอย่างไร


person Eric    schedule 25.06.2018    source แหล่งที่มา
comment
คุณช่วยระบุขนาดไฟล์และจำนวนแถวของไฟล์ CSV ได้ไหม   -  person Tanaike    schedule 26.06.2018
comment
@Tanaike ไฟล์ของฉันมีขนาดใหญ่ 56.5 MB ไฟล์ Excel CSV มี 16 คอลัมน์และ 370,573 แถว   -  person Eric    schedule 26.06.2018


คำตอบ (1)


คุณต้องการแปลงไฟล์ CSV ขนาดใหญ่เป็นสเปรดชีตแบบแยก หากความเข้าใจของฉันถูกต้อง วิธีแก้ปัญหานี้เป็นอย่างไร

ปัญหาและวิธีแก้ปัญหาสำหรับสถานการณ์นี้:

  1. เมื่อไฟล์ CSV ขนาดใหญ่ถูกแปลงเป็นสเปรดชีต ไฟล์ดังกล่าวจะไม่สามารถแปลงเป็นสเปรดชีตได้โดยตรง เนื่องจากมีทั้งจำนวนเซลล์ทั้งหมดและขนาดไฟล์ และเมื่อพยายามแยกไฟล์ขนาดใหญ่ มันก็ไม่สามารถทำได้เนื่องจาก Blob ที่สามารถใช้ใน GAS มีขนาดน้อยกว่า 50 MB (52,428,800 ไบต์)

    • In order to split such large file, it uses "Partial download" of files.get in Drive API.
  2. ในสภาพแวดล้อมของฉัน เมื่อใช้ไฟล์ CSV ขนาด 100 MB สำหรับสคริปต์ตัวอย่างนี้ เมื่อไฟล์ถูกแบ่งออกเป็น 10 MB จะใช้เวลาประมาณ 65 วินาทีในการแปลงก้อนข้อมูลเป็นสเปรดชีต ในกรณีนี้ เมื่อไฟล์ CSV ถูกแปลงอย่างสมบูรณ์ จะถือว่าไฟล์นั้นเกินเวลาที่กำหนด (6 นาที) ในการดำเนินการ GAS

    • In order to avoid this, it is required to implement the resumable conversion from the large CSV-file to several spreadsheets.

เตรียมตัว :

หากต้องการใช้สคริปต์ตัวอย่างนี้ โปรดเปิดใช้งาน Drive API ที่ Advanced Google Services และคอนโซล API

เปิดใช้งาน Drive API v2 ที่บริการขั้นสูงของ Google

  • On script editor
    • Resources -> Advanced Google Services
    • เปิด Drive API เวอร์ชัน 2

เปิดใช้งาน Drive API ที่คอนโซล API

  • On script editor
    • Resources -> Cloud Platform project
    • ดูคอนโซล API
    • ที่เริ่มต้นใช้งาน คลิกเปิดใช้งาน API และรับข้อมูลรับรอง เช่น คีย์
    • ที่ด้านซ้าย คลิกไลบรารี
    • ที่ Search for APIs & services ให้ใส่ "Drive" และคลิก Drive API
    • คลิกปุ่มเปิดใช้งาน
    • หากเปิดใช้งาน API แล้ว โปรดอย่าปิด

สคริปต์ตัวอย่าง:

function createSplitSpreadsheet(obj) {
  var accessToken = ScriptApp.getOAuthToken();
  var baseUrl = "https://www.googleapis.com/drive/v3/files/";

  // Retrieve file size.
  var url1 = baseUrl + obj.fileId + "?fields=size";
  var params1 = {
    method: "get",
    headers: {Authorization: "Bearer " + accessToken},
  };
  var fileSize = Number(JSON.parse(UrlFetchApp.fetch(url1, {headers: {Authorization: "Bearer " + accessToken}}).getContentText()).size);

  // Calculate number of output files.
  if (obj.files == null) {
    obj.number = 1;
    obj.start = 0;
  }
  var start = obj.start;
  var end = start + obj.chunk;
  var useFileSize = fileSize - start;
  f = Math.floor(useFileSize / obj.chunk);
  f = useFileSize % obj.chunk > 0 ? f + 1 : f;
  if (f < obj.files || obj.files == null) {
    obj.files = f;
  }

  // Split large file by chunk size (bytes).
  var url2 = baseUrl + obj.fileId + "?alt=media";
  var i;
  for (i = 0; i < obj.files; i++) {
    var params = {
      method: "get",
      headers: {
        Authorization: "Bearer " + accessToken,
        Range: "bytes=" + start + "-" + end,
      },
    };
    var res = UrlFetchApp.fetch(url2, params).getContentText();
    var e = res.lastIndexOf("\n");
    start += e + 1;
    end = start + obj.chunk;
    Drive.Files.insert(
      {mimeType: MimeType.GOOGLE_SHEETS, title: obj.fileName + (i + obj.number)},
      Utilities.newBlob(res.substr(0, e), MimeType.CSV)
    );
  }

  // Return next start value if there is a next chunk for the resume.
  if (start < fileSize) {
    return {nextStart: start, nextNumber: i + obj.number};
  } else {
    return null;
  }
}

// Please run this function.
function main() {
    var obj = {
        fileId: "#####", // File ID of the large CSV file.
        chunk: 10485760, // 10MB Please modify this for your situation.
        files: 3, // Please input the number of files you want to convert.
        start: 0,
        fileName: "sample",
        number: 1, // Counter of output files. Please input this as a next number.
    };
    var nextStart = createSplitSpreadsheet(obj);
    Logger.log(nextStart);
}

การใช้งาน :

เมื่อคุณใช้สิ่งนี้ โปรดแก้ไข obj ใน main() สำหรับสถานการณ์ของคุณ และเรียกใช้ main() กรณีตัวอย่างมีดังนี้

ก็ประมาณนี้ครับ.

  • คุณต้องการแปลงไฟล์ CSV ที่มีขนาด 100 MB เป็น 10 สเปรดชีต
  • ขนาดของหนึ่งชิ้นคือ 10 MB
  • ไฟล์ CSV จะถูกประมวลผลทุกๆ 3 ครั้ง

ในกรณีตัวอย่างนี้ แต่ละ obj จะเป็นดังนี้ โปรดป้อน obj แต่ละตัวในการรันแต่ละครั้ง

  1. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: 0, fileName: "sample", number: 1}
    • {"nextStart": ### nextStart2 ###, "nextNumber": 4} is returned from createSplitSpreadsheet().
  2. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart2 ###, fileName: "sample", number: 4}
    • {"nextStart": ### nextStart3 ###, "nextNumber": 7} is returned from createSplitSpreadsheet().
  3. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart3 ###, fileName: "sample", number: 7}
    • {"nextStart": ### nextStart4 ###, "nextNumber": 10} is returned from createSplitSpreadsheet().
  4. var obj = {fileId: "#####", chunk: 10485760, files: 3, start: ### nextStart4 ###, fileName: "sample", number: 10}
    • null is returned from createSplitSpreadsheet().

ในขั้นตอนนี้ จะมีการสร้างสเปรดชีต 10 รายการจากไฟล์ CSV ที่มีขนาด 100 MB

หากใช้ null สำหรับ files ใน obj ระบบจะคำนวณ files โดยอัตโนมัติ แต่ในกรณีนี้ ระยะเวลาที่จำกัดในการดำเนินการ GAS อาจสิ้นสุดลงแล้ว โปรดระวังสิ่งนี้

อ้างอิง :

ถ้านี่ไม่ใช่สิ่งที่คุณต้องการ ฉันขอโทษ

person Tanaike    schedule 26.06.2018