nodejs基础认识nodejs详解fs文件系统模块与path路径模块01

Posted 橙子测试笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nodejs基础认识nodejs详解fs文件系统模块与path路径模块01相关的知识,希望对你有一定的参考价值。

 

1.初识 Node.js

浏览器中的 JavaScript 的组成部分

 

为什么 JavaScript 可以在浏览器中被执行

不同的浏览器使用不同的 JavaScript 解析引擎
Chrome 浏览器 => V8
Firefox 浏览器 => OdinMonkey(奥丁猴)
Safri浏览器 => JSCore
IE 浏览器 => Chakra(查克拉)
其中,Chrome 浏览器的 V8 解析引擎性能最好!

为什么 JavaScript 可以操作 DOM 和 BOM

 每个浏览器都内置了 DOM、BOM 这样的 API 函数,因此,浏览器中的 JavaScript 才可以调用它们

浏览器中的 JavaScript 运行环境

运行环境是指代码正常运行所需的必要环境  

总结

  • V8 引擎负责解析和执行 JavaScript 代码
  • 内置 API 是由运行环境提供的特殊接口,只能在所属的运行环境中被调用
JavaScript 能否做后端开发

需要node.js

Node.js 简介

什么是 Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境
官网地址 https://nodejs.org/zh-cn/

Node.js 中的 JavaScript 运行环境

浏览器是 JavaScript 的前端运行环境
Node.js 是 JavaScript 的后端运行环境
Node.js 中无法调用 DOM 和 BOM 等浏览器内置 API
Node.js 可以做什么

Node.js 作为一个 JavaScript 的运行环境,仅仅提供了基础的功能和 API。然而,基于 Node.js 提供的这些基础能,很多强大的工具和框架如雨后春笋,层出不穷,所以学会了 Node.js ,可以让前端程序员胜任更多的工作和岗位  

a 基于 Express 框架 http://www.expressjs.com.cn/ 可以快速构建 Web 应用
b 基于 Electron 框架 https://electronjs.org/ 可以构建跨平台的桌面应用
c 基于 restify 框架 http://restify.com/ 可以快速构建 API 接口项目
d 读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…
Node.js 怎么学

浏览器中的 JavaScript 学习路径

JavaScript 基础语法 + 浏览器内置 API(DOM + BOM) + 第三方库(jQuery、art-template 等)
Node.js 的学习路径
JavaScript 基础语法 + Node.js 内置 API(fs、path、http等)+ 第三方 API 模块(express、mysql 等)

shift+鼠标右键 可以在该目录下打开powershell窗口

在powershell中的快捷键:

⬆,可以快速定位到上一次执行的命令。
tab键,可以快速补全文件的路径(先输入第一个字,然后使用tab键,可以快速补全路径)
ESC,可以快速清空已输入的命令
cls,清空powershell面板

tips:./表示为当前目录,写不写都可以

2.fs 文件系统模块

什么是 fs 文件系统模块
fs 模块是 Node.js 官方提供的、用来操作文件的模块。提供了一系列的方法和属性,用来满足对文件的操作需求
如果要在 JavaScript 代码中,使用 fs 模块来操作文件,则需要使用如下的方式先导入它

const fs = require("fs")
fs.readFile(path[, option], callback)读取指定文件中的内容
path 必选参数,字符串,文件路径
option 可选参数,设置字符集
callback 必选参数,文件读取完成后的回调函数 

// 1. 导入 fs 模块,来操作文件

const fs = require(\'fs\')

// 2. 调用 fs.readFile() 方法读取文件
// 参数1:读取文件的存放路径
// 参数2:读取文件时候采用的编码格式,一般默认指定 utf8
// 参数3:回调函数,拿到读取失败和成功的结果 err dataStr
fs.readFile(\'./files/1.txt\', \'utf8\', function(err, dataStr) 

// 2.1 打印失败的结果
// 如果读取成功,则 err 的值为 null
// 如果读取失败,则 err 的值为 错误对象,dataStr 的值为 undefined

console.log(err)
console.log(\'-------\')

 

// 2.2 打印成功的结果

console.log(dataStr)
)
//一般逻辑可以这么写:
fs.readFile(\'./files/11.txt\', \'utf8\', function(err, dataStr) 
if (err) 
return console.log(\'读取文件失败!\' + err.message)

console.log(\'读取文件成功!\' + dataStr)
)

fs.writeFile(path, data[, option], callback) 向指定的文件中写入内容
path 必选参数,字符串,文件路径
data 必选参数,写入的内容
option 可选参数,设置字符集,默认值是 utf8
callback 必选参数,文件写入完成后的回调函数
注意:写入会覆盖原内容

const fs = require(\'fs\')

// 2. 调用 fs.writeFile() 方法,写入文件的内容
// 参数1:表示文件的存放路径
// 参数2:表示要写入的内容
// 参数3:回调函数

fs.writeFile(\'./files/3.txt\', \'ok123\', function(err) 
// 2.1 如果文件写入成功,则 err 的值等于 null
// 2.2 如果文件写入失败,则 err 的值等于一个 错误对象
// console.log(err)
//判断是否写入成功

  

if (err) 
return console.log(\'文件写入失败!\' + err.message)

console.log(\'文件写入成功!\')
)

省略第三个参数则默认为UTF8格式

前言:路径动拼接的问题

使用fs模块操作文件时,如果提供的操作路径是以./或…/开头的相对路径时,很容易出现路径动态拼接错误的问题。原因:代码在运行的时候,会以执行node命令时所处的目录,动态拼接出被操作文件的完整路径。
解决方案:在使用fs模块操作文件时,直接提供完整的路径,不要提供.或…/开头的相对路径,从而防止路径动态拼接的问题。**注意js中写完整路径要用//,不然会被当成转义字符处理。**但是这种方法移植性差。fs中有解决办法。

__dirname 表示当前文件所处的目录**(即以js文件所处地方为基准),不会根据打开node目录变化而变化(即为打开node的地方为基准)**。

console.log(__dirname)

fs.readFile(__dirname + \'/files/1.txt\', \'utf8\', function(err, dataStr) 
if (err) 
return console.log(\'读取文件失败!\' + err.message)

console.log(\'读取文件成功!\' + dataStr)
)

3.path 路径模块
path 模块是 Node.js 官方提供的、用来处理路径的模块。提供一系列的方法和属性,用来满足对路径的处理需求
如果要在 JavaScript 代码中,使用 path 模块来处理路径,则需要使用如下的方式先导入它

const path = require("path")

path.join(...paths) 可以把多个路径片段拼接为完整的路径字符串
●**…paths ** 路径片段的序列
● 返回
注意:凡是涉及到路径拼接的操作,都要使用 path.join() 方法进行处理。不直接使用 + 进行字符串的拼接

const path = require(\'path\')
const fs = require(\'fs\')

// 注意: ../ 会抵消前面的路径
const pathStr = path.join(\'/a\', \'/b/c\', \'../../\', \'./d\', \'e\')
console.log(pathStr) // \\a\\b\\d\\e

// 取代fs.readFile(__dirname + \'/files/1.txt\', ...)
fs.readFile(path.join(__dirname, \'./files/1.txt\'), \'utf8\', function(err, dataStr) 
if (err) 
return console.log(err.message)

console.log(dataStr)
)

path.basename(path[, ext]) 可以获取路径中的最后一部分,经常通过这个方法获取路径中的文件名
●path 必选参数,表示一个路径的字符串
●ext 可选参数,表示文件扩展名
●返回 路径的最后一部分

const path = require(\'path\')

// 定义文件的存放路径
const fpath = \'/a/b/c/index.html\'

const fullName = path.basename(fpath)
console.log(fullName) // index.html

const nameWithoutExt = path.basename(fpath, \'.html\')
console.log(nameWithoutExt) // index

path.extname(path) 可以获取路径中的扩展名部分
●path 必选参数,表示一个路径的字符串
●返回 返回得到的扩展名字符串

const path = require(\'path\')

// 这是文件的存放路径
const fpath = \'/a/b/c/index.html\'

const fext = path.extname(fpath)
console.log(fext)//输出.html

注意点:

fs.writeFile()方法只能用来创建文件,不能用来创建路径
重复调用fs.writeFile(写入同一个文件,新写入的内容会覆盖之前的旧内容

  

  

nodeJS之fs文件系统

前面的话

  fs文件系统用于对系统文件及目录进行读写操作,本文将详细介绍nodejs中的文件系统

 

概述

  文件 I/O 是由简单封装的标准 POSIX 函数提供的。 通过 require(\'fs\') 使用该模块。 所有的方法都有异步和同步的形式。

  异步形式始终以完成回调作为它最后一个参数。 传给完成回调的参数取决于具体方法,但第一个参数总是留给异常。 如果操作成功完成,则第一个参数会是 null 或 undefined

//异步示例
var fs = require(\'fs\');
fs.unlink(\'/tmp/hello\', function(err){
  if (err) throw err;
  console.log(\'successfully deleted /tmp/hello\');
});

  当使用同步形式时,任何异常都会被立即抛出。 可以使用 try/catch 来处理异常,或让它们往上冒泡

//同步示例
var fs = require(\'fs\');
fs.unlinkSync(\'/tmp/hello\');
console.log(\'successfully deleted /tmp/hello\');

  异步方法不保证执行顺序。 所以下面的例子容易出错

fs.rename(\'/tmp/hello\', \'/tmp/world\', function(err){
  if (err) throw err;
  console.log(\'renamed complete\');
});
fs.stat(\'/tmp/world\', function(err, stats){
  if (err) throw err;
  console.log(\'stats: ${JSON.stringify(stats)}\');
});

  fs.stat 可能在 fs.rename 之前执行。正确的方法是把回调链起来

fs.rename(\'/tmp/hello\', \'/tmp/world\', function(err){
  if (err) throw err;
  fs.stat(\'/tmp/world\', function(err, stats){
    if (err) throw err;
    console.log(\'stats: ${JSON.stringify(stats)}\');
  });
});

  推荐开发者使用这些函数的异步版本。 同步版本会阻塞整个进程,直到它们完成(停止所有连接)

 

底层操作

1、打开文件【fs.open(path, flags[, mode], callback)】

  参数如下:

path <String> | <Buffer>
flags <String> | <Number>
mode <Integer> 设置文件模式(权限和 sticky 位),但只有当文件被创建时才有效。默认为 0666,可读写
callback <Function> 该回调有两个参数 (err错误, fd文件标识,与定时器标识类似)

  flags可以是:

\'r\' - 以读取模式打开文件。如果文件不存在则发生异常。
\'r+\' - 以读写模式打开文件。如果文件不存在则发生异常。
\'rs+\' - 以同步读写模式打开文件。命令操作系统绕过本地文件系统缓存。
\'w\' - 以写入模式打开文件。文件会被创建(如果文件不存在)或截断(如果文件存在)。
\'wx\' - 类似 \'w\',但如果 path 存在,则失败。
\'w+\' - 以读写模式打开文件。文件会被创建(如果文件不存在)或截断(如果文件存在)。
\'wx+\' - 类似 \'w+\',但如果 path 存在,则失败。
\'a\' - 以追加模式打开文件。如果文件不存在,则会被创建。
\'ax\' - 类似于 \'a\',但如果 path 存在,则失败。
\'a+\' - 以读取和追加模式打开文件。如果文件不存在,则会被创建。
\'ax+\' - 类似于 \'a+\',但如果 path 存在,则失败。

  [注意]使用\'rs+\'模式不会使fs.open()进入同步阻塞调用。如果那是你想要的,则应该使用fs.openSync()

var fs = require(\'fs\');
fs.open(\'a.txt\',\'r\',function(err,fs){
    console.log(err);//null
    console.log(fs);//3
})
var fs = require(\'fs\');
fs.open(\'b.txt\',\'r\',function(err,fs){
/*
{ Error: ENOENT: no such file or directory, open \'D:\\project\\b.txt\'
    at Error (native)
  errno: -4058,
  code: \'ENOENT\',
  syscall: \'open\',
  path: \'D:\\\\project\\\\b.txt\' }
 */
    console.log(err);
    console.log(fs);//undefined
})

  文件的回调函数中的第二个参数fd代表文件标识,与定时器标识类似,用于标识文件,且随着文件的打开顺序递增

var fs = require(\'fs\');
fs.open(\'1.txt\',\'r\',function(err,fs){
    console.log(fs);//3
})
fs.open(\'2.txt\',\'r\',function(err,fs){
    console.log(fs);//4
})

【fs.openSync(path, flags[, mode])】

  fs.open() 的同步版本。 返回一个表示文件描述符的整数

var fs = require(\'fs\');
var result = fs.openSync(\'1.txt\',\'r\');
console.log(result);//3

2、读取文件【fs.read(fd, buffer, offset, length, position, callback)】

  参数如下:

fd <Integer> 通过 fs.open() 方法返回的文件描述符
buffer <String> | <Buffer> 数据将被写入到buffer
offset <Integer> buffer中开始写入的偏移量
length <Integer> 指定要读取的字节数(整数)
position <Integer> 指定从文件中开始读取的位置(整数)。 如果position为null,则数据从当前文件位置开始读取
callback <Function> 回调有三个参数 (err, bytesRead, buffer)。err为错误信息,bytesRead表示读取的字节数,buffer为缓冲区对象

  由于使用read()方法,会将文件内容读取buffer对象中,所以需要提前先准备一个buffer对象

var fs = require(\'fs\');
fs.open(\'1.txt\',\'r\',function(err,fd){
    if(err){
        console.log(\'文件打开失败\');
    }else{
        var bf = Buffer.alloc(5);
        fs.read(fd,bf,0,3,null,function(err,len,buffer){
            console.log(err);//null
            console.log(len);//3
            console.log(buffer);//<Buffer 61 61 61 00 00>
        })
    }
});

【fs.readSync(fd, buffer, offset, length, position)】

  fs.read() 的同步版本,返回 bytesRead 的数量

var fs = require(\'fs\');
var fd = fs.openSync(\'1.txt\',\'r\');
var bf = Buffer.alloc(5);
var result = fs.readSync(fd,bf,0,3,null);
console.log(result);//3

3、写入文件【fs.write(fd, buffer, offset, length[, position], callback)】

  参数如下

fd <Integer>  文件标识
buffer <String> | <Buffer> 要将buffer中的数据写入到文件中
offset <Integer> buffer对象中要写入的数据的起始位置
length <Integer> length是一个整数,指定要写入的字节数
position <Integer> 指定从文件开始写入数据的位置的偏移量。 如果 typeof position !== \'number\',则数据从当前位置写入
callback <Function> 回调有三个参数(err, written, buffer),其中written指定从buffer写入了多少字节

  [注意]多次对同一文件使用fs.write且不等待回调,是不安全的。对于这种情况,强烈推荐使用 fs.createWriteStream

  当我们要对打开的文件进行写操作的时候,打开文件的模式应该是读写模式

var fs = require(\'fs\');
fs.open(\'1.txt\',\'r+\',function(err,fd){
    if(err){
        console.log(\'文件打开失败\');
    }else{
        var bf = Buffer.from(\'test\');
        fs.write(fd,bf,0,3,null,function(err,len,buffer){
            console.log(err);//null
            console.log(len);//3
            console.log(buffer);//<Buffer 74 65 73 74>
        })
    }
});

【fs.write(fd, data[, position[, encoding]], callback)】

  该方法写入data到fd指定的文件。如果data不是一个Buffer实例,则该值将被强制转换为一个字符串

  不同于写入 buffer,该方法整个字符串必须被写入。不能指定子字符串,这是因为结果数据的字节偏移量可能与字符串的偏移量不同

fd  <Integer> 文件标识
data <String> | <Buffer> 要将string或buffer中的数据写入到文件中
position <Integer> 指向从文件开始写入数据的位置的偏移量。 如果 typeof position !== \'number\',则数据从当前位置写入
encoding <String> 期望的字符串编码
callback <Function> 回调有三个参数(err, written, str),其中written指定从str写入了多少字节
var fs = require(\'fs\');
fs.open(\'1.txt\',\'r+\',function(err,fd){
    if(err){
        console.log(\'文件打开失败\');
    }else{
        fs.write(fd,\'12345\',function(err,len,str){
            console.log(err);//null
            console.log(len);//5
            console.log(str);//<Buffer 74 65 73 74>
        })
    }
});

【fs.writeSync()】

  fs.write() 的同步版本。返回写入的字节数

var fs = require(\'fs\');
var fd = fs.openSync(\'1.txt\',\'r+\');
var bf = Buffer.alloc(5);
var result = fs.writeSync(fd,bf,0,3,null);
console.log(result);//3

4、关闭文件【fs.close(fd, callback)】

  一个文件被操作后,要及时将该文件关闭

  参数如下:

fd - 通过 fs.open() 方法返回的文件描述符。
callback - 回调函数,没有参数。
var fs = require(\'fs\');
fs.open(\'1.txt\',\'r+\',function(err,fd){
    if(err){
        console.log(\'文件打开失败\');
    }else{
        fs.close(fd, function(err){
            if (err){
                console.log(err);
            } 
            console.log("文件关闭成功");
        });
    }
});

【fs.closeSync(fd)】

  fs.close(fd, callback)的同步版本,返回undefined

var fs = require(\'fs\');
var fd = fs.openSync(\'1.txt\',\'r+\');
fs.closeSync(fd);

 

File操作

  上一部分介绍的都是些底层的操作,接下来将介绍一些更便捷的文件操作。使用下列方法的时候,不需要再打开和关闭文件,直接操作即可

1、写入文件

【fs.writeFile(file, data[, options], callback)】

  异步的将数据写入一个文件,如果文件不存在则新建,如果文件原先存在,会被替换

  参数如下:

file - 文件名或文件描述符。
data - 要写入文件的数据,可以是 String(字符串) 或 Buffer(流) 对象。
options - 该参数是一个对象,包含 {encoding, mode, flag}。默认编码为 utf8, 模式为 0666 , flag 为 \'w\'
callback - 回调函数,回调函数只包含错误信息参数(err),在写入失败时返回。
var fs = require(\'fs\');
var filename = \'1.txt\';
fs.writeFile(filename,\'hello\',function(err){
    console.log(err);//null
})

【fs.writeFileSync(file, data[, options])】

  fs.writeFile() 的同步版本。返回 undefined

var fs = require(\'fs\');
var filename = \'1.txt\';
fs.writeFileSync(filename,\'abc\');

2、追加文件

【fs.appendFile(filename, data, [options], callback)】

  异步地追加数据到一个文件,如果文件不存在则创建文件。 data 可以是一个字符串或 buffer

  参数如下

file - 文件名或文件描述符。
data - 要写入文件的数据,可以是 String(字符串) 或 Buffer(流) 对象。
options - 该参数是一个对象,包含 {encoding, mode, flag}。默认编码为 utf8, 模式为 0666 , flag 为 \'w\'
callback - 回调函数,回调函数只包含错误信息参数(err),在写入失败时返回。
var fs = require(\'fs\');
var filename = \'1.txt\';
fs.appendFile(filename,\' world\',function(err){
    console.log(err);//null
})

【fs.appendFileSync(file, data[, options])】

  fs.appendFile()的同步版本。返回undefined

var fs = require(\'fs\');
var filename = \'1.txt\';
fs.appendFileSync(filename,\' lalala\');

3、读取文件

【fs.readFile(file[, options], callback)】

  参数如下

file - 文件名或文件描述符
options - 该参数是一个对象,包含 {encoding, flag}。默认编码为null,即如果字符编码未指定,则返回原始的 buffer;flag默认为\'r\'
callback - 回调函数,回调有两个参数 (err, data),其中data是文件的内容(buffer对象),err是错误信息参数,在写入失败时返回
var fs = require(\'fs\');
var filename = \'1.txt\';
fs.readFile(filename,function(err,data){
    if(err){
        console.log(\'文件读取失败\');
    }else{
        console.log(data);//<Buffer 61 62 63 20 77 6f 72 6c 64 20 6c 61 6c 61 6c 61>
        console.log(data.toString());//\'abc world lalala\'
    }
});

【fs.readFileSync(file[, options])】

  fs.readFile的同步版本。返回file的内容

  如果指定了encoding选项,则该函数返回一个字符串,否则返回一个buffer

var fs = require(\'fs\');
var filename = \'1.txt\';
var result = fs.readFileSync(filename);
console.log(result);//<Buffer 61 62 63 20 77 6f 72 6c 64 20 6c 61 6c 61 6c 61>
console.log(result.toString());\'abc world lalala\'

4、删除文件

【fs.unlink(path, callback)】

  参数如下:

path - 文件路径。
callback - 回调函数,没有参数。
var fs = require(\'fs\');
var filename = \'1.txt\';
fs.unlink(filename, function(err) {
   if (err) {
       return console.log(\'删除失败\');
   }
   console.log("删除成功");
});

【fs.unlinkSync(path)】

  fs.unlink(path, callback)的同步版本,返回值为undefined

var fs = require(\'fs\');
var filename = \'1.txt\';
fs.unlink(filename);

5、重命名

【fs.rename(oldPath, newPath, callback)】

  参数如下:

oldPath <String> | <Buffer>
newPath <String> | <Buffer>
callback <Function> 回调只有一个可能的异常参数
var fs = require(\'fs\');
var filename = \'a.txt\';
fs.rename(filename,\'2.new.txt\',function(err){
    console.log(err);//null
})

【fs.renameSync(oldPath, newPath)】

  fs.rename(oldPath, newPath, callback)的同步版本,返回undefined

var fs = require(\'fs\');
var filename = \'2.new.txt\';
var result = fs.renameSync(filename,\'a.txt\');

6、文件信息

【fs.stat(path, callback)】

  fs.stat()执行后,会将stats类的实例返回给其回调函数。可通过stats类中的提供方法判断文件的相关属性

  参数如下:

path - 文件路径。
callback - 回调函数,带有两个参数如:(err, stats), stats 是 fs.Stats 对象
var fs = require(\'fs\');
var filename = \'a.txt\';
fs.stat(filename,function(err,stats){
    console.log(err);//null
/*
{ dev: 223576,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: undefined,
  ino: 7599824371527537,
  size: 0,
  blocks: undefined,
  atime: 2017-06-03T14:18:15.370Z,
  mtime: 2017-06-03T14:18:15.370Z,
  ctime: 2017-06-03T16:32:05.776Z,
  birthtime: 2017-06-03T14:18:15.370Z }
 */    
    console.log(stats);
});

  stats类中的方法有

stats.isFile()  如果是文件返回 true,否则返回 false。
stats.isDirectory() 如果是目录返回 true,否则返回 false。
stats.isBlockDevice()   如果是块设备返回 true,否则返回 false。
stats.isCharacterDevice()   如果是字符设备返回 true,否则返回 false。
stats.isSymbolicLink()  如果是软链接返回 true,否则返回 false。
stats.isFIFO()  如果是FIFO,返回true,否则返回false。FIFO是UNIX中的一种特殊类型的命令管道。
stats.isSocket()    如果是 Socket 返回 true,否则返回 false
var fs = require(\'fs\');
var filename = \'a.txt\';
fs.stat(filename,function(err,stats){
    console.log(stats.isFile());//true
});

【fs.statSync(path)】

  fs.stat(path, callback)方法的同步版本,返回一个 fs.Stats 实例

var fs = require(\'fs\');
var filename = \'a.txt\';
var result = fs.statSync(filename);
/*
{ dev: 223576,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: undefined,
  ino: 7599824371527537,
  size: 0,
  blocks: undefined,
  atime: 2017-06-03T14:18:15.370Z,
  mtime: 2017-06-03T14:18:15.370Z,
  ctime: 2017-06-03T16:32:05.776Z,
  birthtime: 2017-06-03T14:18:15.370Z }
 */
console.log(result);

7、监听

【fs.watch(filename[, options][, listener])】

  该方法用于监视filename的变化,filename可以是一个文件或一个目录。返回的对象是一个fs.FSWatcher

  参数如下

filename <String> | <Buffer>
options <String> | <Object> 参数可选,如果options是一个字符串,则它指定了encoding。否则options应该以一个对象传入
    persistent <Boolean> 指明如果文件正在被监视,进程是否应该继续运行。默认为true
    recursive <Boolean> 指明是否全部子目录应该被监视,或只是当前目录。 适用于当一个目录被指定时,且只在支持的平台。默认为false
    encoding <String> 指定用于传给监听器的文件名的字符编码。默认为\'utf8\'
listener <Function> 回调函数有两个参数 (eventType, filename)。 eventType可以是\'rename\'或\'change\',filename是触发事件的文件的名称

  回调中提供的 filename 参数仅在 Linux 和 Windows 系统上支持。 即使在支持的平台中,filename 也不能保证提供。 因此,不要以为 filename 参数总是在回调中提供,如果它是空的,需要有一定的后备逻辑

fs.watch(\'somedir\', (eventType, filename) => {
  console.log(`事件类型是: ${eventType}`);
  if (filename) {
    console.log(`提供的文件名: ${filename}`);
  } else {
    console.log(\'未提供文件名\');
  }
});
var fs = require(\'fs\');
var filename = \'1.txt\';
fs.watch(filename,function(eventType, _filename){
    console.log(eventType);//change
    if(_filename){
        console.log(_filename + \'发生了改变\');//\'1.txt发生了改变\'
    }else{
        console.log(\'...\');
    }
    
})

  [注意]当一个文件出现或消失在一个目录里时,\'rename\'也会被触发

 

目录操作

1、创建

【fs.mkdir(path[, mode], callback)】

  参数如下:

path - 文件路径。
mode - 设置目录权限,默认为 0777。
callback - 回调函数,回调只有一个可能的异常参数
var fs = require(\'fs\');
fs.mkdir(\'./1\',function(err){
    console.log(err);//null
})

【fs.mkdirSync(path[, mode])】

  fs.mkdir(path[, mode], callback)的同步版本,返回undefined

var fs = require(\'fs\');
fs.mkdirSync(\'./2\');

2、删除

【fs.rmdir(path, callback)】

  参数如下:

path - 文件路径。
callback - 回调函数,回调只有一个可能的异常参数
var fs = require(\'fs\');
fs.rmdir(\'./1\',function(err){
    console.log(err);//null
})

【fs.rmdirSync(path, callback)】

  fs.rmdir(path, callback)的同步版本,返回undefined

var fs = require(\'fs\');
fs.rmdirSync(\'./2\');

3、读取

【fs.readdir(path[, options], callback)】

  参数如下:

path <String> | <Buffer>
options <String> | <Object> 可选的 options 参数用于传入回调的文件名,它可以是一个字符串并指定一个字符编码,或是一个对象且由一个 encoding 属性指定使用的字符编码。 如果 encoding 设为 \'buffer\',则返回的文件名会被作为 Buffer 对象传入
    encoding <String> 默认 = \'utf8\'
callback <Function> 回调有两个参数 (err, files),其中 files 是目录中不包括 \'.\' 和 \'..\' 的文件名的数组
var fs = require(\'fs\');
fs.readdir(\'./\',function(err,data){
    console.log(err);//null
/*
[ \'.csslintrc\',
  \'.jshintrc\',
  \'a.txt\',
  \'dist\',
  \'Gruntfile.js\',
  \'Gruntfile1.js\',
  \'index.html\',
  \'main.js\',
  \'node_modules\',
  \'package.json\',
  \'src\' ]
 */
    console.log(data);
})
var fs = require(\'fs\');
fs.readdir(\'./\',function(err,data){
    data.forEach(function(item,index,arr){
        fs.stat(item,function(err,stats){
            if(stats.isFile()){
                console.log(\'文件:\' + item);
            }
            if(stats.isDirectory()){
                console.log(\'目录:\' + item);
            }
        });    
    })

})
/*
文件:.jshintrc
文件:.csslintrc
目录:dist
文件:Gruntfile.js
文件:index.html
文件:Gruntfile1.js
文件:main.js
目录:node_modules
文件:package.json
文件:a.txt
目录:src
 */

【fs.readdirSync(path[, options], callback)】

  fs.readdir(path[, options], callback)的同步版本,返回一个不包括 \'.\' 和 \'..\' 的文件名的数组

var fs = require(\'fs\');
var result = fs.readdirSync(\'./\');
/*
[ \'.csslintrc\',
  \'.jshintrc\',
  \'a.txt\',
  \'dist\',
  \'Gruntfile.js\',
  \'Gruntfile1.js\',
  \'index.html\',
  \'main.js\',
  \'node_modules\',
  \'package.json\',
  \'src\' ]
 */
console.log(result);

 

遍历目录

  遍历目录是操作文件时的一个常见需求。比如写一个程序,需要找到并处理指定目录下的所有JS文件时,就需要遍历整个目录

  遍历目录时一般使用递归算法,否则就难以编写出简洁的代码。递归算法与数学归纳法类似,通过不断缩小问题的规模来解决问题

function factorial(n) {
    if (n === 1) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

  上边的函数用于计算N的阶乘(N!)。可以看到,当N大于1时,问题简化为计算N乘以N-1的阶乘。当N等于1时,问题达到最小规模,不需要再简化,因此直接返回1

  目录是一个树状结构,在遍历时一般使用深度优先+先序遍历算法。深度优先,意味着到达一个节点后,首先接着遍历子节点而不是邻居节点。先序遍历,意味着首次到达了某节点就算遍历完成,而不是最后一次返回某节点才算数。因此使用这种遍历方式时,下边这棵树的遍历顺序是A > B > D > E > C > F

          A
         / \\
        B   C
       / \\   \\
      D   E   F

  了解了必要的算法后,我们可以简单地实现以下目录遍历函数

function travel(dir, callback) {
    fs.readdirSync(dir).forEach(function (file) {
        var pathname = path.join(dir, file);

        if (fs.statSync(pathname).isDirectory()) {
            travel(pathname, callback);
        } else {
            callback(pathname);
        }
    });
}

  可以看到,该函数以某个目录作为遍历的起点。遇到一个子目录时,就先接着遍历子目录。遇到一个文件时,就把文件的绝对路径传给回调函数。回调函数拿到文件路径后,就可以做各种判断和处理。因此假设有以下目录

- /home/user/
    - foo/
        x.js
    - bar/
        y.js
    z.css

  使用以下代码遍历该目录时,得到的输入如下

travel(\'/home/user\', function (pathname) {
    console.log(pathname);
});

------------------------
/home/user/foo/x.js
/home/user/bar/y.js
/home/user/z.css

  如果读取目录或读取文件状态时使用的是异步API,目录遍历函数实现起来会有些复杂,但原理完全相同。travel函数的异步版本如下

function travel(dir, callback, finish) {
    fs.readdir(dir, function (err, files) {
        (function next(i) {
            if (i < files.length) {
                var pathname = path.join(dir, files[i]);

                fs.stat(pathname, function (err, stats) {
                    if (stats.isDirectory()) {
                        travel(pathname, callback, function () {
                            next(i + 1);
                        });
                    } else {
                        callback(pathname, function () {
                            next(i + 1);
                        });
                    }
                });
            } else {
                finish && finish();
            }
        }(0));
    });
}

 

以上是关于nodejs基础认识nodejs详解fs文件系统模块与path路径模块01的主要内容,如果未能解决你的问题,请参考以下文章

nodeJs文件系统(fs)与流(stream)

nodeJs文件系统(fs)与流(stream)

物联网服务NodeJs-5天学习第二天篇① ——fs文件系统

nodeJS之fs文件系统

nodejs之fs模块

NodeJS 文件系统 fs - 是不是可以创建要下载到下载文件夹的文件