繁体   English   中英

创建一个与上传文件的文件夹同名的文件

[英]Create a file with the same name as the folder where a file was uploaded

我在 Web 应用程序中有一个 HTML 表单,是使用 GAS 创建的。

此 HTML 表单是根据此处的文件上传脚本创建的:

驱动多次上传

这是 HTML 表格:

在此处输入图像描述

关键是我需要将文件上传到遵循以下模式的文件夹中: 在此处输入图像描述

第一个数字是指在表格上选择的 model ,第二个数字是指使用的插槽

因此需要创建一个function来识别Model中选择的input ,根据这个input判断第一个空文件夹是哪个,然后取那个文件夹的ID传给客户端上传文件在里面。

在社区一些成员的帮助下,进行了一些改编,最终的 function 是这样的:

    /** Modified version of script written by Tanaike */
    function createOrGetFolder(folderName, parentFolderId) {
      try {
        var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
        if (parentFolder) {
          var foldersIter = parentFolder.getFoldersByName("Video");
          if (foldersIter.hasNext()) {
            var videoFolder = foldersIter.next();
            var nextFolderName = folderName + "-01";
            while (!folder) {
              video_folder = videoFolder.getFoldersByName(nextFolderName);
              if (video_folder.hasNext()) {
                folder = video_folder.next();
                var files = folder.getFiles();
                if (files.hasNext()) {
                  var [a, b] = nextFolderName.split("-");
                  nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
                  folder = null;
                }
              } else {
                folder = videoFolder.createFolder(nextFolderName);
              }
            }
          } else {
            folder = parentFolder.createFolder("Video");
            folder = folder.createFolder(folderName);
          }
        } else {
          throw new Error("Parent Folder with id: " + parentFolderId + " not found");
        }
        return folder.getId();
      } catch (error) {
        return error;
      }
    }

它工作得很好,关键是这个表单还有一个 function,在提交表单时生成一个.csv 文件,function 是这个:

.gs文件:

const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile("Sample.csv", data);

HTML档案:

var name = $('#name01').val();
      var description = $('#description').val();
      var model = $('#Model').val();
      upload_folder = model;
      var color = $('#Color').val();
      var form_values = [name, description, model, color];
      var data = form_values.join(",");

google.script.run.saveDataAsCSV(data, uploadParentFolderId);

我的目标是使 .csv 文件生成与上传文件的文件夹同名,也就是说,如果文件上传到文件夹01-01 ,文件名必须是01-01.csv ,如果文件上传到02-02文件夹,文件名必须是02-02.csv ,依此类推。

我怎样才能做到这一点?

完整的脚本代码可以在这里查看:

.gs文件:

function doGet(e) {
  return HtmlService.createTemplateFromFile('forms0101.html').evaluate();
}


function getOAuthToken() {
  return ScriptApp.getOAuthToken();
}


function getParent(){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var id = ss.getId();
  var parent = DriveApp.getFileById(id).getParents().next().getId();
  return parent
}

function getLimitFolder(){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var pastapai = DriveApp.getFileById(ss.getId()).getParents();
  var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
  return limitfolder;
}

function getFilesLimit(){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var pastapai = DriveApp.getFileById(ss.getId()).getParents();
  var files = [];
  Logger.log(pastapai);
  //var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
  var limitfolder = pastapai.next().getFoldersByName("_").next().getFiles();
  while(limitfolder.hasNext()){
    var file = limitfolder.next();
    files.push([file.getId()]);
  }
  console.log(files.length);
  return files.length;
}

//function testenumeroarquivos(){
//console.log(checkForFiles()); // When you use this line, you can see the filename of the files.
//}

/**
* creates a folder under a parent folder, and returns it's id. If the folder already exists
* then it is not created and it simply returns the id of the existing one
*/

function createOrGetFolder(folderName, parentFolderId) {
  try {
    var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
    if (parentFolder) {
      var foldersIter = parentFolder.getFoldersByName("Video");
      if (foldersIter.hasNext()) {
        var videoFolder = foldersIter.next();
        var nextFolderName = folderName + "-01";
        while (!folder) {
          video_folder = videoFolder.getFoldersByName(nextFolderName);
          if (video_folder.hasNext()) {
            folder = video_folder.next();
            var files = folder.getFiles();
            if (files.hasNext()) {
              var [a, b] = nextFolderName.split("-");
              nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
              folder = null;
            }
          } else {
            folder = videoFolder.createFolder(nextFolderName);
          }
        }
      } else {
        folder = parentFolder.createFolder("Video");
        folder = folder.createFolder(folderName);
      }
    } else {
      throw new Error("Parent Folder with id: " + parentFolderId + " not found");
    }
    console.log("Test" + nextFolderName)
    return folder.getId();
  } catch (error) {
    return error;
  }
}


const saveDataAsCSV = (data, folderId) => {
  const folder = DriveApp.getFolderById(folderId);
  folder.createFile(`${nextFolderName.getName()}.csv`, data);
}
const increaseRequest = (data, folderId) => DriveApp.getFolderById(folderId).createFile("IncreaseRequest.csv", data);


// NOTE: always make sure we use DriveApp, even if it's in a comment, for google to import those
// libraries and allow the rest of the app to work. see https://github.com/tanaikech/Resumable_Upload_For_WebApps

HTML档案:

<!DOCTYPE html>
<html>
  <head>
    <base target="_blank">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Drive Multi Large File Upload</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
     
     <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <style>
      @import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;600;700&display=swap');
      
      .disclaimer{
        width: 480px; 
        color: #646464;
        margin: 20px auto;
        padding:0 16px;
        text-align:center;
        font:400 12px Rubik,sans-serif;
        }

      h5.center-align.teal-text {
        font:700 26px Rubik,sans-serif;
        color: #00F498!important;
      }

      .row {
        font:600 14px Rubik,sans-serif;
      }

      .btn {
        background-color: black;
      }

      .btn:hover {
        background-color: #00F498;
      }

      body {
        margin-top: -40px;
      }

      #progress {
        color: #00000;
      }
      
      .disclaimer a{
        color: #00BCAA;
        }

      #credit{
        display:none
        }

        .btnOpenModal {
  font-size: x-large;
  padding: 10px;
  border: none;
  border-radius: 5px;
  background-color: blueviolet;
  color: white;
  cursor: pointer;
}

hr {
  border: 0px;
  border-top: 1px solid lightgray;
}

.modal-container {
  width: 100vw;
  position: fixed;
  top: 30px;
  display: none;
  z-index: 999;
  justify-content: center;
}

.modal {
  display: flex;
  flex-direction: column;
  padding: 30px;
  background-color: white;
  border-radius: 10px;
  width: 50%;
}

.active {
  display: flex;
}

.active .modal {
  animation: modal .4s;
}

@keyframes modal {
  from {
    opacity: 0;
    transform: translate3d(0, -60px, 0);
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

.btns {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
}

.btns button {
  font-size: medium;
  padding: 10px;
  border: none;
  border-radius: 5px;
  color: white;
  cursor: pointer;
}

.btnOK {
 background-color: blue!important;
}

.btnClose {
  background-color: brown!important;
 }


    </style>
  </head>
  <body>
    <form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
 <div id="forminner">


  <div class="modal-container">
    <div class="modal">
      <h2>Info</h2>
      <hr />
      <span>
        Lorem Ipsum is simply dummy text of the printing and typesetting 
        industry. Lorem Ipsum has been the industry's standard dummy text
         ever since the 1500s, when an unknown printer took a galley of 
         type and scrambled it to make a type specimen book. 
      </span>
      <hr />
      <div class="btns">
        <button class="btnOK" onclick="increaseRequest(); closeModal();">OK</button>
        <button class="btnClose" onclick="closeModal()">Close</button>
      </div>
    </div>
  </div>

  <h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">YOUR NAME</h5>
    <div class="row">
          <div class="input-field col s12">
            <input id="name01" type="text" name="Name" class="validate" required="required" aria-required="true">
            <label for="name" class="">Name</label>
          </div>
        </div>
    
      <h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">SOME DESCRIPTION</h5>
        <div class="row">
          <div class="input-field col s12">
            <input id="description" type="text" name="Description" class="validate" required="required" aria-required="true">
            <label for="name">Description</label>
          </div>
        </div>

    <div class="row">
      <div class="col-8 col-md-4">
        <h6>Model</h6>       
        <select class="custom-select" id="Model">
          <option selected="">Choose...</option>
          <option value="01">01</option>
          <option value="02">02</option>
          <option value="03">03</option>
        </select> 
          &nbsp;

        <h6>Color</h6>        
        <select class="custom-select" id="Color">
          <option selected="">Choose...</option>
          <option value="Red">Red</option>
          <option value="Green">Green</option>
        </select>   
      </div>
  </div>

    
        <div class="row">
          <div class="col s12">
            <h5 class="center-align teal-text">Upload the Video File</h5>
           
          </div>
        </div>
        
        <div class="row">
          <div class="file-field input-field col s12">
            <div id="input-btn" class="btn">
              <span>File</span>
              <input id="files" type="file" single="">
            </div>
            <div class="file-path-wrapper">
              <input class="file-path validate" type="text" placeholder="Select the file">
            </div>
          </div>
        </div>

        <div class="row">
          <div class="input-field col s6">
            <button id="submit-btn" class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12 hide" id="update">
            <hr>
            <p>
              Por favor, aguarde enquanto seu arquivo está sendo carregado.<br><span style="color: #00000;"><b>Não feche ou atualize a janela durante o upload.</b></span>
            </p>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12" id="progress">
          </div>
        </div>
      </div>
     </div> 
      <div id="success" style="display:none">
        <h5 class="center-align teal-text">Tudo certo!</h5>
        <p>Se você já preencheu todos os campos é só fechar essa janela e clicar em enviar!</p>
        <button id="fechar" class="waves-effect waves-light btn submit-btn" style ="transform: translateX(160%);" type="button" onclick="google.script.host.close()">Fechar</button>
      </div>

    </form>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
    <script src="https://gumroad.com/js/gumroad.js"></script>

    <script>
      var upload_folder = "01";
      const chunkSize = 5242880;
      const uploadParentFolderId = <?=getParent()?>; // creates a folder inside of this folder
      const limitfolder = <?=getLimitFolder()?>;
      const fileslimit = <?=getFilesLimit()?>;
      const modal = document.querySelector('.modal-container');

      var name = $('#name01').val();
      var description = $('#description').val();
      var model = $('#Model').val();
      upload_folder = model;
      var color = $('#Color').val();
      var form_values = [name, description, model, color];
      form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
      var data = form_values.join(",");


      function submitForm() {

      var name = $('#name01').val();
      var description = $('#description').val();
      var model = $('#Model').val();
      upload_folder = model;
      var color = $('#Color').val();
      var form_values = [name, description, model, color];
      form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
      var data = form_values.join(",");

        // Added the below script.
        if ($('#submit-btn.disabled')[0]) return; // short circuit

        var name = upload_folder
        var files = [...$('#files')[0].files]; // convert from FileList to array

        
        if (files.length === 0) {
          showError("Por favor, selecione um arquivo");
          return;
        }

        google.script.run.saveDataAsCSV(data, uploadParentFolderId);
        google.script.run.saveDataAsCSV(data, limitfolder);

        disableForm(); // prevent re submission

        // the map and reduce are here to ensure that only one file is uploaded at a time. This allows
        // the promises to be run sequentially
        files.map(file => uploadFilePromiseFactory(file))
            .reduce((promiseChain, currentTask) => {
              return promiseChain.then(currentTask);
            }, Promise.resolve([])).then( () => {
              console.log("Completed all files upload");
              showSuccess();
            });
      }

      function checkforfiles() {
        
        if (fileslimit <= 2) {
        submitForm();
      }
        if (fileslimit == 3) {
        openModal();
      } 
        if (fileslimit >= 4) {
        showError("erro");
        return;
      }
        
      }
      
      function openModal() {
      modal.classList.add('active');
       }

      function closeModal() {
      modal.classList.remove('active');
      }
      
      function increaseRequest() {
      google.script.run.increaseRequest(data, limitfolder);
      }


      function disableForm() {
        $('#submit-btn').addClass('disabled');
        $('#input-btn').addClass('disabled');
        $('#update').removeClass('hide');
         $('#update').removeClass('hide');
      }

       function closer(){
        google.script.host.close();
      }

      function uploadFilePromiseFactory(file) {
        return () => {
          console.log("Processing: ", file.name);
          return new Promise((resolve, reject) => {

            showProgressMessage("Seu arquivo está sendo carregado");

            var fr = new FileReader();
            fr.fileName = file.name;
            fr.fileSize = file.size;
            fr.fileType = file.type;
            // not sure of a better way of passing the promise functions down
            fr.resolve = () => resolve();
            fr.reject = (error) => reject(error);
            fr.onload = onFileReaderLoad;
            fr.readAsArrayBuffer(file);
          });
        };
      }
      
      /**
       * Gets called once the browser has loaded a file. The main logic that creates a folder
       * and initiates the file upload resides here
       */
      function onFileReaderLoad(onLoadEvent) {
        var fr = this;

        var newFolderName = upload_folder
        createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
          console.log("Found or created guest folder with id: ", newFolderId);
          uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
              fr.resolve();
            }, (error) => {
              fr.reject(error);
            });
          },
          (error) => {
            if (error) {
              showError(error.toString());
            }
            console.log("onFileReaderLoad Error2: ", error);
          });

      }

      /**
       * call to the DriveApp api. Wrapped in a promise in case I want to address timing issues between a
       * createFolder and findFolderById
       */
      function createOrGetFolder(folderName, parentFolderId) {
        return new Promise((resolve, reject) => {
          google.script.run.withSuccessHandler(response => {
            console.log("createOrGetFolder response: ", response);
            if (response && response.length) {
              resolve(response);
            }
            reject(response);
          }).createOrGetFolder(folderName, parentFolderId);
        });
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function uploadFileToDriveFolder(parentFolderId) {
        var fr = this;
        return new Promise((resolve, reject) => {
          var fileName = fr.fileName;
          var fileSize = fr.fileSize;
          var fileType = fr.fileType;
          console.log({fileName: fileName, fileSize: fileSize, fileType: fileType});
          var buf = fr.result;
          var chunkpot = getChunkpot(chunkSize, fileSize);
          var uint8Array = new Uint8Array(buf);
          var chunks = chunkpot.chunks.map(function(e) {
            return {
               data: uint8Array.slice(e.startByte, e.endByte + 1),
               length: e.numByte,
               range: "bytes " + e.startByte + "-" + e.endByte + "/" + chunkpot.total,
            };
          });
          google.script.run.withSuccessHandler(oAuthToken => {
            var xhr = new XMLHttpRequest();
            xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
            xhr.setRequestHeader('Authorization', "Bearer " + oAuthToken);
            xhr.setRequestHeader('Content-Type', "application/json");
            xhr.send(JSON.stringify({
              mimeType: fileType,
              name: fileName,
              parents: [parentFolderId]
            }));
            xhr.onload = () => {
              doUpload(fileName, {
                location: xhr.getResponseHeader("location"),
                chunks: chunks,
              }).then(success => {
                resolve(success);
                console.log("Successfully uploaded: ", fileName);
              },
              error => {
                reject(error);
              });
            };

            xhr.onerror = () => {
              console.log("ERROR: ", xhr.response);
              reject(xhr.response);
            };
          }).getOAuthToken();
        });
      }

      function showSuccess() {
        $('#forminner').hide();
        $('#success').show();
        $('#fechar').show();
      }

      function showError(e) {
        $('#progress').addClass('red-text').html(e);
      }

      function showMessage(e) {
        $('#update').html(e);
      }

      function showProgressMessage(e) {
        $('#progress').removeClass('red-text').html(e);
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function doUpload(fileName, e) {
        return new Promise((resolve, reject) => {
          showProgressMessage("Carregando: <span style='color: #00F498 ;'>" + "0%</span>");
          var chunks = e.chunks;
          var location = e.location;
          var cnt = 0;
          var end = chunks.length;
          var temp = function callback(cnt) {
            var e = chunks[cnt];
            var xhr = new XMLHttpRequest();
            xhr.open("PUT", location, true);
            console.log("content range: ", e.range);
            xhr.setRequestHeader('Content-Range', e.range);
            xhr.send(e.data);
            xhr.onloadend = function() {
                var status = xhr.status;
                cnt += 1;
                console.log("Uploading: " + status + " (" + cnt + " / " + end + ")");
                showProgressMessage("Carregando: <span style='color: #00F498 ;'>" 
                       + Math.floor(100 * cnt / end) + "%</span>" );
                if (status == 308) {
                    callback(cnt);
                } else if (status == 200) {
                    $("#progress").text("Done.");
                    resolve();
                } else {
                    $("#progress").text("Error: " + xhr.response);
                    reject();
                }
            };
          }(cnt);
        });
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function getChunkpot(chunkSize, fileSize) {
        var chunkPot = {};
        chunkPot.total = fileSize;
        chunkPot.chunks = [];
        if (fileSize > chunkSize) {
            var numE = chunkSize;
            var endS = function(f, n) {
                var c = f % n;
                if (c == 0) {
                    return 0;
                } else {
                    return c;
                }
            }(fileSize, numE);
            var repeat = Math.floor(fileSize / numE);
            for (var i = 0; i <= repeat; i++) {
                var startAddress = i * numE;
                var c = {};
                c.startByte = startAddress;
                if (i < repeat) {
                    c.endByte = startAddress + numE - 1;
                    c.numByte = numE;
                    chunkPot.chunks.push(c);
                } else if (i == repeat && endS > 0) {
                    c.endByte = startAddress + endS - 1;
                    c.numByte = endS;
                    chunkPot.chunks.push(c);
                }
            }
        } else {
            var chunk = {
                startByte: 0,
                endByte: fileSize - 1,
                numByte: fileSize,
            };
            chunkPot.chunks.push(chunk);
        }
        return chunkPot;
      }

    </script>

  </body>

</html>

也可以通过访问此工作表来查看

虽然我不确定我是否能正确理解你的实际预期结果,但请测试以下修改。

Google Apps 脚本端:

请修改 Google Apps Script 的saveDataAsCSV如下。

const saveDataAsCSV = (data, folderId1, folderId2 = null) => {
  if (folderId2) {
    DriveApp.getFolderById(folderId1).createFile(`${DriveApp.getFolderById(folderId2).getName()}.csv`, data);
  } else {
    DriveApp.getFolderById(folderId1).createFile("sample.csv", data);
  }
}

Javascript 方:

请删除google.script.run.saveDataAsCSV(data, uploadParentFolderId); 在 function submitForm中。

并且,修改onFileReaderLoad的onFileReaderLoad如下。

function onFileReaderLoad(onLoadEvent) {
  var fr = this;
  var newFolderName = upload_folder
  createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
    google.script.run.saveDataAsCSV(data, uploadParentFolderId, newFolderId);
    console.log("Found or created guest folder with id: ", newFolderId);
    uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
      fr.resolve();
    }, (error) => {
      fr.reject(error);
    });
  },
    (error) => {
      if (error) {
        showError(error.toString());
      }
      console.log("onFileReaderLoad Error2: ", error);
    });
}
  • 通过此修改,我认为创建了一个 CSV 文件,如01-01.csvuploadParentFolderId文件夹。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM