Office 365(StartUpload,ContinueUpload,FinishUpload)的大文件上载无法按预期工作 - SharePoint

时间:2017-06-07 08:06:27

标签: file-upload office365api sharepoint-online large-file-upload sharepoint-2016

当我尝试通过上传文件块使用3种新方法(StartUpload,ContinueUpload,FinishUpload)上传大文件时,最终上传的文件是损坏的文件,大小也大于实际文件。我使用Rest API上传大文件。

遵循的步骤如下: -

  1. 为输入文件创建HTML。
  2. <input name="FileUpload" type="file" id="uploadInput" className="inputFile" multiple="false" onchange="upload(this.files[0])" />

    1. 下面的方法是代码的起点:

      • 为siteurl创建全局变量
    2. var Tasks = {
        urlName: window.location.origin + "/",
        siteName: '/sites/ABC',
      };

      1. 调用Upload()方法

        • 首先在文件夹中创建大小为0的虚拟文件,以继续进行大文件上传。

        • 创建FileReader对象,然后开始创建包含3个参数(偏移量,长度,方法(即start / continue / finishupload))的文件块,并将块推送到数组中。

        • 创建上传的唯一ID,即uploadID
        • 调用UploadFile方法
      2. function upload(file) {
          var docLibraryName = "/sites/ABC/Shared Documents";
          var fileName = $("#uploadInput").val().replace(/C:\\fakepath\\/i, '');
          var folderName = "";
          createDummaryFile(docLibraryName, fileName, folderName)
          var fr = new FileReader();
          var offset = 0;
          var total = file.size;
          var length = 1000000 > total ? total : 1000000;
          var chunks = [];
          fr.onload = evt => {
            while (offset < total) {
              if (offset + length > total)
                length = total - offset;
              chunks.push({
                offset,
                length,
                method: getUploadMethod(offset, length, total)
              });
              offset += length;
            }
            for (var i = 0; i < chunks.length; i++)
              console.log(chunks[i]);
            if (chunks.length > 0) {
              const id = getGuid();
              uploadFile(evt.target.result, id, docLibraryName, fileName, chunks, 0);
            }
          };
          fr.readAsArrayBuffer(file);
        }
        
        function createDummaryFile(libraryName, fileName, folderName) {
          return new Promise((resolve, reject) => {
            var endpoint = Tasks.urlName + Tasks.siteName + "/_api/web/GetFolderByServerRelativeUrl('" + libraryName + "/" + folderName + "')/Files/add(url=@TargetFileName,overwrite='true')?" +
              "&@TargetFileName='" + fileName + "'";
            var url;
            const headers = {
              "accept": "application/json;odata=verbose"
            };
            performUpload(endpoint, headers, libraryName, fileName, folderName, convertDataBinaryString(0));
          });
        }
        
        function S4() {
          return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }
        
        function getGuid() {
          return (S4() + S4() + "-" + S4() + "-4" + S4().substr(0, 3) + "-" + S4() + "-" + S4() + S4() + S4()).toLowerCase();
        }
        //check position for selecting method
        
        function getUploadMethod(offset, length, total) {
          if (offset + length + 1 > total) {
            return 'finishupload';
          } else if (offset === 0) {
            return 'startupload';
          } else if (offset < total) {
            return 'continueupload';
          }
          return null;
        }

        1. 上传文件方法

          • 将arraybuffer转换为blob块以开始上传文件

          • 使用我们之前创建的方法和偏移量1mb开始实际文件块上传(uploadFileChunk方法)

          • 启动chunk循环并调用相同的方法

        2. function uploadFile(result, id, libraryPath, fileName, chunks, index) {
            const data = convertFileToBlobChunks(result, chunks[index]);
            var response = uploadFileChunk(id, libraryPath, fileName, chunks[index], data);
            index += 1;
            if (index < chunks.length)
              uploadFile(result, id, libraryPath, fileName, chunks, index, chunks[index].offset);
          }
          
          function convertFileToBlobChunks(result, chunkInfo) {
            var arrayBuffer = chunkInfo.method === 'finishupload' ? result.slice(chunkInfo.offset) : result.slice(chunkInfo.offset, chunkInfo.offset + chunkInfo.length);
            return convertDataBinaryString(arrayBuffer);
          }
          
          function convertDataBinaryString(data) {
            var fileData = '';
            var byteArray = new Uint8Array(data);
            for (var i = 0; i < byteArray.byteLength; i++) {
              fileData += String.fromCharCode(byteArray[i]);
            }
            return fileData;
          }

          1. UploadFileChunk方法实际开始上传文件块)

            • 表单字符串if startupload然后没有fileoffset,如果是continueupload和finishupload那么它将有fileoffset。
            • 使用rest api
            • 调用performupload方法开始上传
          2. function uploadFileChunk(id, libraryPath, fileName, chunk, data) {
              new Promise((resolve, reject) => {
                var offset = chunk.offset === 0 ? '' : ',fileOffset=' + chunk.offset;
                var folderName = "";
                var endpoint = Tasks.urlName + Tasks.siteName + "/_api/web/getfilebyserverrelativeurl('" + libraryPath + "/" + fileName + "')/" + chunk.method + "(uploadId=guid'" + id + "'" + offset + ")";
                const headers = {
                  "Accept": "application/json; odata=verbose",
                  "Content-Type": "application/octet-stream"
                };
                performUpload(endpoint, headers, libraryPath, fileName, folderName, data);
              });
            }
            
            function performUpload(endpoint, headers, libraryName, fileName, folderName, fileData) {
              new Promise((resolve, reject) => {
                var digest = $("#__REQUESTDIGEST").val();
                $.ajax({
                  url: endpoint,
                  async: false,
                  method: "POST",
                  headers: headers,
                  data: fileData,
                  binaryStringRequestBody: true,
                  success: function(data) {},
                  error: err => reject(err.responseText)
                });
              });
            }

            请说明为什么上传的文件已损坏且大小小于或大于实际文件?

            提前致谢。

1 个答案:

答案 0 :(得分:1)

我遇到了与此代码相同的问题。我将convertFileToBlobChunks更改为仅返回ArrayBuffer

function convertFileToBlobChunks(result, chunkInfo) {
  var arrayBuffer = chunkInfo.method === 'finishupload' ? 
  result.slice(chunkInfo.offset) : result.slice(chunkInfo.offset, chunkInfo.offset + chunkInfo.length);

  return arrayBuffer;
}

我还从标题中删除了"Content-Type": "application/octet-stream"

这样做后上传得很好。