2016-09-14 3 views
1

Я использую API-интерфейс Office Javascript для написания надстройки для Word с помощью Angular.Преобразование вывода массива байтов в файл Blob corrupts

Я хочу получить документ Word через API, а затем преобразовать его в файл и загрузить его через POST на сервер.

кода я использую почти идентичен коду документации, что Microsoft предоставляет для этого случая использования: https://dev.office.com/reference/add-ins/shared/document.getfileasync#example---get-a-document-in-office-open-xml-compressed-format

Конечной сервер требуют добавлений быть вывешенными через многочастную форму, поэтому я создаю объект FormData, на котором Я добавляю файл (blob), а также некоторые метаданные при создании вызова $ http.

Файл передается на сервер, но когда я его открываю, он поврежден и не может быть открыт Word.

В соответствии с документацией функция Office.context.document.getFileAsync возвращает массив байтов. Однако результирующая переменная fileContent является строкой. Когда я console.log эту строку, кажется, это сжатые данные, как и должно быть.

Мое предположение: мне нужно выполнить некоторую предварительную обработку, прежде чем превращать строку в Blob. Но какая предварительная обработка? Base64-кодирование через atob, похоже, ничего не делает.

   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); 
} 

Я тогда приступают к возведению Blob с этими байтами:

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

Если я затем отправить это с помощью запроса POST, тыс e файл не искажен и может быть правильно открыт Word.

У меня все еще возникает ощущение, что этого можно добиться с меньшими усилиями. Если у кого-то есть лучшее решение, мне было бы очень интересно учиться.

0

Пфф! что не так с получением экземпляра файла, а не с помощью FileReader api? c'mon Microsoft!

Вы должны принять массив байтов и бросить его в конструктор двоичных объектов, превращая блоб в строку в JavaScript является плохой идеей, что может привести к «вне диапазона» ошибки или неправильного кодирования

просто делать что-то вместе с этим

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 закодировать его (~ 3x больше + медленнее)

+0

>> Pff! что не так с получением экземпляра файла, а не с помощью FileReader api? c'mon Microsoft! Разве я не знаю ... Очень смущает. Когда вы говорите, создайте Uint8Array, где вы вводите срезы? – Squrler

0

thx для вашего ответа, Uint8Array было решением. Просто небольшое улучшение, чтобы избежать создания строки:

let bytes = new Uint8Array(docdata.length); 
for (var i = 0; i < docdata.length; i++) { 
    bytes[i] = docdata[i]; 
} 
Смежные вопросы