У меня есть два сервера, которые общаются друг с другом. Server1 запрашивает части файла у Server2 и сохраняет полученные данные в один файл. Предполагается, что Server2 получит каждый из этих запросов и создаст поток данных по конвейеру.
Предположим, что файлы, хранящиеся (каталог) на Сервере 2, выглядят следующим образом
bigfile.gz
bigfile.gz.part-0
bigfile.gz.part-1
bigfile.gz.part-2
......
Таким образом, Server1 отправит запрос на часть 0, затем на часть 1 и так далее на Server2. Отсюда и использование цикла для выполнения запросов.
Сервер 1 (фрагмент кода)
for (var i in requestInfo['blockName']) {
var blockName = i;
var IP = requestInfo['blockName'][i][0];
var fileData = JSON.stringify({
blockName: blockName,
fileName: requestInfo['fileName']
});
makeRequest(fileData, IP);
console.info(counter);
}
function makeRequest(fileData, IP) {
var options = {
host: IP,
port: 5000,
path: '/read',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
var req = http.request(options, function(res) {
var data = '';
res.on('data', function(chunk) {
data += chunk;
});
res.on('end', function() {
console.info(data.length);
//fs.appendFileSync(fileName, data);
var writeStream = fs.createWriteStream(fileName, { "flags": 'a' });
writeStream.write(data);
writeStream.end();
});
});
req.write(fileData);
req.end();
}
Сервер 2 (фрагмент кода)
app.post('/read', function(req, res) {
var dataBody = req.body;
fs.createReadStream(dataBody.fileName + '/' + dataBody.blockName).pipe(res);
});
Тот, что выше, работает, когда я тестирую его с текстовым файлом размером 100 МБ. Но это не удается, когда у меня есть файл .gz размером 1 ГБ или даже когда я тестирую его с файлом .zip, выходной файл .zip, созданный на стороне Сервера 1, имеет неправильный размер.
Я не уверен, что я здесь делаю не так, или это альтернативное решение
Обновлено:
Также мой Server1 вылетает при работе с большим файлом .gz размером 1 ГБ
Я перешел по вашим предложенным ссылкам, но вижу эту ошибку TypeError: аргумент «список» должен быть массивом буферов, даже если я передаю массив
@Jamiec теперь работает, я устанавливал res.setencoding (..), это не нужно. Но файл размером 1 ГБ вызывает сбой приложения
Вы должны передавать ответ прямо в файл, таким образом вы сохраните потребление памяти на минимальном уровне.
@ alex-rokabilis не могли бы вы привести пример



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Основная проблема здесь в том, что вы обрабатываете свои данные как строку, добавляя к ней chunks.
Переписав это, должно быть
var req = http.request(options, function(res) {
var data = [];
res.on('data', function(chunk) {
data.push(chunk);
});
res.on('end', function() {
fs.writeFile(fileName, Buffer.concat(data), function() {
console.info("write end")
});
});
});
Таким образом, мы создаем массив двоичных фрагментов большой, и по завершении загрузки записываем конкатенацию всех фрагментов в файл.
Но обратите внимание на слово большой
Если вы будете придерживаться этой реализации, вы рискуете получить нехватку памяти, особенно если вы имеете дело с большими (> 500 МБ) файлами.
Потоки на помощь
var req = https.request(options, function(res) {
res.pipe(fs.createWriteStream(fileName)).on("close", function() {
console.info("write end");
});
});
При использовании указанной выше реализации объем памяти должен оставаться низким. Потому что в тот момент, когда вы получаете определенный объем данных из загрузки, вы записываете их в файл. Таким образом, вы никогда не сохраните весь файл в памяти программы.
Вы обрабатываете все содержимое как текст - вот почему он отлично работает с текстовым файлом, но не с двоичным файлом! Нашел это, который может вам помочь. Также, вероятно, ваш ответ - это.