Node.js中fsモジュール使用例--ファイル読み書き
19096 ワード
Node.jsファイルI/Oはシンプルパッケージの標準POSIX関数から提供される[1]です.fs(File System)はNode.jsの内蔵モジュールです.
readFileを使ってファイルのサンプルを読む[2]
createWriteStreamを使ってファイルのサンプルを作成する[2]
ファイルコピー例[3]
コード例[7]
Aynchronous Copy
stream version in one line[8]
多くの場合、ファイルを読むスピードはファイルを書くより速いです.そうすると、大量のデータがメモリに蓄積され、読みたいファイルが大きいと、メモリを使う量が多すぎて、Node.jsプロセスが崩壊することになります.読み取り速度が私たちの期待した値を超えた場合は、PAuse()を実行して一旦停止し、タイミングが合ったら再度reume()を実行して[5]を再開します.
「RFC 1867-Form-based File Upload in HTML」プロトコルに従って、Node.jsを使ってファイルアップロードを実現します.
ブラウザでフォームを使ってファイルをアップロードするときに使うパケットのフォーマットは以下の通りです.
大ファイルのダウンロード例[4]
大きなファイルのダウンロードと断点継続の基本原理は、ファイルのダウンロードが切断された後です.クライアントがサーバ側に要求を続けると、http要求のヘッダファイルには一つのパラメータ「Range」が追加され、現在ダウンロードされているファイルが切断されている位置を表示します.
Node.js中fsモジュールのisfile()関数使用例
[1]http://nodejs.cn/api/fs [2]http://javabeat.net/nodejs-read-write-file/ [3]https://segmentfault.com/a/1190000000519006[4]http://www.cnblogs.com/fengmk2/archive/2011/08/16/2140460.html[5]http://morning.work/page/2015-07/read_and_write_big_file_同前nodejs.[6]https://cnodejs.org/topic/4f5b47c42373009b5c04e9cb[7]http://procbits.com/2011/11/15/synchronous-file-copy-in-node-js[8]http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js[9]http://www.aichengxu.com/javascript/24609788.htm
const fs = require('fs');
このモジュールを使用します fsモジュールのすべてのAPIは、非同期の形態を有する.非同期形式は常に最終パラメータとしてフィードバックを完了する.フィードバックを完了するパラメータは具体的な方法に依存するが、最初のパラメータは常に異常を残している.操作が成功すれば、最初のパラメータはnullまたはundefinedになります.同期形式を使うと、どの異常もすぐに投げ出されます.try/catchを使用して異常を処理したり、上に泡を発生させたりすることができます.非同期APIを使用すると、関数の呼び出し順序が保証されません.以下のコードの中で、ファイル名を変更し、fs.statを使って名前変更操作結果を確認します.非同期APIを使用すると、fs.statは、fs.renameを起動する前に実行されるかもしれない[1].fs.rename('/tmp/hello', '/tmp/world', function(err){
if (err) throw err;
console.log('renamed complete');
});
fs.stat('/tmp/world', function(err, stats){
if (err) throw err;
console.log(`stats: ${JSON.stringify(stats)}`);
});
の正しいやり方は、一連のコールバック関数を使用してAPI呼び出し順序を保証することである.fs.rename('/tmp/hello', '/tmp/world', function(err){
if (err) throw err;
fs.stat('/tmp/world', function(err, stats){
if (err) throw err;
console.log(`stats: ${JSON.stringify(stats)}`);
});
});
ファイルの読み書きreadFileを使ってファイルのサンプルを読む[2]
var fs = require('fs');
var readFileName = './foo.txt';
var writeFileName = './target.txt';
/** Using the readFile API - Asynchronous */
fs.readFile( readFileName, "utf8", function(err, data){
if ( err ){ throw err;}
console.log("Reading file asynchronously");
console.log(data);
});
readFileSyncを使ってファイルのサンプルを読む[2]var fs = require('fs');
var readFileName = './foo.txt';
var writeFileName = './target.txt';
/** Using the readFile API - Asynchronous */
console.log("Reading file synchronously");
var fileData = fs.readFileSync( readFileName, "utf8");
console.log(fileData);
ReadStreamを使ってファイルのサンプルを読む[2]var fs = require('fs');
var readFileName = './foo.txt';
var writeFileName = './target.txt';
/** Reading file using ReadStream API */
//Creating a stream out of the file
var readStreamObject = fs.createReadStream( readFileName, { flags: 'r',
encoding:"utf8",
fd: null,
mode: 0666,
autoClose: true
});
//Setting up event handlers on the stream object
//readable - this event is fired when data can be read from stream
readStreamObject.on('readable', function(){
console.log("*** Reading from file using ReadStream");
});
//data - this event is fired when data is available to be read from stream
readStreamObject.on('data', function(data){
console.log(data);
});
writeFileSyncを使ってファイルのサンプルを作成する[2]var fs = require('fs');
var readFileName = './foo.txt';
var writeFileName = './target.txt';
fs.writeFileSync( writeFileName, "Writing to a file synchronously from node.js", {"encoding":'utf8'});
console.log("*** File written successfully");
//Now reading the same file to confirm data written
fs.readFile( writeFileName, "utf8", function(err, data){
if ( err ){ throw err;}
console.log("*** Reading just written file");
console.log(data);
});
writeFileを使ってファイルのサンプルを作成する[2]var fs = require('fs');
var readFileName = './foo.txt';
var writeFileName = './target.txt';
fs.writeFile( writeFileName, "Writing to a file from node.js", {"encoding":'utf8'}, function(err){
if ( err ) { throw err; }
console.log("*** File written successfully");
//Now reading the same file to confirm data written
fs.readFile( writeFileName, "utf8", function(err, data){
if ( err ){ throw err;}
console.log("*** Reading just written file");
console.log(data);
});
});
何回も同じファイルにfs.writeを使っていますが、まだ返事を待っていないので、安全ではありません.fs.reate WriteStream[1]を使うことをオススメします. . createWriteStreamを使ってファイルのサンプルを作成する[2]
var fs = require('fs');
var readFileName = './foo.txt';
var writeFileName = './target.txt';
//Create a stream with the required path
var writeStreamObject = fs.createWriteStream( writeFileName );
//write to the stream using the API
writeStreamObject.write("Writing to a file using WriteStream", "utf8");
//Now read the same file to verify that the contents have been successfully written
fs.readFile( writeFileName, "utf8", function(err, data){
if ( err ){ throw err;}
console.log("*** Reading the recently written file");
console.log(data);
});
ファイルコピーファイルコピー例[3]
var fs = require('fs'),
path = require('path'),
out = process.stdout;
var stat
var filePath = './foo.mkv';
var readStream = fs.createReadStream(filePath);
var writeStream = fs.createWriteStream('file.mkv');
try {
stat = fs.statSync(filePath);
console.log("File exists.");
}
catch (e) {
if (e.code == 'ENOENT') {
console.log("File does not exist.");
//return false;
}
console.log("Exception fs.statSync (" + filePath + "): " + e);
// console.log(filePath + " does not exist.");
}
var totalSize = stat.size;
var passedLength = 0;
var lastSize = 0;
var startTime = Date.now();
readStream.on('data', function(chunk) {
passedLength += chunk.length;
if (writeStream.write(chunk) === false) {
readStream.pause();
}
});
readStream.on('end', function() {
writeStream.end();
});
writeStream.on('drain', function() {
readStream.resume();
});
setTimeout(function show() {
var percent = Math.ceil((passedLength / totalSize) * 100);
var size = Math.ceil(passedLength / 1000000);
var diff = size - lastSize;
lastSize = size;
out.clearLine();
out.cursorTo(0);
out.write(' ' + size + 'MB, ' + percent + '%, :' + diff * 2 + 'MB/s');
if (passedLength < totalSize) {
setTimeout(show, 500);
} else {
var endTime = Date.now();
console.log();
console.log(' :' + (endTime - startTime) / 1000 + ' 。');
}
}, 500);
Synch ronous Copyコード例[7]
copyFileSync = (srcFile, destFile)
function copyFileSync(srcFile, destFile) {
var BUF_LENGTH = 64*1024
var buff = new Buffer(BUF_LENGTH)
var fdr = fs.openSync(srcFile, 'r')
var fdw = fs.openSync(destFile, 'w')
var bytesRead = 1
var pos = 0
while( bytesRead > 0 )
{
bytesRead = fs.readSync(fdr, buff, 0, BUF_LENGTH, pos)
fs.writeSync(fdw,buff,0,bytesRead)
pos += bytesRead
}
fs.closeSync(fdr);
fs.closeSync(fdw);
}
Results of testing influnce of the buffer size for time consumpation shows that there is a lower limitation of the parameter. For one file about 300 MB,the coping processs with various buffer sizes,which over 2 KB、take roughly simiar time. If the buffer is lower than 2 KB、however、time computation would increase significantly. Aynchronous Copy
stream version in one line[8]
var fs = require('fs');
fs.createReadStream('test.log').pipe(fs.createWriteStream('newLog.log'));
stream version with errors handling provided by Mike Shilling[8]function copyFile(source, target, cb) {
var cbCalled = false;
var rd = fs.createReadStream(source);
rd.on("error", function(err) {
done(err);
});
var wr = fs.createWriteStream(target);
wr.on("error", function(err) {
done(err);
});
wr.on("close", function(ex) {
done();
});
rd.pipe(wr);
function done(err) {
if (!cbCalled) {
cb(err);
cbCalled = true;
}
}
}
stream version with errors handling presented by Jens Hauke[8]function copyFile(source, target, cb) {
var cbCalled = false;
var rd = fs.createReadStream(source);
rd.on("error", done);
var wr = fs.createWriteStream(target);
wr.on("error", done);
wr.on("close", function(ex) {
done();
});
rd.pipe(wr);
function done(err) {
if (!cbCalled) {
cb(err);
cbCalled = true;
}
}
}
大きなファイルの読み書き多くの場合、ファイルを読むスピードはファイルを書くより速いです.そうすると、大量のデータがメモリに蓄積され、読みたいファイルが大きいと、メモリを使う量が多すぎて、Node.jsプロセスが崩壊することになります.読み取り速度が私たちの期待した値を超えた場合は、PAuse()を実行して一旦停止し、タイミングが合ったら再度reume()を実行して[5]を再開します.
var util = require('util');
var events = require('events');
var fs = require('fs');
// M
var inputFile = '/Volumes/foo.txt';
function ReadStreamThrottle (stream, speed) {
this._stream = stream;
this._readBytes = 0;
this._speed = speed;
this._ended = false;
this._readBytesSecond = 0;
this._lastTimestamp = Date.now();
this._paused = false;
var self = this;
//
function isTooFast () {
var t = (Date.now() - self._lastTimestamp) / 1000;
var bps = self._readBytesSecond / t;
return bps > speed;
}
//
function checkSpeed () {
if (isTooFast()) {
self.pause();
//
var tid = setInterval(function () {
if (!isTooFast()) {
clearInterval(tid);
self.resume();
}
}, 100);
} else {
self.resume();
}
}
stream.on('data', function (chunk) {
self._readBytes += chunk.length;
self._readBytesSecond += chunk.length;
self.emit('data', chunk);
checkSpeed();
});
stream.on('end', function () {
self._ended = true;
self.emit('end');
});
}
util.inherits(ReadStreamThrottle, events.EventEmitter);
ReadStreamThrottle.prototype.pause = function () {
this._paused = true;
this._stream.pause();
};
ReadStreamThrottle.prototype.resume = function () {
this._paused = false;
this._stream.resume();
};
// , 10MB/S
var MB = 1024 * 1024;
var s = new ReadStreamThrottle(fs.createReadStream(inputFile), MB * 10);
var bytes = 0;
var t = Date.now();
s.on('data', function (c) {
bytes += c.length;
var spent = (Date.now() - t) / 1000;
console.log('read %s bytes, speed: %sMB/S', bytes, (bytes / MB / spent).toFixed(2));
});
s.on('end', function () {
console.log('end. total %s bytes', bytes);
});
ファイルアップロード「RFC 1867-Form-based File Upload in HTML」プロトコルに従って、Node.jsを使ってファイルアップロードを実現します.
ブラウザでフォームを使ってファイルをアップロードするときに使うパケットのフォーマットは以下の通りです.
POSThttp://www.foo.com/ HTTP/1.1
Host: www.foo.com
Content-Length: 199
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywr3X7sXBYQQ4ZF5G
------WebKitFormBoundarywr3X7sXBYQQ4ZF5G
Content-Disposition: form-data; name="myfile"; filename="upload.txt"
Content-Type: text/plain
hello world
------WebKitFormBoundarywr3X7sXBYQQ4ZF5G--
サンプルコード[9]const http = require('http');
const fs = require('fs');
//
var boundaryKey = '----WebKitFormBoundaryjLVkbqXtIi0YGpaB';
var currentDir = __dirname + '/';
var sourceFileName = 'BMW5_torsion.bdf'
var filePath = currentDir + sourceFileName;
// checking file
try {
stat = fs.statSync(filePath);
console.log("File exists.");
}
catch (e) {
if (e.code == 'ENOENT') {
console.log("File does not exist.");
//return false;
}
console.log("Exception fs.statSync (" + filePath + "): " + e);
// console.log(filePath + " does not exist.");
}
//
var options = {
hostname: 'localhost',
port: 80,
path: '/fileupload',
method: 'POST'
}
//
fs.readFile( filePath, function (err, data) {
//
var payload = '--' + boundaryKey + '\r
' ;
payload += 'Content-Disposition:form-data; name="myfile"; filename="'+ sourceFileName + '"\r
' ;
payload += 'Content-Type:text/plain\r
\r
';
payload += data;
payload += '\r
--' + boundaryKey + '--';
//
var req = http.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('body:' + chunk);
});
});
req.on('error', function(e) {
console.error("error:"+e);
});
// boundary、
req.setHeader('Content-Type', 'multipart/form-data; boundary='+boundaryKey+'');
req.setHeader('Content-Length', Buffer.byteLength(payload, 'utf8'));
req.write(payload);
req.end();
});
ファイルアップロードのサンプル[4]var urlparse = require('url').parse
, http = require('http')
, fs = require('fs');
function upload(url, uploadfile, callback) {
var urlinfo = urlparse(url);
var options = {
method: 'POST',
host: urlinfo.host,
path: urlinfo.pathname
};
if(urlinfo.port) {
options.port = urlinfo.port;
}
if(urlinfo.search) {
options.path += urlinfo.search;
}
var req = http.request(options, function(res) {
var chunks = [], length = 0;
res.on('data', function(chunk) {
length += chunk.length;
chunks.push(chunk);
});
res.on('end', function() {
var buffer = new Buffer(length);
// delay copy
for(var i = 0, pos = 0, size = chunks.length; i < size; i++) {
chunks[i].copy(buffer, pos);
pos += chunks[i].length;
}
res.body = buffer;
callback(null, res);
});
});
var readstream = fs.createReadStream(uploadfile);
readstream.on('data', function(chunk) {
console.log('write', chunk.length);
req.write(chunk);
});
readstream.on('end', function() {
req.end();
});
};
upload('http://weibo.com/', '/tmp/bigfile.pdf', function(err, res) {
console.log(res.statusCode, res.headers);
});
ファイルのダウンロード大ファイルのダウンロード例[4]
var urlparse = require('url').parse
var http = require('http')
var fs = require('fs');
function download(url, savefile, callback) {
console.log('download', url, 'to', savefile)
var urlinfo = urlparse(url);
var options = {
method: 'GET',
host: urlinfo.host,
path: urlinfo.pathname
};
if(urlinfo.port) {
options.port = urlinfo.port;
}
if(urlinfo.search) {
options.path += urlinfo.search;
}
var req = http.request(options, function(res) {
var writestream = fs.createWriteStream(savefile);
writestream.on('close', function() {
callback(null, res);
});
res.pipe(writestream);
});
req.end();
};
download('http://web.mit.edu/cocosci/Papers/sci_reprint.pdf', '/temp/isomap.pdf', function(err, res) {
console.log(res.statusCode, res.headers);
});
大きなファイルのダウンロードと断点更新大きなファイルのダウンロードと断点継続の基本原理は、ファイルのダウンロードが切断された後です.クライアントがサーバ側に要求を続けると、http要求のヘッダファイルには一つのパラメータ「Range」が追加され、現在ダウンロードされているファイルが切断されている位置を表示します.
function Transfer(req, resp) {
this.req = req;
this.resp = resp;
}
/**
* [@description](/user/description)
* [@param](/user/param) {string} Range http , undefined, (range: bytes=232323-)
* [@return](/user/return) {integer} startPos
*/
Transfer.prototype._calStartPosition = function(Range) {
var startPos = 0;
if( typeof Range != 'undefined') {
var startPosMatch = /^bytes=([0-9]+)-$/.exec(Range);
startPos = Number(startPosMatch[1]);
}
return startPos;
}
/**
* [@description](/user/description)
* [@param](/user/param) {object} Config ( )
*/
Transfer.prototype._configHeader = function(Config) {
var startPos = Config.startPos,
fileSize = Config.fileSize,
resp = this.resp;
// startPos 0, 0 , 。
if(startPos == 0) {
resp.setHeader('Accept-Range', 'bytes');
} else {
resp.setHeader('Content-Range', 'bytes ' + startPos + '-' + (fileSize - 1) + '/' + fileSize);
}
resp.writeHead(206, 'Partial Content', {
'Content-Type' : 'application/octet-stream',
});
}
/**
* [@description](/user/description)
* [@param](/user/param) {string} filePath
* [@param](/user/param) {function} down
*/
Transfer.prototype._init = function(filePath, down) {
var config = {};
var self = this;
fs.stat(filePath, function(error, state) {
if(error)
throw error;
config.fileSize = state.size;
var range = self.req.headers.range;
config.startPos = self._calStartPosition(range);
self.config = config;
self._configHeader(config);
down();
});
}
/**
* [@description](/user/description) ,
* [@param](/user/param) {string} filePath
*/
Transfer.prototype.Download = function(filePath) {
var self = this;
path.exists(filePath, function(exist) {
if(exist) {
self._init(filePath, function() {
var config = self.config
resp = self.resp;
fReadStream = fs.createReadStream(filePath, {
encoding : 'binary',
bufferSize : 1024 * 1024,
start : config.startPos,
end : config.fileSize
});
fReadStream.on('data', function(chunk) {
resp.write(chunk, 'binary');
});
fReadStream.on('end', function() {
resp.end();
});
});
} else {
console.log(' !');
return;
}
});
}
var fs = require('fs')
http = require('http')
path = require('path');
var server = http.createServer(function(req, resp) {
var transfer = new Transfer(req, resp);
var filePath = '/Users/xukai/Downloads/love.rmvb';
transfer.Download(filePath);
});
server.listen('8000');
isfile()Node.js中fsモジュールのisfile()関数使用例
var fs = require('fs');
var path = '.\foo.txt';
//
fs.statSync( path ).isFile() ;
//
fs.stat( path, function(s){
callback(s.isFile() );
});
参考文献[1]http://nodejs.cn/api/fs [2]http://javabeat.net/nodejs-read-write-file/ [3]https://segmentfault.com/a/1190000000519006[4]http://www.cnblogs.com/fengmk2/archive/2011/08/16/2140460.html[5]http://morning.work/page/2015-07/read_and_write_big_file_同前nodejs.[6]https://cnodejs.org/topic/4f5b47c42373009b5c04e9cb[7]http://procbits.com/2011/11/15/synchronous-file-copy-in-node-js[8]http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js[9]http://www.aichengxu.com/javascript/24609788.htm