2016-09-14 76 views
1

我正在使用Office JavaScript API为使用Angular的Word编写加载项。将字节数组输出转换为Blob损坏文件

我想通过API检索Word文档,然后将其转换为文件并通过POST将其上传到服务器。

我使用的代码几乎等同于文档的代码,微软提供了这个用例:https://dev.office.com/reference/add-ins/shared/document.getfileasync#example---get-a-document-in-office-open-xml-compressed-format

服务器端点都需要上传到通过多形式发布,所以我创建在其上FORMDATA对象在创建$ http调用时,我追加文件(blob)以及一些元数据。

该文件正在传输到服务器,但是当我打开它时,它已损坏,Word无法再打开它。

根据文档,Office.context.document.getFileAsync函数返回一个字节数组。但是,生成的fileContent变量是一个字符串。当我console.log这个字符串它似乎是压缩数据,就像它应该。

我的猜测是我需要做一些预处理之前,将字符串变成一个Blob。但是哪个预处理?通过atob进行Base64编码似乎没有做任何事情。

   let sendFile = (fileContent) => { 

        let blob = new Blob([fileContent], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }), 
         fd = new FormData(); 

        blob.lastModifiedDate = new Date(); 

        fd.append('file', blob, 'uploaded_file_test403.docx'); 
        fd.append('case_id', caseIdReducer.data()); 

        $http.post('/file/create', fd, { 
         transformRequest: angular.identity, 
         headers: { 'Content-Type': undefined } 
        }) 
        .success(() => { 

         console.log('upload succeeded'); 

        }) 
        .error(() => { 
         console.log('upload failed'); 
        }); 

       }; 


       function onGotAllSlices(docdataSlices) { 

        let docdata = []; 

        for (let i = 0; i < docdataSlices.length; i++) { 
         docdata = docdata.concat(docdataSlices[i]); 
        } 

        let fileContent = new String(); 

        for (let j = 0; j < docdata.length; j++) { 
         fileContent += String.fromCharCode(docdata[j]); 
        } 

        // Now all the file content is stored in 'fileContent' variable, 
        // you can do something with it, such as print, fax... 

        sendFile(fileContent); 

       } 

       function getSliceAsync(file, nextSlice, sliceCount, gotAllSlices, docdataSlices, slicesReceived) { 
        file.getSliceAsync(nextSlice, (sliceResult) => { 

         if (sliceResult.status === 'succeeded') { 
          if (!gotAllSlices) { // Failed to get all slices, no need to continue. 
           return; 
          } 

          // Got one slice, store it in a temporary array. 
          // (Or you can do something else, such as 
          // send it to a third-party server.) 
          docdataSlices[sliceResult.value.index] = sliceResult.value.data; 
          if (++slicesReceived === sliceCount) { 
           // All slices have been received. 
           file.closeAsync(); 

           onGotAllSlices(docdataSlices); 

          } else { 
           getSliceAsync(file, ++nextSlice, sliceCount, gotAllSlices, docdataSlices, slicesReceived); 
          } 
         } else { 

          gotAllSlices = false; 
          file.closeAsync(); 
          console.log(`getSliceAsync Error: ${sliceResult.error.message}`); 
         } 
        }); 
       } 

       // User clicks button to start document retrieval from Word and uploading to server process 
       ctrl.handleClick = () => { 

        Office.context.document.getFileAsync(Office.FileType.Compressed, { sliceSize: 65536 /*64 KB*/ }, 
         (result) => { 
          if (result.status === 'succeeded') { 

           // If the getFileAsync call succeeded, then 
           // result.value will return a valid File Object. 
           let myFile = result.value, 
            sliceCount = myFile.sliceCount, 
            slicesReceived = 0, gotAllSlices = true, docdataSlices = []; 

           // Get the file slices. 
           getSliceAsync(myFile, 0, sliceCount, gotAllSlices, docdataSlices, slicesReceived); 

          } else { 

           console.log(`Error: ${result.error.message}`); 

          } 
         } 
        ); 
       }; 

回答

1

我结束了与fileContent字符串这样做:

let bytes = new Uint8Array(fileContent.length); 

for (let i = 0; i < bytes.length; i++) { 
    bytes[i] = fileContent.charCodeAt(i); 
} 

然后我继续建立与这些字节斑点:

let blob = new Blob([bytes], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); 

如果我然后通过POST请求,第发送此e文件没有被损坏,并且可以通过Word正确打开。

我仍然觉得这可以用更少的麻烦/更少的步骤来实现。如果有人有更好的解决方案,我会非常感兴趣的学习。

0

PFF!获取File实例而不使用FileReader API有什么问题?来吧微软!

你应该采取的字节数组,把它扔进了一滴构造,在javascript打开一个二进制的blob串是一个坏主意,可导致“超出范围”的错误或不正确编码

刚做一些与此

var byteArray = new Uint8Array(3) 
byteArray[0] = 97 
byteArray[1] = 98 
byteArray[2] = 99 
new Blob([byteArray]) 

沿着如果块是typed arrays的实例或BLOB /文件的一个实例。在这种情况下,你可以这样做:

blob = new Blob([blob, chunk]) 

并请...不要使用Base64编码它(〜3倍大+慢)

+0

>> Pff!获取File实例而不使用FileReader API有什么问题?来吧微软! 难道我不知道...非常混乱。 当你说创建一个Uint8Array,你在哪里输入切片? – Squrler

0

thx为您的答案,Uint8Array是解决方案。只是稍加改进,以避免创建字符串:

let bytes = new Uint8Array(docdata.length); 
for (var i = 0; i < docdata.length; i++) { 
    bytes[i] = docdata[i]; 
} 
相关问题