Outline
3 文件、进程、流和网络
- 3.1 查询和读写文件
- 3.2 创建和控制外部进程
- 3.3 读写数据流
3 文件、进程、流和网络
3.1 查询和读写文件
path
从Node 0.8起,path模块只负责处理文件路径相关的字符串,不与实际文件或路径关联。
sample code:
/**
demonstration of module 'path' 's usage
*/
var path = require("path");
// 1 exists() - DEPRECATED use fs.exists("<path>", function(exists){}) instead
var fs = require("fs");
fs.exists("./path_demo.js", function(exists){// this file
console.log(exists);
});
console.log(fs.existsSync("./path_demo.js"));// syn version
// 2 normalize()
console.log(path.normalize("/foo/bar/../baz"))
// 3 join()
var myPath = path.join("/foo", "bar", "..", "baz");
console.log(myPath);
// 4 resolve()
myPath = path.resolve("/hotdoc", "static_files/script", "../images/home.gif");
console.log(myPath);
// 5 relative()
myPath = path.relative("/data/test/aaa", "/data/src/aaa");
console.log(myPath);
// 6 dirname(), basename(), extname()
myPath = "/foo/bar/baz/index.html";
console.log("dirname="+path.dirname(myPath));
console.log("basename="+path.basename(myPath));
console.log("basename without extention="+path.basename(myPath, ".html"));
console.log("extname="+path.extname(myPath));
fs
fs模块用于查询文件的统计信息、文件的打开/读写/关闭等操作。
/**
demonstration of module 'fs''s usage,
files are put in $CWD/data
*/
var fs = require("fs");
// 1 stat()
fs.stat("./data/data.txt", function(error, stats){
if(error){
throw error;
}
console.log(stats);
// hepler methods
console.log("isFile="+stats.isFile());
console.log("isDirectory="+stats.isDirectory());
console.log("isBlockDevice="+stats.isBlockDevice());
console.log("isCharacterDevice="+stats.isCharacterDevice());
console.log("isSymbolicLink="+stats.isSymbolicLink());
console.log("isFIFO="+stats.isFIFO());
console.log("isSocket="+stats.isSocket());
});
// 2 open()
// 3 read()
fs.open("./data/data.txt", "r", function opened(error, fd){
// fd: file descriptor
if(error){ throw error; }
var readBuffer = new Buffer(1024);
fs.read(fd,
readBuffer,
0, // buffer's start position
readBuffer.length,//data size
0, // file postion
function(error, readBytes){
if(error) {throw error;}
console.log("read "+ readBytes + " bytes");
if(readBytes > 0){
console.log(readBuffer.slice(0, readBytes).toString());
}
});
fs.close(fd, function(){
console.log("closed after read");
});
});
// 4 write()
fs.open("./data/data.txt", "a", function(error, fd){// append mode
if(error) {throw error;}
var writeBuffer = new Buffer("this is the appended content");
fs.write(fd,
writeBuffer,
0, // buffer's start position
writeBuffer.length,// data size
null, // current file's cursor
function(error, writeBytes){
if(error) {throw error;}
console.log("write " + writeBytes + " bytes");
}
);
fs.close(fd, function(){
console.log("closed after write");
});
});
// 5 close()
// default: file is closed when process end
3.2 创建和控制外部进程
(1) 执行外部进程
exec_external_cmd.js
/**
demonstration of execute external commands
*/
var exec = require("child_process").exec;
// execute "cat *.js | wc -l"
exec("cat *.js | wc -l", function(error, stdout, stderr){
if(error){
console.log("child process exited with error code: " + error.code);
return;
}
console.log(stdout);//renderer the output of child process
});
// use configuration options
var options = {
encoding: "utf8",
timeout: 10000,
killSignal: "SIGKILL",
maxBuffer: 10 * 1024//default is 200*1024Bytes
};
exec("cat *.js | wc -c", options, function(error, stdout, stderr){
if(error){
console.log("child process exited with error code: " + error.code);
return;
}
console.log(stdout);
});
// play with environment variables
// get this process's ENV
var env = process.env;
var envCopy = {};
for(var envVarname in env){
envCopy[envVarname] = env[envVarname];// deep copy
}
envCopy["number"] = 123;// customed environment variable
exec("node child_env.js", {env: envCopy}, function(error, stdout, stderr){
if(error) { throw error;}
console.log("stdout:"+stdout);
console.log("stderr:"+stderr);
});
child_env.js
/**
a child process script to handle ENVs
*/
// ENV: number
var number = process.env.number;
console.log(typeof(number));// should be string
number = parseInt(number, 10);
console.log(typeof(number));
(2) 生成子进程
spawn_demo.js
/**
demonstration of spawn child processes
*/
var spawn = require("child_process").spawn;
// 1 spawn usage
// (1) not long-lived child process
// wc -l spawn_demo.js
//var child = spawn("wc", ["-l", "spawn_demo.js"]);
// (2) a long-lived child process
// tail -f spawn_demo.js
//var child = spawn("tail", ["-f", "spawn_demo.js"]);//this file
// (3) a sample IPC
/*
// node child_spawn.js
var child = spawn("node", ["child_spawn.js"]);
setInterval(function(){
var number = Math.floor(Math.random() * 10000);
// communicate to child process through FD stdin
child.stdin.write(number+"\n");
child.stdout.once("data", function(data){
console.log("child's reply to " + number + " is " + data);
});
}, 1000);
*/
// (4) child process killed by a singal
var child = spawn("sleep", ["5"]);
// 2 listen to child process's stdout
child.stdout.on("data", function(data){
console.log("child output: "+ data);
});
child.stderr.on("data", function(data){
console.log("child error output: " + data);
});
// listen to child process's exit
child.on("exit", function(code){
console.log("child process exitd with code: " + code);
});
// listen to child process's exit with a returned signal
child.on("exit", function(code, signal){
if(code){
console.log("child process exitd with code: " + code);
} else if(signal){
console.log("child process killed by signal: " + signal);
}
});
child_spawn_demo.js
/**
demonstration of a spawnded child process to receive data from its stdin
*/
// unlock stream stdin's PAUSE state
process.stdin.resume();
process.stdin.on("data", function(data){
var number;
try{
number = parseInt(data.toString(), 10);
number += 1;
// write to stdin
process.stdout.write(number+"\n");
} catch(error){
process.stderr.write(err.message + "\n");
}
});
(3) 进程间通信(IPC)
process_signal.js
/**
demonstration of sending signal to child process
*/
var spawn = require("child_process").spawn;
// [1]
//var child = spawn("sleep", ["10"]);
// [2]
var child = spawn("node", ["child_process_signal.js"]);
setTimeout(function(){
// [1]
// send a signal to child process: SIGTERM
//child.kill();
// [2]
// send a signal to child process
child.kill("SIGUSR2");
}, 3000);
// listeners
child.stdout.on("data", function(data){
console.log("child stdout: " + data);
});
child.stderr.on("data", function(data){
console.log("child stderr: " + data);
});
child.on("exit", function(code, signal){
if(code){
console.log("child process exitd with code: " + code);
} else if(signal){
console.log("child process killed by signal: " + signal);
}
});
child_process_signal.js
/**
demonstration of process handle signals
*/
console.log("child process's pid="+process.pid);
var exec = require("child_process").exec;
exec("sleep 10", function(error, stdout, stderr){
if(error){
console.log("child process exited with error code: " + error.code);
return;
}
console.log("stdout="+stdout);
console.log("stderr="+stderr);
});
process.on("SIGUSR2", function(){
console.log("incoming a SIGUSR2 singal, i will quit with killing myself");
process.kill(process.pid);// kill self
});
3.3 读写数据流
文件流
可读read_stream.js
/**
demonstration of readable stream, including
events: data, end
method: pause(), resume()
*/
var fs = require("fs");
var options = {
encoding: 'utf8',// null means will be Buffer in 'data' event, and 'utf8' means string
fd: null, // an opened file descriptor
bufferSize: 0,//size of file chunk
start: 0, // start postion in file that want to read
end:10 // end position in file that want to read
};
var readStream = fs.createReadStream("./data/data.txt", options);
readStream.on("data", function(data){
console.log("type of data is : " + typeof(data));
console.log(data.toString());
});
// pause the stream
readStream.pause();
// resume the paused stream
readStream.resume();
readStream.on("end", function(){
console.log("the stream has ended");
})
可写write_stream.js
/**
demonstration of writeable stream, including
events: drain
method: write()
*/
var fs = require("fs");
var options = {
flags: 'w',// same as fs.open()
encoding: 'utf8',// same as readable buffer's options
mode: 0666// file's priviledge
};
var writeStream = fs.createWriteStream("./data/data2.txt");
var inKernelOrQueue = writeStream.write("What is rational is real, and what is real is rational.");
// true means data has been sent to kernel's buffer,
// false means data had been save in queue in process's memory space
console.log("inKernelOrQueue="+inKernelOrQueue);
writeStream.on("drain", function(){
console.log("data has been sent");
});
网络流
Socket是可读/可写流。
HTTP请求对象(request)是可读流,HTTP响应对象(response)是可写流。
具体内容见后面的模块说明。
慢客户端问题
典型场景:从可写流读,向可写流写入;但读的速度比写的速度快,需要可读流等待一下。
pipe_demo.js
/**
demonstration of readable stream's pipe() method,
it's used for handle write is more slow than read operation
*/
var http = require("http");
var fs = require("fs");
http.createServer(function(request, response){
var readStream = fs.createReadStream("./data/data.txt");
var options = {
// true means the writeable stream's end() method will be called when the readable stream is end
end: false
};
readStream.pipe(response, options);
readStream.on("end", function(){
response.write("that all the content");
response.end();// directly call the end() method
});
}).listen(8080);