(5) 删除文件夹 :使用 fs.rmdir() 或 fs.rmdirSync() 可以删除文件夹。
删除包含内容的文件夹可能会更复杂。在这种情况下,最好安装 fs-extra 模块,该模块非常受欢迎且维护良好。 它是 fs 模块的直接替代品,在其之上提供了更多的功能。
使用以下命令安装:
npm install fs-extra
并像这样使用它:
const fs = require('fs-extra') const folder = './test' fs.remove(folder, err => { console.error(err) })
也可以与 promise 一起使用:
fs.remove(folder) .then(() => { //完成 }) .catch(err => { console.error(err) })
或使用 async/await:
async function removeFolder(folder) { try { await fs.remove(folder) //完成 } catch (err) { console.error(err) } } const folder = '/Users/joe' removeFolder(folder)
文件操作
(1)写内容到文件里 使用fs.writeFile()
const fs = require('fs') // 写内容到文件里 fs.writeFile( './test/test2.txt', 'hello', // 错误的回调函数 (err) => { if (err) { console.log(err.message) } else { console.log('文件创建成功') } } )
另外,也可以使用同步的版本 fs.writeFileSync()
:
const fs = require('fs') const content = '一些内容' try { const data = fs.writeFileSync('./test/test.txt', content) //文件写入成功。 } catch (err) { console.error(err) }
默认情况下,此 API 会替换文件的内容(如果文件已经存在)。可以通过指定标志来修改默认的行为:
const fs = require('fs') // 写内容到文件里 fs.writeFile( './test/test2.txt', 'hello', { flag:"a+" }, // 错误的回调函数 (err) => { if (err) { console.log(err.message) } else { console.log('文件创建成功') } } )
常用的标志有,其他用到再查:
r+ 打开文件用于读写。
w+ 打开文件用于读写,将流定位到文件的开头。如果文件不存在则创建文件。
a 打开文件用于写入,将流定位到文件的末尾。如果文件不存在则创建文件。
a+ 打开文件用于读写,将流定位到文件的末尾。如果文件不存在则创建文件。
(2)删除文件 :可以使用fs.unlink()删除文件
const fs = require('fs') fs.unlink('./test/test2.txt', (err) => { console.log('done.') })
(3) 批量写文件
const fs = require('fs') for (let i = 0; i < 10; i++) { fs.writeFile(`./test/log-${i}.txt`, `log-${i}`,{flag:"a+"}, (err) => { console.log('done.') }) }
(4) 读取文件
在 Node.js 中读取文件最简单的方式是使用 fs.readFile() 方法,向其传入文件路径、编码、以及会带上文件数据(以及错误)进行调用的回调函数:
const fs = require('fs') fs.readFile('./test/test.txt', 'utf8' , (err, data) => { if (err) { console.error(err) return } console.log(data) })
另外,也可以使用同步的版本 fs.readFileSync():
const fs = require('fs') try { const data = fs.readFileSync('./test/test.txt', 'utf8') console.log(data) } catch (err) { console.error(err) }
fs.readFile() 和 fs.readFileSync() 都会在返回数据之前将文件的全部内容读取到内存中。
这意味着大文件会对内存的消耗和程序执行的速度产生重大的影响。
在这种情况下,更好的选择是使用流来读取文件的内容。我们下面马上就会讲到流模块。
在fs模块中,提供同步方法是为了方便使用。那我们到底是应该用异步方法还是同步方法呢?
由于Node环境执行的JavaScript代码是服务器端代码,所以,绝大部分需要在服务器运行期反复执行业务逻辑的代码,必须使用异步代码,否则,同步代码在执行时期报错或阻塞,服务器将停止响应,因为JavaScript只有一个执行线程。
服务器启动时如果需要读取配置文件,或者结束时需要写入到状态文件时,可以使用同步代码,因为这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。
8. stream流模块
stream是Node.js提供的又一个仅在服务区端可用的模块,目的是支持“流”这种数据结构。
什么是流?流是一种抽象的数据结构。想象水流,当在水管中流动时,就可以从某个地方(例如自来水厂)源源不断地到达另一个地方(比如你家的洗手池)。我们也可以把数据看成是数据流,比如你敲键盘的时候,就可以把每个字符依次连起来,看成字符流。这个流是从键盘输入到应用程序,实际上它还对应着一个名字:标准输入流。
如果应用程序把字符一个一个输出到显示器上,这也可以看成是一个流,这个流也有名字:标准输出流。流的特点是数据是有序的,而且必须依次读取,或者依次写入,不能像Array那样随机定位。
有些流用来读取数据,比如从文件读取数据时,可以打开一个文件流,然后从文件流中不断地读取数据。有些流用来写入数据,比如向文件写入数据时,只需要把数据不断地往文件流中写进去就可以了。
在Node.js中,流也是一个对象,我们只需要响应流的事件就可以了:data事件表示流的数据已经可以读取了,end事件表示这个流已经到末尾了,没有数据可以读取了,error事件表示出错了。
const fs = require('fs'); // 打开一个流: let rs = fs.createReadStream('./test/test.txt', 'utf-8'); rs.on('data', function (chunk) { console.log('DATA:') console.log(chunk); }); rs.on('end', function () { console.log('END'); }); rs.on('error', function (err) { console.log('ERROR: ' + err); });
要注意,data
事件可能会有多次,每次传递的chunk
是流的一部分数据。但是上面案例文件的内容太少了,所以一次就读出来了。
要以流的形式写入文件,只需要不断调用write()
方法,最后以end()
结束:
const fs = require('fs'); let ws1 = fs.createWriteStream('./test/test.txt', 'utf-8'); ws1.write('使用Stream写入文本数据...\n'); ws1.write('1111111111111111111111111111\n'); ws1.write('22222222222222222222222222222\n'); ws1.write('END.'); ws1.end();
如果要实现一个文件一边读一边写入呢?可以用到pipe
pipe 就像可以把两个水管串成一个更长的水管一样,两个流也可以串起来。一个Readable流和一个Writable流串起来后,所有的数据自动从Readable流进入Writable流,这种操作叫pipe。
在Node.js中,Readable流有一个pipe()方法,就是用来干这件事的。
让我们用pipe()把一个文件流和另一个文件流串起来,这样源文件的所有数据就自动写入到目标文件里了,所以,这实际上是一个复制文件的程序:
const fs = require('fs') const readstream = fs.createReadStream('./1.txt') const writestream = fs.createWriteStream('./2.txt') readstream.pipe(writestream)
9. zlib模块
大家都知道,我们的浏览器要想去加载一个html的过程是由服务器读取文件后返回给浏览器的,在这个过程中,文件可能挺大的,我们可以在传输时打包压缩,到了浏览器中时,浏览器再对其解压缩后显示出来就可以了。很多网站中,我们会发现他们很多都是通过gzip这种方式把原来的那些静态资源文件,给压缩成gzip来传给浏览器,浏览器再解压出来的。
我们先写一个不用压缩技术的程序,给浏览器传一个js文件,看看文件的大小:
const fs = require('fs') const http = require('http') http.createServer((req, res) =>{ //创建可读流 let readStream=fs.createReadStream("./index.js") res.writeHead(200,{"Content-Type": "application/x-javascript;charset=utf-8"}) //把可读流通过管道,送到res可写流当中去 readStream.pipe(res) }).listen(3000,()=>{ console.log("server start") })
在没有压缩的情况下传输,大小为2.3 KB。
下面我们对程序改一个,采用gzip的压缩方式传输:
const fs = require('fs') const zlib = require('zlib') const http = require('http') //通过zlib创建gzip对象 const gzip = zlib.createGzip(); http.createServer((req, res) =>{ //创建可读流 let readStream=fs.createReadStream("./index.js") //gzip传输文件,响应头要加上"Content-Encoding":"gzip" ,不然浏览器无法解析gzip的文件 res.writeHead(200,{ "Content-Type": "application/x-javascript;charset=utf-8", "Content-Encoding":"gzip" }) //把可读流通过管道时先经过gzip压缩后,在送到res可写流当中去 readStream.pipe(gzip).pipe(res) }).listen(3000,()=>{ console.log("server start") })
这时浏览器再访问,发现大小居然变成190 B了。