Узел: загрузка zip через запрос, Zip поврежден

Я использую отличную библиотеку Request для загрузки файлов в Node для небольшого инструмента командной строки, над которым я работаю. Запрос отлично работает для извлечения одного файла, без проблем, но он не работает для ZIP.

Например, я пытаюсь загрузить архив Twitter Bootstrap, который находится по адресу:

http://twitter.github.com/bootstrap/assets/bootstrap.zip

Соответствующая часть кода:

var fileUrl = "http://twitter.github.com/bootstrap/assets/bootstrap.zip";
var output = "bootstrap.zip";
request(fileUrl, function(err, resp, body) {
  if(err) throw err;
  fs.writeFile(output, body, function(err) {
    console.log("file written!");
  }
}

Я попытался установить кодировку "двоичный" тоже, но не повезло. Фактический размер почтового индекса составляет ~74 КБ, но при загрузке с помощью вышеуказанного кода он составляет ~134 КБ, и при двойном щелчке в Finder, чтобы извлечь его, я получаю сообщение об ошибке:

Невозможно извлечь "bootstrap" в "nodetest" (Ошибка 21 - каталог)

У меня такое ощущение, что это проблема кодирования, но я не уверен, куда идти дальше.

2 ответа

Решение

Да, проблема с кодировкой. Когда вы ждете, чтобы закончить весь перевод body по умолчанию приводится к строке. Ты можешь сказать request чтобы дать вам Buffer вместо этого, установив encoding возможность null:

var fileUrl = "http://twitter.github.com/bootstrap/assets/bootstrap.zip";
var output = "bootstrap.zip";
request({url: fileUrl, encoding: null}, function(err, resp, body) {
  if(err) throw err;
  fs.writeFile(output, body, function(err) {
    console.log("file written!");
  });
});

Еще одним более элегантным решением является использование pipe() чтобы направить ответ в файл для записи потока:

request('http://twitter.github.com/bootstrap/assets/bootstrap.zip')
  .pipe(fs.createWriteStream('bootstrap.zip'))
  .on('close', function () {
    console.log('File written!');
  });

А один лайнер всегда побеждает:)

pipe() возвращает целевой поток (в данном случае WriteStream), поэтому вы можете прослушать его close событие, чтобы получить уведомление, когда файл был написан.

Я искал функцию, которая запрашивает zip-файл и извлекает его без создания какого-либо файла на моем сервере, вот моя функция TypeScript, она использует модуль JSZIP и Request:

let bufs : any = [];
let buf : Uint8Array;
request
    .get(url)
    .on('end', () => {
        buf = Buffer.concat(bufs);

        JSZip.loadAsync(buf).then((zip) => {
            // zip.files contains a list of file
            // chheck JSZip documentation
            // Example of getting a text file : zip.file("bla.txt").async("text").then....
        }).catch((error) => {
            console.log(error);
        });
    })
    .on('error', (error) => {
        console.log(error);
    })
    .on('data', (d) => {
        bufs.push(d);
    })
Другие вопросы по тегам