将文件数组拆分为 N 个块
Split array of files in N chunks
我有一个文件数组,我必须根据文件大小将它分成块,这样:
[10MB image, 5MB image, 5MB image] 最大大小为 20MB 实际上不需要拆分,但 [10MB, 10MB, 15MB] 将拆分为 [10MB, 10MB] 和 [ 15MB]
然后我必须执行获取文件并将它们放入表单数据以将其发送到端点的功能。
我想要做的是 return 包含所需块的 FormData
数组。
我怎样才能做到这一点?
这是当前函数:
const newImagesToEndpoint = (newFiles: NewImagesInterface[]) => {
const newImages = new FormData();
newFiles.forEach(img => {
newImages.append('images[]', (img.file as unknown) as File);
});
return newImages;
};
这是我很快想到的算法。这是一个有点贪婪的算法,按大小降序排列,然后迭代排序后的数组,并将文件“打包”到具有剩余可用性的数组中。它最终将中间结果映射到仅包含块的数组。
注意: 显然你需要将其调整为 实际上 消耗你的文件数组并正确计算和比较文件大小。
const MAX_CHUNK_SIZE = 20;
const chunkFiles = (filesArray) =>
filesArray
.slice()
.sort((a, b) => b.size - a.size)
.reduce((chunks, file) => {
const chunk = chunks.find((chunk) => chunk.available >= file.size);
if (chunk) {
chunk.array.push(file);
chunk.available -= file.size;
} else {
chunks.push({
array: [file],
available: MAX_CHUNK_SIZE - file.size
});
}
return chunks;
}, [])
.map(({ array }) => array);
const filesToProcess = [
[{ size: 10 }, { size: 5 }, { size: 5 }],
[{ size: 10 }, { size: 10 }, { size: 15 }],
[{ size: 10 }, { size: 3 }, { size: 7 }, { size: 10 }, { size: 15 }]
];
filesToProcess.forEach((files, i) => {
const chunks = chunkFiles(files);
console.log(JSON.stringify(chunks));
});
这些文件块数组可以传递给您的 newImagesToEndpoint
实用程序。
你的问题不是很清楚。我理解您所说的拆分是指通过多个 http 调用从客户端发送到服务器,而不是拆分单个文件?
假设 NewImagesInterface
有一个 size: number
字段,那么是这样的吗?
function sendChunks(images: NewImagesInterface[], limit = 20e6): FormData[] {
const out: FormData[] = [], chunkSize = 0;
for(const img of images) {
if(img.size > limit)
throw new Error('each individual image must be < ' + limit);
if(!out.length || chunkSize + img.size > limit) {
chunkSize = 0;
out.push(new FormData[]);
}
out[out.length-1].append('images[]', (img.file as unknown) as File);
chunkSize += img.size;
return out;
};
另外请注意类型,毕竟这是打字稿的要点。如果你想输出一个 FormData
的数组,那么你的函数的 return 类型必须是 FormData[]
。这意味着您的函数将在某个时候构建和 return 一个数组。如果您这样想,从类型要求开始并将它们应用到您构建代码的方式中,它将帮助您提出解决方案。
我有一个文件数组,我必须根据文件大小将它分成块,这样:
[10MB image, 5MB image, 5MB image] 最大大小为 20MB 实际上不需要拆分,但 [10MB, 10MB, 15MB] 将拆分为 [10MB, 10MB] 和 [ 15MB]
然后我必须执行获取文件并将它们放入表单数据以将其发送到端点的功能。
我想要做的是 return 包含所需块的 FormData
数组。
我怎样才能做到这一点?
这是当前函数:
const newImagesToEndpoint = (newFiles: NewImagesInterface[]) => {
const newImages = new FormData();
newFiles.forEach(img => {
newImages.append('images[]', (img.file as unknown) as File);
});
return newImages;
};
这是我很快想到的算法。这是一个有点贪婪的算法,按大小降序排列,然后迭代排序后的数组,并将文件“打包”到具有剩余可用性的数组中。它最终将中间结果映射到仅包含块的数组。
注意: 显然你需要将其调整为 实际上 消耗你的文件数组并正确计算和比较文件大小。
const MAX_CHUNK_SIZE = 20;
const chunkFiles = (filesArray) =>
filesArray
.slice()
.sort((a, b) => b.size - a.size)
.reduce((chunks, file) => {
const chunk = chunks.find((chunk) => chunk.available >= file.size);
if (chunk) {
chunk.array.push(file);
chunk.available -= file.size;
} else {
chunks.push({
array: [file],
available: MAX_CHUNK_SIZE - file.size
});
}
return chunks;
}, [])
.map(({ array }) => array);
const filesToProcess = [
[{ size: 10 }, { size: 5 }, { size: 5 }],
[{ size: 10 }, { size: 10 }, { size: 15 }],
[{ size: 10 }, { size: 3 }, { size: 7 }, { size: 10 }, { size: 15 }]
];
filesToProcess.forEach((files, i) => {
const chunks = chunkFiles(files);
console.log(JSON.stringify(chunks));
});
这些文件块数组可以传递给您的 newImagesToEndpoint
实用程序。
你的问题不是很清楚。我理解您所说的拆分是指通过多个 http 调用从客户端发送到服务器,而不是拆分单个文件?
假设 NewImagesInterface
有一个 size: number
字段,那么是这样的吗?
function sendChunks(images: NewImagesInterface[], limit = 20e6): FormData[] {
const out: FormData[] = [], chunkSize = 0;
for(const img of images) {
if(img.size > limit)
throw new Error('each individual image must be < ' + limit);
if(!out.length || chunkSize + img.size > limit) {
chunkSize = 0;
out.push(new FormData[]);
}
out[out.length-1].append('images[]', (img.file as unknown) as File);
chunkSize += img.size;
return out;
};
另外请注意类型,毕竟这是打字稿的要点。如果你想输出一个 FormData
的数组,那么你的函数的 return 类型必须是 FormData[]
。这意味着您的函数将在某个时候构建和 return 一个数组。如果您这样想,从类型要求开始并将它们应用到您构建代码的方式中,它将帮助您提出解决方案。