将字节数组输出转换为 Blob 会损坏文件 [英] Converting byte array output into Blob corrupts file

查看:21
本文介绍了将字节数组输出转换为 Blob 会损坏文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Office Javascript API 使用 Angular 编写 Word 插件.

I am using the Office Javascript API to write an Add-in for Word using Angular.

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

I want to retrieve the Word document through the API, then convert it to a file and upload it via POST to a server.

我使用的代码与微软为此用例提供的文档代码几乎相同:https://dev.office.com/reference/add-ins/shared/document.getfileasync#示例---get-a-document-in-office-open-xml-compressed-format

The code I am using is nearly identical to the documentation code that Microsoft provides for this use case: https://dev.office.com/reference/add-ins/shared/document.getfileasync#example---get-a-document-in-office-open-xml-compressed-format

服务器端点要求通过多部分表单发布上传,因此我创建了一个 FormData 对象,在创建 $http 调用时,我将文件(一个 blob)以及一些元数据附加到该对象上.

The server endpoint requires uploads to be POSTed through a multipart form, so I create a FormData object on which I append the file (a blob) as well as some metadata, when creating the $http call.

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

The file is being transmitted to the server, but when I open it, it has become corrupted and it can no longer be opened by Word.

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

According to the documentation, the Office.context.document.getFileAsync function returns a byte array. However, the resulting fileContent variable is a string. When I console.log this string it seems to be compressed data, like it should be.

我的猜测是我需要在将字符串转换为 Blob 之前进行一些预处理.但是哪个预处理?通过 atob 进行 Base64 编码似乎没有任何作用.

My guess is I need to do some preprocessing before turning the string into a Blob. But which preprocessing? Base64 encoding through atob doesn't seem to be doing anything.

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

                            }
                        }
                    );
                };

推荐答案

我最终使用了 fileContent 字符串:

I ended up doing this with the fileContent string:

let bytes = new Uint8Array(fileContent.length);

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

然后我继续用这些字节构建 Blob:

I then proceed to build the Blob with these bytes:

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

如果我随后通过 POST 请求发送此文件,则该文件不会损坏并且可以通过 Word 正确打开.

If I then send this via a POST request, the file isn't mangled and can be opened correctly by Word.

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

I still get the feeling this can be achieved with less hassle / less steps. If anyone has a better solution, I'd be very interested to learn.

这篇关于将字节数组输出转换为 Blob 会损坏文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆