Node中的I/O操作
从某种意义上讲,Node其实是在C 的基础上又包了一层。和其他语言一样,Node和操作系统的交互也是通过I/O。
Node的I/O操作包括哪些内容
Node的I/O操作具体包括哪些内容呢?有这么几个:
- 标准I/O
- 文件处理 fs
- 元数据处理 metadata
- 文件和目录的监听
- sockets通信
获取元数据
上节文章大致讲了Node中的标准I/O和文件操作,这篇接着讲元数据处理。
首先我们要理解一个概念,元数据指的是什么?
这里要提的一个问题是,读取文件列表,获取权限,以及获取文件创建以及修改时间,这些是文件系统非常重要的功能,元信息指的就是这些信息。
我们可以使用tableaux这个模块将这些信息显示到终端上。
我们先安装tableaux模块。
代码语言:javascript复制npm install --save tableaux
然后在index.js中,写下面的内容:
代码语言:javascript复制const fs = require('fs')
const path = require('path')
const tableaux = require('tableaux')
const write = tableaux(
{ name: 'Name', size: 20 },
{ name: 'Created', size: 30 },
{ name: 'DevicedId', size: 30 },
{ name: 'Mode', size: 8 },
{ name: 'Lnks', size: 4 },
{ name: 'Size', size: 6 }
)
function toMeta({ file, dir }) {
const stats = fs.statSync(path.join(dir, file))
var { birthtime, ino, mode, nlike, size } = stats
mode = mode.toString(9)
size = 'B'
return {
file,
dir,
info: [birthtime, ino, mode, nlike, size],
isDir: stats.isDirectory(),
}
}
function output({ file, dir, info, isDir }) {
write(file, ...info)
if (!isDir) {
return
}
const p = path.join(dir, file)
write.arrow()
fs.readdirSync(p).forEach((f) => {
const stats = fs.statSync(path.join(p, f))
const style = stats.isDirectory() ? 'blod' : 'dim'
write[style](f)
})
write.newLine()
}
function print(dir) {
fs.readdirSync(dir)
.map((file) => ({ file, dir }))
.map(toMeta)
.forEach(output)
write.newLine()
}
print(process.argv[2] || '.')
执行这个文件,我们最终可以看到下面的内容:
大体流程是print方法先用fs.readdir读取文件夹进行遍历,然后toMeta方法用fs.statSync对文件进行统计,然后返回元信息,最后output方法将信息通过write写到终端上,大体是这么一个过程。
需要注意的是
我们的代码里最后一行:
代码语言:javascript复制process.argv[2] || '.'
argv是process的一个命令行的参数,它是一个数组,arprocess.argv[0]可以理解为node , provess.argv[1]则是index.js , process.argv[2]不存在时默认为一个点,表示当前文件夹。
获取符号链接信息
有些人可能不理解符号链接信息是什么?
举个例子,我们都用过windows系统,都创建过桌面快捷方式,那么这个快捷方式是什么呢?
其实他就是个链接,只不过这个链接指向一个程序的启动命令,比如说我们双击浏览器图标,浏览器就打开了,其实图标也是指向了浏览器的启动文件。
我们修改index.js
代码语言:javascript复制
const fs = require('fs')
const path = require('path')
const tableaux = require('tableaux')
const write = tableaux(
{ name: 'Name', size: 20 },
{ name: 'Created', size: 30 },
{ name: 'DevicedId', size: 30 },
{ name: 'Mode', size: 8 },
{ name: 'Lnks', size: 4 },
{ name: 'Size', size: 6 }
)
function toMeta({ file, dir }) {
const stats = fs.statSync(path.join(dir, file))
var { birthtime, ino, mode, nlike, size } = stats
mode = mode.toString(9)
size = 'B'
return {
file,
dir,
info: [birthtime, ino, mode, nlike, size],
isDir: stats.isDirectory(),
isSymLink: stats.isSymbolicLink(),
}
}
function output({ file, dir, info, isDir, isSymLink }) {
if (isSymLink) {
outputSymLink(file, dir, info)
return
}
write(file, ...info)
if (!isDir) {
return
}
const p = path.join(dir, file)
write.arrow()
fs.readdirSync(p).forEach((f) => {
const stats = fs.lstatSync(path.join(p, f))
const style = stats.isDirectory() ? 'blod' : 'dim'
if(stats.isSymbolicLink()){
f = 'u001b[3m' f 'u001b[0m'
}
write[style](f)
})
write.newLine()
}
function outputSymLink(file, dir, info) {
write('u001b[33]' file 'u001b0m', ...info)
process.stdout.write('ub001b[33m')
write.arrow(4)
write.bold(fs.readlinkSync(path.join(dir, file)))
process.stdout.write('u001b[0m')
write.newline()
}
function print(dir) {
fs.readdirSync(dir)
.map((file) => ({ file, dir }))
.map(toMeta)
.forEach(output)
write.newLine()
}
print(process.argv[2] || '.')
在toMeta方法中增加链接信息,同时增加function outputSymLink方法,然后重新执行index.js。
然后会看到,输出的内容中多了一条链接信息,my-link。
当然,前提是你需要先设置这个链接。
元信息的修改
元信息的修改主要涉及,权限,创建时间,更新时间等信息,这些都有对应的API,这里就不多说了。
下节主要说一说监听文件的变化。