嗯,我有以下功能和用法,但无法弄清楚为什么它说偏移量超出范围。
我的功能:
function zip(files, zipFileName) {
const zipData = [];
files.forEach((file) => {
const content = new TextEncoder().encode(file.content);
zipData.push({
name: file.name,
content,
contentLength: content.length
});
});
const centralDirectory = [];
let currentOffset = 0;
zipData.forEach((file) => {
centralDirectory.push({
name: file.name,
offset: currentOffset,
contentLength: file.contentLength
});
currentOffset += file.contentLength;
});
const zipArray = [];
zipData.forEach((file) => {
const header = new Uint8Array([
0x50, 0x4b, 0x03, 0x04, // local file header signature
0x0A, 0x00, // version needed to extract
0x00, 0x00, // general purpose bit flag
0x00, 0x00, // compression method
0x00, 0x00, 0x00, 0x00, // file modification time
0x00, 0x00, 0x00, 0x00, // file modification date
0x00, 0x00, 0x00, 0x00, // CRC-32
0x00, 0x00, 0x00, 0x00, // compressed size
0x00, 0x00, 0x00, 0x00, // uncompressed size
file.name.length, 0x00 // file name length
]);
const headerArray = new Uint8Array(header.length + file.name.length);
headerArray.set(header);
headerArray.set(new TextEncoder().encode(file.name), header.length);
const content = new Uint8Array(file.content);
const fileEntry = new Uint8Array(headerArray.length + content.length);
fileEntry.set(headerArray);
fileEntry.set(content, headerArray.length);
zipArray.push(fileEntry);
});
const centralDirectoryArray = [];
centralDirectory.forEach((file) => {
const header = new Uint8Array([
0x50, 0x4b, 0x01, 0x02, // central file header signature
0x0A, 0x00, // version made by
0x0A, 0x00, // version needed to extract
0x00, 0x00, // general purpose bit flag
0x00, 0x00, // compression method
0x00, 0x00, 0x00, 0x00, // file modification time
0x00, 0x00, 0x00, 0x00, // file modification date
0x00, 0x00, 0x00, 0x00, // CRC-32
0x00, 0x00, 0x00, 0x00, // compressed size
0x00, 0x00, 0x00, 0x00, // uncompressed size
file.name.length, 0x00, // file name length
0x00, 0x00, // extra field length
0x00, 0x00, // file comment length
0x00, 0x00, // disk number start
0x00, 0x00, // internal file attributes
0x00, 0x00, 0x00, 0x00, // external file attributes
file.currentOffset & 0xFF, // relative offset of local header (lo)
(file.currentOffset >> 8) & 0xFF, // relative offset of local header (hi)
]);
const headerArray = new Uint8Array(header.length + file.name.length);
headerArray.set(header);
headerArray.set(new TextEncoder().encode(file.name), header.length);
centralDirectoryArray.push(headerArray);
});
const endOfCentralDirectory = new Uint8Array([
0x50, 0x4b, 0x05, 0x06, // end of central directory signature
0x00, 0x00, 0x00, 0x00, // number of this disk
0x00, 0x00, 0x00, 0x00, // number of the disk with the start of the central directory
centralDirectoryArray.length & 0xFF, // total number of entries in the central directory on this disk (lo)
(centralDirectoryArray.length >> 8) & 0xFF, // total number of entries in the central directory on this disk (hi)
centralDirectoryArray.length & 0xFF, // total number of entries in the central directory (lo)
(centralDirectoryArray.length >> 8) & 0xFF, // total number of entries in the central directory (hi)
centralDirectoryArray.reduce((acc, entry) => acc + entry.length, 0) & 0xFFFFFFFF, // size of the central directory (lo)
((centralDirectoryArray.reduce((acc, entry) => acc + entry.length, 0) >> 8) & 0xFFFFFFFF) & 0xFF, // size of the central directory (hi)
(currentOffset & 0xFFFFFFFF) & 0xFF, // offset of start of central directory with respect to the starting disk number (lo)
((currentOffset & 0xFFFFFFFF) >> 8) & 0xFF, // offset of start of central directory with respect to the starting disk number (hi)
0x00, 0x00 // .zip file comment length
]);
const zipFile = new Uint8Array(zipArray.reduce((acc, entry) => acc + entry.length, 0) + centralDirectoryArray.reduce((acc, entry) => acc + entry.length, 0) + endOfCentralDirectory.length);
zipArray.forEach((entry) => {
zipFile.set(entry, currentOffset);
currentOffset += entry.length;
});
centralDirectoryArray.forEach((entry) => {
zipFile.set(entry, currentOffset);
currentOffset += entry.length;
});
zipFile.set(endOfCentralDirectory, currentOffset);
const zipBlob = new Blob([zipFile], { type: 'application/zip' });
const link = document.createElement('a');
link.href = window.URL.createObjectURL(zipBlob);
link.download = zipFileName;
link.click();
return zipBlob;
}
我这样使用它:
const files = [
{
name: 'file1.txt',
content: 'This is the content of file 1.',
},
{
name: 'file2.txt',
content: 'This is the content of file 2.',
}
];
// Zip the files
const zipFileName = 'Archive.zip';
zip(files, zipFileName);
但是浏览器抛出这个错误
Uncaught RangeError: offset is out of bounds
at Uint8Array.set (<anonymous>)
at file.js:228:21
at Array.forEach (<anonymous>)
at File.zip (file.js:227:31)
at index.js:17:19
我没有尝试过任何东西,但我需要帮助,伙计们!!
我该如何解决它,或者是函数中的错误
zip
。
如果是bug,你能告诉我哪里吗!!
我怀疑问题在于,当您创建
Uint8Array
时,您使用类似 + file.name.length
的内容来指定长度。但是当你存储到数组中时,你使用 Textencoder.encode(file.name)
。编码器返回的数据可能比原始名称长,因此这里尝试设置在数组之外。使用编码名称的长度。更改代码如下
const headerArray = new Uint8Array(header.length + file.name.length);
headerArray.set(header);
headerArray.set(new TextEncoder().encode(file.name), header.length);
到
const encodedName = new TextEncoder().encode(file.name);
const headerArray = new Uint8Array(header.length + encodedName.length);
headerArray.set(header);
headerArray.set(encodedName, header.length);