Я делаю скрипт для автоматической загрузки файла резервной копии (на Backblaze) ...
Создаю скрипт, который загружает полный файл в const
, разбивает строку и загружает каждую часть, когда размер файлаувеличивается (с 1 до более 3 ГБ) мой скрипт вылетает.
Я пытался переписать скрипт полностью асинхронно.
Я пишу это:
async getFileInfoAndUploadPart(path, sizeChunk = 1024) {
const info = {
sha1: null,
size: 0,
partNumber: 0,
partSha1: {},
};
return new Promise(resolve => {
const shasumGlobal = crypto.createHash('sha1');
console.log(path, sizeChunk);
const input = fs.createReadStream(path);
input.on('readable', () => {
console.log('1');
let chunk;
while ((chunk = input.read(sizeChunk)) !== null) {
console.log('2');
const tempShasum = crypto.createHash('sha1');
shasumGlobal.update(chunk);
tempShasum.update(chunk);
info.partNumber += 1;
info.partSha1[info.partNumber] = tempShasum.digest('hex');
}
console.log('3');
info.sha1 = shasumGlobal.digest('hex');
resolve(info);
});
});
}
Но обещание разрешается до while
: / Какие правильные методычтобы сделать это, пока закончите, прежде чем вернуть мое обещание?
(я собираюсь вызвать асинхронную функцию для загрузки каждой части)
Редактировать
Наконец, я использую эти методы:
async getFileInfoAndUploadPart(path, sizeChunk = 1024, fileId = 'xxx') {
return new Promise(resolve => {
const info = {
fileId: fileId,
sha1: null,
size: 0,
partNumber: 0,
partSha1: {},
};
const input = fs.createReadStream(path, { highWaterMark: sizeChunk });
const shasumGlobal = crypto.createHash('sha1');
input.on('data', async dataChunk => {
const shasumPart = await crypto.createHash('sha1');
await shasumPart.update(dataChunk);
await shasumGlobal.update(dataChunk);
info.partNumber += 1;
info.partSha1[info.partNumber] = shasumPart.digest('hex');
});
input.on('end', () => {
info.sha1 = shasumGlobal.digest('hex');
resolve(info);
});
});
}
РЕДАКТИРОВАТЬ 2:
Код выше не работает хорошо ...
Во-первых, вам нужно сделатьпауза потока при воспроизведении данных и возобновление потока при обработке следующей части ...
Вторая ошибка: если вы попробуете этот код с 10-октетным файлом и используете 5-октановый блок...
Вы запускаете событие 'data' в первый раз => ok
Вы запускаете событие 'data' во второй раз => ok
Вы запускаетесобытие 'end' => ok ...
Но если вы хотите разделить поток на 3 части (Math.ceil (fileSize / chunkSize) => 4 + 4 + 2, толькопоследний номиналкороче)
Вы запускаете событие 'data' в первый раз => ok
Вы запускаете событие 'data' во второй раз => ok
Вы запускаете событие 'data' в третий раз, но вы достигаете конца потока, поэтому вы запускаете событие 'end' одновременно ...
Я не нашел ни одногорешение для запуска 'end' события только после того, как моя логика 'data' будет завершена ...
Так что я думаю, что предварительно вычисляю количество чанка и реализую свою логику 'end' в событии 'data'когда я в последний кусок ...