缓冲区( Buffer )

Buffer 是 Node.js 中的一个全局对象,它是对 ECMAScript 中的 Uint8Array API 在 Node.js 中的实现

Buffer 代表内存中的一个独立的区域( V8 外分配的内存空间 ),其大小是固定的,无法手动调整,通过 Node.js 中的 Buffer 对象,可以创建这样的一块内存区域,并可以对该区域中的二进制数据进行操作

静态方法:

Buffer.alloc() 创建一个指定大小的 buffer

语法:

1
2
3
4
5
6
Buffer.alloc(size[, fill[, encoding]])
/*
size 为 Buffer 的大小( 必选 )
fill 为填充数据( 可选,可以是 字符串 or 数字 or buffer,默认为 0 )
encoding( 可选,如果 fill 是字符串,则该值是它的字符编码 )
*/

例:

1
2
3
4
5
6
7
8
// 创建大小为 10 个字节( Byte )、且用 0x64 填充的 Buffer
const buffer = Buffer.alloc(10, 0x64);
console.log(buffer); // <buffer 64 64 64 64 64 64 64 64 64 64> ( 默认以16进制数输出 )
// 修改buffer( 类似数组 )
buffer[0] = 1; // 仅数字有效
buffer[1] = 0xa;
console.log(buffer); // <buffer 01 0a 64 64 64 64 64 64 64 64>
console.log(buffer.length) // 10

Buffer.from() 创建一个填充了指定字符串、数组或 buffer 的新 buffer

语法:

1
2
3
4
5
6
/* 语法1 */
Buffer.from(array) // array 为一个数组,数组中只有数字有效
/* 语法2 */
Buffer.from(string[, encoding]) // string 为一个字符串,encoding 为字符串的字符编码,如:ascii、utf8
/* 语法3 */
Buffer.from(buffer) // 将指定buffer中的数据拷贝到一个新的buffer中

例:

1
2
3
4
// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer
const buf1 = Buffer.from([1, 2, 3]);
// 创建一个包含 [0x68, 0x65, 0x6c, 0x6c, 0x6f] ( UTF-8编码 ) 的 Buffer
const buf2 = Buffer.from('hello', 'utf8');

Buffer.isBuffer(obj) 判断 obj 是否为 Buffer,返回 true / false

Buffer.concat() 将多个 buffer 拼接合并为一个 buffer

语法:

1
2
3
4
5
Buffer.concat(list[, totalLength])
/*
list 要合并的buffer
totalLength 长度限制,合并时 list 的长度( 大小 )
*/

实例方法:

buf.fill() 向指定 buffer 中填充数据

语法:

1
2
3
4
5
6
7
8
buf.fill(value[, offset[, end]][, encoding])
/*
value 要填充的值,可以是 字符串 or 数字 or buffer
offset 从指定字节( 索引 )开始往后填充,默认 0
end 从指定字节( 索引 )结束填充,默认 buf.length
encoding 如果 value 是字符串,则这是它的字符编码
返回:填充后的 buffer
*/

buf.write() 向指定 buffer 中写入数据

语法:

1
2
3
4
5
6
7
8
buf.write(string[, offset[, length]][, encoding])
/*
string 要写入的字符串
offset 从指定字节( 索引 )开始往后写入,默认 0
length 写入的长度( 大小 ),默认 (buf.length - offset)
encoding 字符编码,默认 utf8
返回:写入的字节大小
*/

buf.toString() 将指定 buffer 中的数据解码为字符串

语法:

1
2
3
4
5
6
7
buf.toString([encoding[, start[, end]]])
/*
encoding 解码使用的字符编码,默认 utf8
start 从指定字节( 索引 )开始往后解码,默认 0
end 从指定字节( 索引 )结束解码,默认 buf.length
返回:字符串
*/

buf.slice() 从指定 buffer 中截取出一个新的 buffer

语法:

1
2
3
4
5
6
buf.slice([start[, end]])
/*
start 从指定字节( 索引 )开始往后截取,默认 0
end 从指定字节( 索引 )结束截取,默认 buf.length
返回:截取后的新buffer
*/

buf.indexOf() 搜索 buffer 中是否存在指定内容

语法:

1
2
3
4
5
6
7
buf.indexOf(value[, offset][, encoding])
/*
value 要搜索的值,可以是 字符串 or 数字 or buffer
offset 从指定字节( 索引 )开始往后搜索,默认 0
encoding 如果 value 是一个字符串,则这是它的字符编码,默认 utf8
返回:buf中value首次出现的索引值,如果没有搜索到则返回 -1
*/

buf.copy() 将源 buffer 拷贝到目标 buffer 中

语法:

1
2
3
4
5
6
7
8
buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
/*
target 目标 buffer
targetStart 从 目标buffer( target ) 的指定字节开始往后写入拷贝的数据,默认 0
sourceStart 指定要拷贝数据的 源buffer( buf ) 的起始字节,默认 0
sourceEnd 指定要拷贝数据的 源buffer( buf ) 的结束字节,默认 buf.length
返回:被拷贝的字节数
*/
  • 手写 buf.split() 实例方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /*
    sep 要拆分的分隔符
    */
    Buffer.prototype.split = function (sep) {
    let len = Buffer.from(sep).length
    let ret = []
    let start = 0
    let offset = 0

    // 循环查找非 sep 的数据
    while ((offset = this.indexOf(sep, start)) !== -1) {
    ret.push(this.slice(start, offset))
    start = offset + len
    }

    // 防护数据最后面是截取关键词的情况
    ret.push(this.slice(start))
    return ret
    }

文件系统( fs )

fs 是 Node.js 中专门用来操作文件的模块,模块中所有方法都有同步和异步两种形式,同步文件操作会阻塞程序的执行,而异步文件操作不会,异步文件操作完成时,会通过回调函数将结果返回,且回调函数的第一个参数总是留给异常参数( exception )

fs.readFile() 读取文件,同步方法:fs.readFileSync()

语法:

1
2
3
4
5
6
7
8
9
10
11
12
fs.readFile(path[, options], callback)
/*
path 文件路径或文件描述符
option 对象 or 字符串( 指定字符编码 )
{
encoding 指定字符编码解析,默认 null ( 不解析,返回buffer )
flag 指定文件操作符,默认 'r'
}
callback(err, data) 回调函数
err 错误对象,文件读取成功时,err 为 null
data 字符串 or buffer
*/

fs.writeFile() 写入文件( 不保留文件内容 ),同步方法:fs.writeFileSync()

语法:

1
2
3
4
5
6
7
8
9
10
11
12
fs.writeFile(file, data[, options], callback)
/*
file 文件名或文件描述符,如果写入文件不存在,则会自动创建
data 字符串 or buffer。要写入的数据
option 对象 or 字符串( 指定字符编码 )
{
encoding 指定字符编码写入,默认 utf8
flag 指定文件操作符,默认 'w'
}
callback(err) 回调函数
err 错误对象,文件写入成功时,err 为 null
*/

fs.appendFile() 追加写入文件( 在原有内容后面添加新内容 ),同步方法:fs.appendFileSync()

语法:

1
2
3
4
fs.appendFile(file, data[, options], callback)
/*
同 fs.writeFile()
*/

fs.copyFile() 拷贝文件,同步方法:fs.copyFileSync()

语法:

1
2
3
4
5
6
7
fs.copyFile(src, dest, callback)
/*
src 要被拷贝的源文件名称
dest 拷贝操作的目标文件名
callback(err) 回调函数
err 错误对象,文件拷贝成功时,err 为 null
*/

fs.watchFile() 监听文件,同步方法:fs.watchFileSync()

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fs.watchFile(filename[, options], listener)
/*
filename 文件名
options 对象
{
interval 间隔时间 ms,默认 5007
}
listener(current, previous) 回调函数,文件修改时调用
current 文件修改后的状态
previous 文件修改前的状态
*/
fs.unwatchFile(filename)
// 取消监听文件
/*
filename 文件名
*/

fs.open() 打开文件,同步方法:fs.openSync()

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fs.open(path, flags, callback)
/*
path 文件路径
flags 指定文件操作符
callback(err, fd) 回调函数
err 错误对象,文件打开成功时,err 为 null
fd 被打开文件的文件描述符
*/
fs.close(fd, callback)
// 关闭文件
/*
fd 文件描述符
callback(err) 回调函数
*/

fs.read() 读文件( 读取文件并写入到 buffer 中 )

语法:

1
2
3
4
5
6
7
8
9
10
11
12
fs.read(fd, buffer, offset, length, position, callback)
/*
fd 文件描述符
buffer 要写入的 buffer
offset 从 buffer 的指定字节开始往后写入
length 写入的长度( 大小 )
position 从文件( fd )的指定字节开始写入( buffer )
callback(err, bytesRead, buffer)
err 错误对象,文件读成功时,err 为 null
bytesRead 从文件( fd )中读的字节数
buffer
*/

fs.write() 写文件( 读取 buffer 中数据并写入到文件中 )

语法:

1
2
3
4
5
6
7
8
9
10
11
12
fs.write(fd, buffer[, offset[, length[, position]]], callback)
/*
fd 文件描述符
buffer 要读取 buffer
offset 从 buffer 的指定字节开始往后读取数据
length 读取的长度( 大小 )
position 从文件( fd )的指定字节开始写入( 文件 )
callback(err, bytesRead, buffer)
err 错误对象,文件写成功时,err 为 null
bytesRead 从文件( fd )中读的字节数
buffer
*/

fs.access() 判断文件或目录是否具有相应权限

语法:

1
2
3
4
5
fs.access(path, callback)
/*
path 文件路径
callback(err) 回调函数
*/

fs.stat() 获取文件目录信息

语法:

1
2
3
4
5
6
7
8
9
10
 fs.stat(path, callback)
/*
path 路径
callback(err, stats) 回调函数
err 错误对象
stats 对象
stats.size 文件大小
stats.isFile() path是否为文件 true / false
stats.isDirectory() paht是否为目录 true / false
*/

fs.mkdir() 创建目录

语法:

1
2
3
4
5
6
7
8
9
fs.mkdir(path[, options], callback)
/*
path 路径
options 对象
{
recursive 递归创建,true / false
}
callback(err) 回调函数
*/

fs.rmdir() 删除目录

语法:

1
2
3
4
fs.rmdir(path[, options], callback)
/*
同 fs.mkdir()
*/

fs.readdir() 读取目录

语法:

1
2
3
4
5
6
7
fs.readdir(path, callback)
/*
path 路径
callback(err, files) 回调函数
err 错误对象
files path路径下文件列表
*/

语法:

1
2
3
4
5
fs.unlink(path, callback)
/*
path 文件路径
callback(err)
*/

fs.createWriteStream() 创建文件写入流

语法:

1
2
3
4
5
6
7
8
9
10
11
12
fs.createWriteStream(path)
/*
path 文件路径
*/

// 例子
const ws = fs.createWriteStream('./content') // './content' 为目标文件, 返回该文件写入流对象
ws.write('one line ') // 往目标文件中写入字符串, 也可将 buffer 中的数据写入到目标文件
ws.write('tow line ')
ws.write('there line ')
console.log(fs.readFileSync('./content')) // one line tow line there line
ws.close() // 关闭文件

路径( path )

path.resolve() 将所有给定的 path 解析为一个规范的绝对路径

语法:

1
2
3
4
5
6
7
8
9
10
11
12
path.resolve([...paths])
/*
...paths 一个路径或路径片段的序列
*/

// 例子
path.resolve('/foo/bar', './baz') // '/foo/bar/baz'
path.resolve('/foo/bar', '/tmp/file/') // '/tmp/file'
path.resolve(__dirname, './tmp/file/')
path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif')
// 如果当前工作目录为 /home/myself/node
// 则返回 '/home/myself/node/wwwroot/static_files/gif/image.gif'

path.join() 使用操作系统特定的路径分隔符将所有给定的 path 连接为一个路径

语法:

1
2
3
4
5
6
7
path.join([...paths])
/*
...paths 一个路径或路径片段的序列
*/

// 例子
path.join('./xxx', 'asasd/asdd') // 'xxx/asasd/asdd'

path.sep 获取操作系统的路径分隔符

例子:

1
path.sep // Linux 为 '/' Windows 为 '\'

path.parse() 解析一个路径

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
path.parse(path)
/*
path 一个路径
*/

// 例子
path.parse('/home/user/dir/file.txt')
// 返回:
/*
{
root: '/',
dir: '/home/user/dir',
base: 'file.txt',
ext: '.txt',
name: 'file'
}
*/
// root 根目录
// dir 目录, 可以通过 path.dirname() 方法获取
// base 文件完整名(不包括目录部分), 可以通过 path.basename() 方法单独获取
// ext 文件扩展名, 可以通过 path.extname() 方法单独获取
// name 文件名

URL( url )