2016-09-14 74 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]; 
} 
相關問題