从零学习node.js之文件操作(三)


Posted in Javascript onFebruary 21, 2017

一、文件操作

在文件操作里,主要是有文件读写,创建、移动文件等。

1.1 读取文件

读取文本文件时,如.txt, .js, .json等文件,直接使用readFile就可以获取文件的内容。

// server.js
var fs = require('fs');

fs.readFile('./data.txt', 'utf-8', function(err, data){
 if(err) throw err;
 console.log(data);
});

读取图片时,我们是不能直接输出到控制台中的,是需要创建一个服务器,然后在浏览器上进行查看。其实在上节中,我们已经了解过显示图片的过程了。

// server.js
var http = require('http'),
 fs = require('fs');

http.createServer(function(request, response){
 // 使用二进制方式读取图片
 fs.readFile('./img/test.png', 'binary', function(err, file){
  if( err ) throw err;
  // 当前数据以image/png方式进行输出
  response.writeHead(200, {"Content-Type": "image/png"});
  response.write(file, 'binary');
  response.end();
 });
}).listen(3000);
console.log('server has started...');

打开浏览器:127.0.0.1:3000,就能看到图片了。

1.2 写入文件

将字符串写入到文件文件中,是非常简单的操作,使用writeFile即可搞定:

var fs = require('fs');

var data = '从一开始,就选择了做前端开发,因为觉得前端开发更贴近用户,能够倾听用户的声音,更好玩,更有意思,美的更直观。我们总是在尝试最新的技术,尝试更炫的效果,希望更能优化用户的体验效果!';

fs.writeFile('./test.txt', data, function(err){
 if(err) throw err;
 console.log('写入数据成功...');
});

writeFile方法,在没有文件时会创建文件并写入;若文件存在则内容被覆盖。

1.3 创建或文件重命名

根据writeFile的特性,可以使用writeFile写入空字符串的方式创建文件。

同时,fs.open也可以创建文件:

// 打开模式可以使用 w | w+ | a | a+
// 这些模式在打开不存在的文件时,会创建文件
// fd为一个整数,表示打开文件返回的文件描述符,window中又称文件句柄
fs.open(Date.now()+'.txt', 'a+', function(err, fd){
 if(err) throw err;
 console.log(fd);
})

在文件系统中,有一个fs.rename的方法,顾名思义,对文件(文件夹)进行重命名。

fs.rename(oldname, newname, callback(err));

特性:

将oldname文件(目录)移动至newname的路径下,并重新命名;如果oldname和newname是同一个路径,则直接进行重命名。

二、文件夹操作

通常对目录的操作比较简单一些。

2.1 读取文件夹中的文件和文件夹列表

使用fs.readdir(path, callback)可以获取path路径下的文件和目录列表,而且只能读取直接目录下的文件和文件夹,子目录里的是获取不到的。

fs.readdir('./', function(err, files){
 if(err) throw err;
 console.log( files );
});

输出结果:

[
 'img',
 'msg.txt',
 'node_modules',
 'package.json',
 'server.js',
 'test.js',
 'tmp'
]

node_modulestmp是文件夹,剩下的是文件,而且是获取不到node_modulestmp里面的数据。获取一个目录下所有的文件,后面会讲解,稍等。

2.2 删除文件夹

使用fs.rmdir(path, callback)可以删除文件夹,但只能删除空文件夹,如果当前路径不是文件夹或当前文件夹不为空,则删除失败;删除的为空文件夹时,可以删除成功。

fs.rmdir('./tmp', function(err){
 if(err){
  console.log('删除文件夹失败');
  throw err;
 }else{
  console.log('删除成功');
 }
})

如何删除不为空的目录,后面会讲解,稍等。

2.3 获取文件或文件夹的信息

fs.stat(path, callback)能够获取path路径的信息,比如创建时间,修改时间,文件大小,当前是否为文件,当前是否为文件夹等信息;如果path路径不存在,则抛出异常。

fs.stat('./test.js', function(err, stats){
 if( err ){
 console.log( '路径错误' );
 throw err;
 }
 console.log(stats);
 console.log( 'isfile: '+stats.isFile() ); // 是否为文件
 console.log( 'isdir: '+stats.isDirectory() ); // 是否为文件夹
});

结果:

{
 dev: -29606086,
 mode: 33206,
 nlink: 1,
 uid: 0,
 gid: 0,
 rdev: 0,
 blksize: undefined,
 ino: 2251799813687343,
 size: 2063, // path路径为文件夹时,size为0
 blocks: undefined,
 atime: Thu Jan 12 2017 21:12:36 GMT+0800 (中国标准时间),
 mtime: Sat Jan 14 2017 21:57:26 GMT+0800 (中国标准时间),
 ctime: Sat Jan 14 2017 21:57:26 GMT+0800 (中国标准时间),
 birthtime: Thu Jan 12 2017 21:12:36 GMT+0800 (中国标准时间)
}
isfile: true // 是否为文件
isdir: false // 是否为文件夹

关于这几个时间属性的理解,可以参考这篇文章。

stats中的size属性就是当前文件的大小(单位:字节,除以1024即为kb),stats还有下面方法可供使用:

  1. stats.isFile()
  2. stats.isDirectory()
  3. stats.isBlockDevice()
  4. stats.isCharacterDevice()
  5. stats.isSymbolicLink() (only valid with fs.lstat())
  6. stats.isFIFO()
  7. stats.isSocket()

fs.stat(path, callback)是异步执行的,对应的还有同步执行版本:fs.statSync(path) ,这个方法返回的就是fs.stats实例。

三、综合运用

我们在上面的讲解中,还留着两个功能没实现,这里实现一下它的过程。

3.1 遍历目录中所有的文件

我们已经知道使用readdir只能获取当前目录里的文件和文件夹名称,为了获取这个目录里所有的文件名称,只能是读取当前目录里所有的文件夹里的文件。这里我们使用递归的方法,如果当前资源是文件,则进行存储,是文件夹则进行递归进一步检索,直到把所有的文件夹遍历完毕。

// 获取文件夹中所有的文件
function readDirAll(path){
 // 获取字符串的最后一个字符
 var getLastCode = function(str){
  return str.substr(str.length-1, 1);
 }

 var result = []; // 存储获取到的文件
 var stats = fs.statSync(path); // 获取当前文件的状态
 if( stats.isFile() ){
  result.push(path);
 }else if( stats.isDirectory() ){
  // 若当前路径是文件夹,则获取路径下所有的信息,并循环
  var files = fs.readdirSync(path);

  for(var i=0, len=files.length; i<len; i++){
   var item = files[i],
    itempath = getLastCode(path)=='/' ? path+item : path+'/'+item; // 拼接路径
   var st = fs.statSync(itempath);
   if( st.isFile() ){
    result.push(itempath);
   }else if( st.isDirectory() ){
    // 当前是文件夹,则递归检索,将递归获取到的文件列表与当前result进行拼接
    var s = readDirAll( itempath );
    result = result.concat( s );
   }
  }
 }
 return result;
}
console.log( readDirAll('./') );

使用此程序获取当前目录中所有的文件(展示的为部分文件):

[ 
 './bing.doc',
 './img/1484234634801.png',
 './img/1484234660592.png',
 './img/test.png',
 './inter.js',
 './msg.txt',
 './node_modules/formidable/.npmignore',
 './node_modules/formidable/.travis.yml',
 './node_modules/formidable/index.js',
 './node_modules/formidable/lib/file.js',
 './node_modules/formidable/lib/incoming_form.js',
 './node_modules/formidable/lib/index.js',
 ...
]

如果想要输出一种树形的结构,就可以对当前的递归程序进行改造,比如我想要输出如下的这种结果,那么,就要分析这种结构的特点:

bing.doc         
img           
 |---1484234634801.png     
 |---1484234660592.png     
 |---test.png       
inter.js         
msg.txt          
node_modules        
 |---formidable       
  |---.npmignore      
  |---.travis.yml      
  |---index.js      
  |---lib        
   |---file.js 
   |---incoming_form.js 
   |---index.js

可以看出的规律:

  1. 第一层级的文件和文件夹前面是没有空格和字符的;
  2. 第一级子目录中的文件或文件夹前面是1组空格和1个字符;
  3. 第二级子目录中的文件或文件夹前面是2组空格和1个字符;
  4. 依次类推…

我们可以再传递一个depth来表示当前目录的层级,然后计算出前面空格的数量:

// depth为递归的深度,可根据递归的深度输出文件名称前面的格式
function readDirAll(path, depth){
 // 获取字符串
 var getLastCode = function(str){
  return str.substr(str.length-1, 1);
 }

 depth = depth || 0; // 默认为0
 var fir_code = '';

 // 计算文件名称前面的字符,4个空格为1组
 for(var j=0; j<depth; j++){
  fir_code += ' ';
 }
 depth && (fir_code += '|---');

 var stats = fs.statSync(path);
 if( stats.isFile() ){
  console.log( fir_code+path );
 }else if( stats.isDirectory() ){
  var files = fs.readdirSync(path);
  for(var i=0, len=files.length; i<len; i++){
   var item = files[i],
    itempath = getLastCode(path)=='/' ? path+item : path+'/'+item,
    st = fs.statSync(itempath);

   console.log( fir_code+item );
   if( st.isDirectory() ){
    var s = readDirAll( itempath, depth+1 );
   }
  }
 }
}
console.log( readDirAll('./') );

3.2 删除目录

使用fs.rmdir(path)是有局限性的,只能删除空目录,如果是个非空目录,我们可以根据上面的思路,写出一个能删除当前目录下所有的文件。递归,只要找到里面的文件夹就递归寻找,直到找到最底层,把最底层的文件删除,然后再逐级向上删除文件夹,直到删除到当前目录。

// 删除path下所有的文件和文件夹,包括path自己
function rmDirAll(path){
 // 获取字符串
 var getLastCode = function(str){
  return str.substr(str.length-1, 1);
 }

 var stats = fs.statSync(path); // 获取当前文件的状态
 if( stats.isFile() ){
  fs.unlinkSync(path);
  console.log( '删除成功: '+path );
 }else if( stats.isDirectory() ){
  // 若当前路径是文件夹,则获取路径下所有的信息,并循环
  var files = fs.readdirSync(path);

  for(var i=0, len=files.length; i<len; i++){
   var item = files[i],
    itempath = getLastCode(path)=='/' ? path+item : path+'/'+item; // 拼接路径
   var st = fs.statSync(itempath);
   if( st.isFile() ){
    fs.unlinkSync(itempath);
    console.log( '删除成功: '+itempath );
   }else if( st.isDirectory() ){
    // 当前是文件夹,则递归检索
    rmDirAll( itempath );
   }
  }
  // 现在可以删除文件夹
  fs.rmdir(path);
  console.log( '删除成功: '+path );
 }
}
rmDirAll('./img');

则删除时输出的信息如下,先把内部的文件和文件夹删除干净,最后删除 ‘./img':

删除成功: ./img/1484234634801.png
删除成功: ./img/1484234660592.png
删除成功: ./img/gggg/est.txt
删除成功: ./img/gggg
删除成功: ./img/test.png
删除成功: ./img

当然,你也可以试着实现这样的程序:

  1. 删除path内部所有的内容,同时能保留下path目录
  2. 只删除文件,将所有的空文件夹保留下来
  3. 将内部所有的文件都移动到path的根目录下,并删除空文件夹

等等,都可以试着实现一下。

总结

以上就是这篇文章的全部内容了,其实文件系统里也有很多的内容需要学习,这里只是抛砖引玉,希望通过自己一点的微薄知识,能为大家指点迷津。小编还会继续分享关于node入门学习的文章,感兴趣的朋友们请继续关注三水点靠木。

Javascript 相关文章推荐
Javascript类库的顶层对象名用户体验分析
Oct 24 Javascript
JS仿flash上传头像效果实现代码
Jul 18 Javascript
Javascript 垃圾收集机制介绍理解
May 14 Javascript
js(jQuery)获取时间的方法及常用时间类搜集
Oct 23 Javascript
IE、FF浏览器下修改标签透明度
Jan 28 Javascript
jquery删除指定的html标签并保留标签内文本内容的方法
Apr 02 Javascript
使用jquery解析XML示例代码
Sep 05 Javascript
jQuery通过ajax快速批量提交表单数据
Oct 25 Javascript
深入理解ES6之数据解构的用法
Jan 13 Javascript
ES6之Proxy的get方法详解
Oct 11 Javascript
基于纯JS实现多张图片的懒加载Lazy过程解析
Oct 14 Javascript
绘制微信小程序验证码功能的实例代码
Jan 05 Javascript
JavaScript实现按键精灵的原理分析
Feb 21 #Javascript
javascript 组合按键事件监听实现代码
Feb 21 #Javascript
简单谈谈gulp-changed插件
Feb 21 #Javascript
从零学习node.js之搭建http服务器(二)
Feb 21 #Javascript
jQuery动态生成不规则表格(前后端)
Feb 21 #Javascript
jquery设置css样式的多种方法(总结)
Feb 21 #Javascript
JavaScript中 this 指向问题深度解析
Feb 21 #Javascript
You might like
Php注入点构造代码
2008/06/14 PHP
CodeIgniter框架提示Disallowed Key Characters的解决办法
2014/04/21 PHP
PHP中的类型约束介绍
2015/05/11 PHP
浅谈PHP5.6 与 PHP7.0 区别
2019/10/09 PHP
Javascript客户端脚本的设计和应用
2006/08/21 Javascript
使用ajaxfileupload.js实现ajax上传文件php版
2014/06/26 Javascript
javascript 常见功能汇总
2015/06/11 Javascript
纯HTML5制作围住神经猫游戏-附源码下载
2015/08/23 Javascript
Javascript使用uploadify来实现多文件上传
2016/11/16 Javascript
JS作用域深度解析
2016/12/29 Javascript
angular中实现控制器之间传递参数的方式
2017/04/24 Javascript
QRCode.js:基于JQuery的生成二维码JS库的使用
2017/06/23 jQuery
微信小程序实现添加手机联系人功能示例
2017/11/30 Javascript
JavaScript惰性求值的一种实现方法示例
2019/01/11 Javascript
微信小程序Flex布局用法深入浅出分析
2019/04/25 Javascript
简单分析js中的this的原理
2019/08/31 Javascript
vue自定义switch开关组件,实现样式可自行更改
2019/11/01 Javascript
解决Vue在Tomcat8下部署页面不加载的问题
2019/11/12 Javascript
Python基于回溯法子集树模板解决旅行商问题(TSP)实例
2017/09/05 Python
python中装饰器级连的使用方法示例
2017/09/29 Python
Django使用 Bootstrap 样式修改书籍列表过程解析
2019/08/09 Python
tensorflow的ckpt及pb模型持久化方式及转化详解
2020/02/12 Python
python中使用paramiko模块并实现远程连接服务器执行上传下载功能
2020/02/29 Python
Python Scrapy框架:通用爬虫之CrawlSpider用法简单示例
2020/04/11 Python
解决img标签上下出现间隙的方法
2016/12/14 HTML / CSS
HTML5 拖拽批量上传文件的示例代码
2018/03/28 HTML / CSS
英国户外服装、鞋类和设备的领先零售商:Millets
2020/10/12 全球购物
下面代码从性能上考虑,有什么问题
2015/04/03 面试题
小饰品店的创业计划书范文
2013/12/28 职场文书
大学生自我鉴定范文模板
2014/01/21 职场文书
山东省召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
2014年调度员工作总结
2014/11/19 职场文书
罚站检讨书
2015/01/29 职场文书
学雷锋广播稿大全
2015/08/19 职场文书
2016年七夕情人节宣传语
2015/11/25 职场文书
导游词之河姆渡遗址博物馆
2019/10/10 职场文书