Javascript 使用node.js下载大文件,避免高内存消耗
我正试图创建一个文件下载程序作为后台服务,但是当计划一个大文件时,它首先被放入内存,然后在下载结束时,文件被写入磁盘 考虑到我可能同时下载了很多文件,我如何使文件逐渐写入磁盘保留内存 以下是我使用的代码:Javascript 使用node.js下载大文件,避免高内存消耗,javascript,node.js,Javascript,Node.js,我正试图创建一个文件下载程序作为后台服务,但是当计划一个大文件时,它首先被放入内存,然后在下载结束时,文件被写入磁盘 考虑到我可能同时下载了很多文件,我如何使文件逐渐写入磁盘保留内存 以下是我使用的代码: var sys = require("sys"), http = require("http"), url = require("url"), path = require("path"), fs = require("fs"), events = re
var sys = require("sys"),
http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs"),
events = require("events");
var downloadfile = "http://nodejs.org/dist/node-v0.2.6.tar.gz";
var host = url.parse(downloadfile).hostname
var filename = url.parse(downloadfile).pathname.split("/").pop()
var theurl = http.createClient(80, host);
var requestUrl = downloadfile;
sys.puts("Downloading file: " + filename);
sys.puts("Before download request");
var request = theurl.request('GET', requestUrl, {"host": host});
request.end();
var dlprogress = 0;
setInterval(function () {
sys.puts("Download progress: " + dlprogress + " bytes");
}, 1000);
request.addListener('response', function (response) {
response.setEncoding('binary')
sys.puts("File size: " + response.headers['content-length'] + " bytes.")
var body = '';
response.addListener('data', function (chunk) {
dlprogress += chunk.length;
body += chunk;
});
response.addListener("end", function() {
fs.writeFileSync(filename, body, 'binary');
sys.puts("After download finished");
});
});
您不应该将内容保存在
“data”
事件侦听器中的内存中,而应该以追加模式写入文件。我将回调更改为:
request.addListener('response', function (response) {
var downloadfile = fs.createWriteStream(filename, {'flags': 'a'});
sys.puts("File size " + filename + ": " + response.headers['content-length'] + " bytes.");
response.addListener('data', function (chunk) {
dlprogress += chunk.length;
downloadfile.write(chunk, encoding='binary');
});
response.addListener("end", function() {
downloadfile.end();
sys.puts("Finished downloading " + filename);
});
});
这非常有效。下载大文件时,请使用
fs.write
而不是writeFile
,因为它将覆盖以前的内容
function downloadfile(res) {
var requestserver = http.request(options, function(r) {
console.log('STATUS: ' + r.statusCode);
console.log('HEADERS: ' + JSON.stringify(r.headers));
var fd = fs.openSync('sai.tar.gz', 'w');
r.on('data', function (chunk) {
size += chunk.length;
console.log(size+'bytes received');
sendstatus(res,size);
fs.write(fd, chunk, 0, chunk.length, null, function(er, written) {
});
});
r.on('end',function(){
console.log('\nended from server');
fs.closeSync(fd);
sendendstatus(res);
});
});
}
请求包是否适合您的使用 它允许您执行以下操作:
request(downloadurl).pipe(fs.createWriteStream(downloadtohere))
使用卡特·科尔建议的流。下面是一个更完整的示例
var inspect = require('eyespect').inspector();
var request = require('request');
var filed = require('filed');
var temp = require('temp');
var downloadURL = 'http://upload.wikimedia.org/wikipedia/commons/e/ec/Hazard_Creek_Kayaker.JPG';
var downloadPath = temp.path({prefix: 'singlePageRaw', suffix: '.jpg'});
var downloadFile = filed(downloadPath);
var r = request(downloadURL).pipe(downloadFile);
r.on('data', function(data) {
inspect('binary data received');
});
downloadFile.on('end', function () {
inspect(downloadPath, 'file downloaded to path');
});
downloadFile.on('error', function (err) {
inspect(err, 'error downloading file');
});
您可能需要安装模块,您可以通过
npm安装已存档的请求视野温度
查看:
我们不是更喜欢setEncoding(null)而不是binary吗?
{'flags':'a'}
会将数据附加到文件中,如果它已经存在的话,您很可能会共享最终结果?我正在寻找这样的东西…我试图实现一个功能,以遵循302重定向,但我不认为它的工作正常。也许你可以试试。就是这样:如果不等待回调,fs.write是不安全的。您应该使用WriteStream。最好只将res
管道传输到可写文件流。没有理由使用eyespect、Field或temp。这个例子很好,但看起来有些臃肿。你甚至不需要请求这个。只需从http.get或正在使用的任何东西中导入res
。它正好在4gb时崩溃,您知道为什么以及如何让它下载高达10gb的大型文件吗?
// shorthand syntax, buffered response
http.get('http://localhost/get', function (err, res) {
if (err) throw err;
console.log(res.code, res.headers, res.buffer.toString());
});
// save the response to 'myfile.bin' with a progress callback
http.get({
url: 'http://localhost/get',
progress: function (current, total) {
console.log('downloaded %d bytes from %d', current, total);
}
}, 'myfile.bin', function (err, res) {
if (err) throw err;
console.log(res.code, res.headers, res.file);
});