Javascript 将字节数组输出转换为Blob会损坏文件

Javascript 将字节数组输出转换为Blob会损坏文件,javascript,angularjs,api,ms-word,ms-office,Javascript,Angularjs,Api,Ms Word,Ms Office,我正在使用Office Javascript API使用Angular为Word编写外接程序 我想通过API检索Word文档,然后将其转换为文件并通过POST将其上载到服务器 我使用的代码与Microsoft为此用例提供的文档代码几乎相同: 服务器端点要求通过多部分表单发布上传,因此在创建$http调用时,我创建了一个FormData对象,在该对象上附加了文件(blob)和一些元数据 该文件正在传输到服务器,但当我打开它时,它已损坏,无法再通过Word打开 根据文档,Office.context

我正在使用Office Javascript API使用Angular为Word编写外接程序

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

我使用的代码与Microsoft为此用例提供的文档代码几乎相同:

服务器端点要求通过多部分表单发布上传,因此在创建$http调用时,我创建了一个FormData对象,在该对象上附加了文件(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}`);

                            }
                        }
                    );
                };
let sendFile=(fileContent)=>{
设blob=newblob([fileContent],{type:'application/vnd.openxmlformats officedocument.wordprocessingml.document'}),
fd=新FormData();
blob.lastModifiedDate=新日期();
append('file',blob,'upload_file_test403.docx');
fd.append('case_id',caseIdReducer.data());
$http.post('/file/create',fd{
请求:angular.identity,
标题:{“内容类型”:未定义}
})
.成功(()=>{
console.log('upload successed');
})
.错误(()=>{
console.log('upload failed');
});
};
总切片上的函数(docdataSlices){
让docdata=[];
for(设i=0;i{
如果(sliceResult.status===“成功”){
如果(!gotAllSlices){//未能获取所有切片,则无需继续。
返回;
}
//得到一个切片,将其存储在临时数组中。
//(或者你可以做其他事情,比如
//将其发送到第三方服务器。)
docdataSlices[sliceResult.value.index]=sliceResult.value.data;
如果(++切片接收===切片计数){
//所有切片均已收到。
closeAsync()文件;
总切片(docdataSlices);
}否则{
getSliceAsync(文件、++nextSlice、sliceCount、GotalSlices、docdataSlices、slicesReceived);
}
}否则{
gotallsices=false;
closeAsync()文件;
log(`getSliceAsync Error:${sliceResult.Error.message}`);
}
});
}
//用户单击按钮开始从Word检索文档并上载到服务器进程
ctrl.handleClick=()=>{
Office.context.document.getFileAsync(Office.FileType.Compressed,{sliceSize:65536/*64 KB*/},
(结果)=>{
如果(result.status===“成功”){
//如果getFileAsync调用成功,则
//result.value将返回有效的文件对象。
让myFile=result.value,
sliceCount=myFile.sliceCount,
slicesReceived=0,gotAllSlices=true,docdataSlices=[];
//获取文件切片。
getSliceAsync(myFile、0、sliceCount、gotAllSlices、docdataSlices、slicesReceived);
}否则{
log(`Error:${result.Error.message}`);
}
}
);
};
Pff!获取文件实例而不使用FileReader api有什么问题?来吧,微软

您应该将字节数组放入blob构造函数,在javascript中将二进制blob转换为字符串是一个坏主意,可能会导致“超出范围”错误或编码错误

就这样做吧

var byteArray = new Uint8Array(3)
byteArray[0] = 97
byteArray[1] = 98
byteArray[2] = 99
new Blob([byteArray])
如果区块是一个或一个blob/file实例。在这种情况下,您只需执行以下操作:

blob = new Blob([blob, chunk])

请。。。不要对它进行base64编码(~3倍大+更慢)

我最后用fileContent字符串完成了这项工作:

let bytes = new Uint8Array(fileContent.length);

for (let i = 0; i < bytes.length; i++) {
    bytes[i] = fileContent.charCodeAt(i);
}
如果我通过POST请求发送此文件,则文件不会损坏,可以通过Word正确打开。

let blob = new Blob([bytes], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
let bytes = new Uint8Array(docdata.length);
for (var i = 0; i < docdata.length; i++) {
    bytes[i] = docdata[i];
}