2017-01-22 5 views
0

Я пытаюсь загрузить файл MP4 удаленно с помощью HTTP GET-запроса. Когда HTTP GET-ответ загружается в файл, файл записывается отлично (~ 3 МБ).Node.js - createWriteStream пишет другой файл, чем writeFile

request.get('http://url.tld/video.mp4').pipe(fs.createWriteStream('video.mp4')) 

Однако, когда HTTP GET тело ответа записывается функцией fs.writeFileSync, он создает файл большего размера (~ 7 МБ), и она не может быть выполнена, так как он поврежден.

request.get('http://url.tld/video.mp4', function(err, res, body){ 
    fs.writeFileSync('./video.mp4', body) 
}); 

Почему это происходит? Использует ли функция pipe правильную кодировку для соответствующего файла?

ответ

0

Да, это кодировка. Во время записи в файл вместо потока в потоке поток тела преобразуется в объект Buffer с кодировкой utf8 перед записью в файл.

Просто простой эксперимент, подтверждающий это.

Проверьте длину загруженного потока

var streamlen = 0; 

request.get('http://url.tld/video.mp4') 
.on('data', function(data){ 
    streamlen = streamlen + data.length; 
}) 
.on('end',function(){ 
    console.log("Downloaded stream length is: " + streamlen); 
}) 

//This should output your actual size of the mp4 file 

Проверить длину тела

request.get('http://url.tld/video.mp4', function(err, res, body){ 
    console.log("The body length of the response in utf8 is: " + Buffer.from(body).length); 
    console.log("The body length of the response in ascii is: " + Buffer.from(body,'ascii').length); 
}); 

//This would be approximately double in utf8 and a little less than original bytes in ascii 

Примечание:

Это не то, что трубопровод делает право кодирование, его просто то, что трубопровод делает не делать кодирование. Он просто передает поток, как есть.

+0

Похоже, проблема заключается в типе тела ответа. Это строка вместо буфера. – Avi

+0

Да. Но я не мог понять, если не отладить обратный путь. Легче доказывать противоречие, а не читать всю библиотеку 'request' :) – user3151330

0

Проблема заключается в том, что, получив ответ следующим образом, тип body представляет собой кодировку UTF-8, закодированную вместо буфера.

request.get('http://url.tld/video.mp4', function(err, res, body){ 
     fs.writeFileSync('./video.mp4', body) 
    }); 

Согласно документации библиотеки запросу:

кодирование - кодирование для использования на setEncoding данных ответа. Если null, тело возвращается как буфер. Все остальное (включая значение по умолчанию undefined) будет передано как параметр кодирования на toString() (это означает, что по умолчанию это utf8). (Примечание: если вы ожидаете двоичные данные, вы должны установить кодировку:. Нуль)

Решение было бы передать «кодирование» аргумент опции объекта в запросе следующим образом:

request.get('http://url.tld/video.mp4', {encoding: null}, function(err, res, body){ 
    fs.writeFileSync('./video.mp4', body) 
});