Nodejs 文件 与 路径 相关用法
1.路径
(1)引入path模块
const path = require('path');
(2)当前文件所在目录的绝对路径:__dirname
console.log("__dirname =",__dirname);
__dirname = g:\NodeJs\fs
(3)路径连接:path.join()
path.join() 方法使用特定于平台的分隔符作为定界符将所有给定的 path 片段连接在一起,然后规范化生成的路径。
- 零长度的 path 片段被忽略;
- 如果连接的路径字符串是零长度字符串,则将返回 ‘.’,表示当前工作目录。
const joined_path = path.join(__dirname, 'NodeJs', 'textFile.txt') console.log(joined_path);
g:\NodeJs\fs\NodeJs\textFile.txt
(4)获取文件名:path.basename()
const filename = path.basename('g:\\NodeJs\\fs\\NodeJs\\textFile.txt') console.log(filename);
textFile.txt
(5)获取文件扩展名:path.extname()
const surfix = path.extname('g:\\NodeJs\\fs\\NodeJs\\textFile.txt') console.log(surfix);
.txt
(6)分解绝对路径:path.parse()
- root: 根目录/ 磁盘名
- dir: 文件或文件夹所在文件夹完整绝对路径
- base: 文件/文件夹名加扩展(非绝对路径)
- ext: 扩展名
- name: 文件/文件夹名
const parserst = path.parse('g:\\NodeJs\\fs\\NodeJs\\textFile.txt') console.log(parserst);console.log();
{ root: 'g:\\', dir: 'g:\\NodeJs\\fs\\NodeJs', base: 'textFile.txt', ext: '.txt', name: 'textFile' }
(7)从对象返回路径字符串:path.format()
与path.parse()
功能相反
const pt = path.format({ root: 'g:\\', dir: 'g:\\NodeJs\\fs\\NodeJs', base: 'textFile.txt' }); console.log(pt);
g:\NodeJs\fs\NodeJs\textFile.txt
(8)判断是否是绝对路径:path.isAbsolute()
const isAbs1 = path.isAbsolute('g:\\NodeJs\\fs\\NodeJs\\textFile.txt'); const isAbs2 = path.isAbsolute('textFile.txt'); console.log('isAbs1是绝对路径吗:',isAbs1); console.log('isAbs2是绝对路径吗:',isAbs2);
isAbs1是绝对路径吗: true isAbs2是绝对路径吗: false
(9)返回两端路径之间的相对路径表示:path.relative()
const path1 = '/data/orandea/test/aaa'; const path2 = '/data/orandea/impl/bbb'; const relativepath = path.relative(path1,path2) console.log('path2在path1的相对表示为:',relativepath);console.log();
path2在path1的相对表示为: ..\..\impl\bbb
(10)将路径或路径片段的序列解析为绝对路径:path.resolve()
// 给定的路径序列从右到左处理,每个后续的 path 会被追加到前面,直到构建绝对路径。 console.log(path.resolve('/foo/bar', '/tmp/file/')); console.log(path.resolve('NodeJs', 'fs/NodeJs/', 'textFile'));
G:\tmp\file G:\NodeJs\NodeJs\fs\NodeJs\textFile
(11)将路径分割为数组:path.sep
(注意与不同系统的路径分隔符有关)
console.log('foo\\bar\\baz'.split(path.sep));console.log();
[ 'foo', 'bar', 'baz' ]
注意区分不同系统上的路径分隔符不同。
(12)获取当前操作系统上的路径定界符:path.delimiter
console.log('路径定界符为:',path.delimiter);
路径定界符为: ;
应用
const processEnvPATH = process.env.PATH console.log(processEnvPATH); console.log(processEnvPATH.split(path.delimiter));console.log();
C:\Program Files\PowerShell\7;C:\Program Files\AdoptOpenJDK\jdk-11.0.8.10-hotspot\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\PowerShell\7\;D:\Program Files\Dart\dart-sdk\bin;C:\Program Files\PuTTY\;D:\Program Files\nodejs\;C:\ProgramData\chocolatey\bin;C:\Program Files (x86)\Yarn\bin\;C:\Program Files\Docker\Docker\resources\bin;C:\ProgramData\DockerDesktop\version-bin;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Program Files\MySQL\MySQL Shell 8.0\bin\;C:\Users\a2911\AppData\Local\Programs\Python\Python39\Scripts\;C:\Users\a2911\AppData\Local\Programs\Python\Python39\;C:\Users\a2911\AppData\Local\Microsoft\WindowsApps;D:\flutter;C:\Users\a2911\AppData\Local\GitHubDesktop\bin;C:\Users\a2911\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\a2911\AppData\Local\Yarn\bin;D:\flutter\bin;C:\Users\a2911\.dotnet\tools;D:\Program Files\Nox\bin;C:\Users\a2911\AppData\Roaming\npm; [ 'C:\\Program Files\\PowerShell\\7', 'C:\\Program Files\\AdoptOpenJDK\\jdk-11.0.8.10-hotspot\\bin', 'C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath', 'C:\\Program Files\\Common Files\\Oracle\\Java\\javapath', 'C:\\WINDOWS\\system32', 'C:\\WINDOWS', 'C:\\WINDOWS\\System32\\Wbem', 'C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\', 'C:\\WINDOWS\\System32\\OpenSSH\\', 'C:\\Program Files\\PowerShell\\7\\', 'D:\\Program Files\\Dart\\dart-sdk\\bin', 'C:\\Program Files\\PuTTY\\', 'D:\\Program Files\\nodejs\\', 'C:\\ProgramData\\chocolatey\\bin', 'C:\\Program Files (x86)\\Yarn\\bin\\', 'C:\\Program Files\\Docker\\Docker\\resources\\bin', 'C:\\ProgramData\\DockerDesktop\\version-bin', 'C:\\Program Files\\dotnet\\', 'C:\\Program Files\\Git\\cmd', 'C:\\Program Files\\MySQL\\MySQL Shell 8.0\\bin\\', 'C:\\Users\\a2911\\AppData\\Local\\Programs\\Python\\Python39\\Scripts\\', 'C:\\Users\\a2911\\AppData\\Local\\Programs\\Python\\Python39\\', 'C:\\Users\\a2911\\AppData\\Local\\Microsoft\\WindowsApps', 'D:\\flutter', 'C:\\Users\\a2911\\AppData\\Local\\GitHubDesktop\\bin', 'C:\\Users\\a2911\\AppData\\Local\\Programs\\Microsoft VS Code\\bin', 'C:\\Users\\a2911\\AppData\\Local\\Yarn\\bin', 'D:\\flutter\\bin', 'C:\\Users\\a2911\\.dotnet\\tools', 'D:\\Program Files\\Nox\\bin', 'C:\\Users\\a2911\\AppData\\Roaming\\npm', '' ]
(13)返回所在文件夹绝对路径:path.dirname()
const dir = path.dirname('g:\\NodeJs\\fs\\NodeJs\\textFile.txt'); console.log(dir);
g:\NodeJs\fs\NodeJs
2. 文件
(1)引入相关模块
const path = require('path');
(2)异步地获取指定文件的相关信息:access()
const file = 'g:\\NodeJs\\textFile.txt'; // 检查当前目录中是否存在该文件。 fs.access(file, fs.constants.F_OK, (err) => { console.log(`${file} ${err ? '不存在' : '存在'}`); }); // 检查文件是否可读。 fs.access(file, fs.constants.R_OK, (err) => { console.log(`${file} ${err ? '不可读' : '可读'}`); }); // 检查文件是否可写。 fs.access(file, fs.constants.W_OK, (err) => { console.log(`${file} ${err ? '不可写' : '可写'}`); }); // 检查当前目录中是否存在文件,是否可写。 fs.access(file, fs.constants.F_OK | fs.constants.W_OK, (err) => { if (err) { console.error( `${file} ${err.code === 'ENOENT' ? '不存在' : '是 只读文件'}`); } else { console.log(`${file} 存在, 并且它是可写的`); } });
g:\NodeJs\textFile.txt 存在 g:\NodeJs\textFile.txt 可读 g:\NodeJs\textFile.txt 可写 g:\NodeJs\textFile.txt 存在, 并且它是可写的
(3)复制文件(自动创建或覆盖目标):copyFile()
let sourceFile = 'g:\\NodeJs\\textfile.txt'; let destinationFile = 'g:\\NodeJs\\textfile.txt'; // 定义复制操作后执行的回调函数 function callBack(err) { if (err) {throw err} else{ console.log('文件顺利复制完成'); }; } fs.copyFile(sourceFile, destinationFile, callBack);
文件顺利复制完成
(4)复制文件(文件存在则报错):fs.constants.COPYFILE_EXCL
let sourceFile = 'g:\\NodeJs\\textfile.txt'; let destinationFile = 'g:\\NodeJs\\textfile.txt'; function callBack(err) { if (err) throw err; console.log('文件顺利复制完成'); } fs.copyFile(sourceFile, destinationFile, fs.constants.COPYFILE_EXCL, callBack);
[Error: EEXIST: file already exists, copyfile 'g:\NodeJs\textfile.txt' -> 'g:\NodeJs\textfile.txt'] { errno: -4075, code: 'EEXIST', syscall: 'copyfile', path: 'g:\\NodeJs\\textfile.txt', dest: 'g:\\NodeJs\\textfile.txt' }
(5)打开文件:open()
let target = 'G:\\NodeJs\\fs\\a.txt' let a = fs.open(target, 'r', (err,fd)=>{ if(err){throw err} else{ console.log("文件已在内存中加载"); } })
注:
fs.open(path[, flags[, mode]], callback)
- path:文件路径
- flags:文件打开方式;
- mode(可选):文件权限模式,默认为可读写;
- Callback:回调函数,带有err和fd两个参数。
其中回调函数callback(err,fd)的两个参数中:
- err:打开时的异常;
fd
:文件描述符。
一个文件打开以后,需要在操作完后对其关闭(见关闭文件:close()
部分)以释放内存资源,并确认其正确关闭,这是需要用到这些曾今打开过的文件的文件描述符。也就是说该参数是用来跟踪一个已经打开的文件的,他在读取方法read()
和关闭方法close()
中都需要用到。
flag | 含义 |
r | 以只读模式打开文件,文件不存在时抛出异常 |
r+ | 以读写模式打开文件,文件不存在时抛出异常 |
rs | 以同步方式读取文件 |
rs+ | 以同步方式读写文件 |
w | 以只写模式打开文件,文件不存在时自动将其创建 |
wx | 以只写模式打开文件,如果文件路径存在则写入失败 |
w+ | 以读写模式打开文件,文件不存在时自动将其创建 |
wx+ | 以读写模式打开文件,如果文件路径存在则写入失败 |
a | 以追加模式打开文件,文件不存在时自动创建 |
ax | 以追加模式打开文件,文件存在时将导致追加失败 |
(6)关闭文件:close()
该方法时open()
的逆过程,需要接收open()方法返回的fd
(文件描述符)参数以跟踪一个打开的文件进行关闭。
let target = 'G:\\NodeJs\\fs\\a.txt' let a = fs.open(target, 'r', (err,fd)=>{ if(err){throw err} else{ console.log("文件已在内存中加载"); fs.close(fd, (error)=>{ if(error){console.log(error)} else{ console.log("文件关闭成功"); } }) } })
文件已在内存中加载 文件关闭成功
(7)写入文件:writeFile()
let file = 'message.txt'; const data = new Uint8Array(Buffer.from('这是一些用于写入的文字')); fs.writeFile(file, data, (err) => { if (err) throw err; console.log('文件已被写入'); });
文件已被写入
可以看到生成了一个文本文件:
(8)异步地将数据追加到文件:appendFile()
如果该文件尚不存在,则将自动创建该文件
// 将数据追加到文件,如果该文件尚不存在,则创建该文件 let file_path = 'g:\\NodeJs\\newfile.txt'; let datas = 'some text to append...' fs.appendFile(file_path, datas, (err) => { if (err) throw err; console.log('The ' + datas + ', was appended to file!'); });
(9)读取文件:readFile()
假设我们在path指定处有一个文本,其内容为文本:这里有一些文字
直接读取这个文本文件:
let path = './fs/a.txt'; fs.readFile(path , (err, data) => { if (err) {throw err} else{console.log(data)} });
<Buffer e8 bf 99 e9 87 8c e6 9c 89 e4 b8 80 e4 ba 9b e6 96 87 e5 ad 97>
可以看到由于未指定编码,则返回原始缓冲区数据。由于此处文本是先前使用utf-8格式保存的,我们可以这样读取:
fs.readFile('./fs/a.txt', 'utf8', (err, data) => { if (err) {throw err} else{console.log(data)} });
这里有一些文字
注:这里这API都是异步的,且有相应的同步API,函数名相差不过多了一个Sync
,比如我们也可以使用同步API读取文件:
let uts8Text = fs.readFileSync('./fs/a.txt',"utf8",'r+'); console.log(uts8Text)
这里有一些文字
(10)读取文件:read()
该方法需要提供以open()
方法打开所返回的fd
(文件资源定位符)参数作为参数。其格式为:
fs.read(fd, [options,] callback)
- fd:通过
open()
方法返回的文件描述符; - buffer(可选):数据写入的缓冲区;
- offset(可选):写入缓冲区时的写入偏移量;
- length(可选):要从文件中读取的字节数;
- position(可选):文件读取的起始位置,当为
null
时,就会从当前文件指针的位置进行读取。
let target = 'G:\\NodeJs\\fs\\a.txt' fs.open(target, 'r', (err,fd)=>{ if(err){throw err} else{ console.log("文件已加载\n"); let readUf = Buffer.alloc(1024); let offset = 0; let length = readUf.length; let position = null; fs.read(fd, readUf, offset, length, position, (ery, bytesRead)=>{ if(ery){throw err} else{ console.log('读取文件大小',bytesRead +'bytes\n'); let rst = readUf.slice(0,bytesRead); console.log('Buffer形式:',rst,'\n'); console.log('以UTF-8编码转为字符串:',rst.toString('utf8'),'\n'); fs.close(fd, (error)=>{ if(error){console.log(error)} else{ console.log("文件关闭成功"); } }) } }) } })
文件已加载 读取文件大小 36bytes Buffer形式: <Buffer e8 bf 99 e9 87 8c e6 9c 89 e4 b8 80 e4 ba 9b e7 94 a8 e4 ba 8e e8 af bb e5 8f 96 e7 9a 84 e6 96 87 e5 ad 97> 以UTF-8编码转为字符串: 这里有一些用于读取的文字 文件关闭成功
(11)异步地创建文件夹:mkdir()
fs.mkdir('./newFolder', { recursive: true }, (err) => { if (err) {throw err} else{ console.log('新文件夹创建成功'); }; });
新文件夹创建成功
如果成功,则将在指定目录下看到一个新的名为newFolder
的文件夹。
(12)异步地删除文件和目录:rm()
function callBack(err) { if (err) throw err; console.log('文件删除完成'); } fs.rm('a.text', {force: false , maxRetries: 0, recursive: false, retryDelay: 100,}, callBack)
如果文件不存在:
[Error: ENOENT: no such file or directory, stat 'xxxxxx'] { errno: -4058, code: 'ENOENT', syscall: 'stat', path: 'xxxxxx' }
(13)异步地删除目录:fs.rmdir
在文件(而不是目录)上使用 fs.rmdir(),则在 Windows 上会导致 ENOENT 错误,在 POSIX 上会导致 ENOTDIR 错误。
function callBack(err) { if (err) throw err; console.log('文件夹删除完成'); } fs.rm('folder', { maxRetries: 0, recursive: false, retryDelay: 100,}, callBack)
(14)读取文件夹(中的所有项目的名字):fs.readdir()
即 读取目录
,其读取的内容既包括文件名也包括目录名。(不是绝对路径表示)
let dirName = 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css'; fs.readdir(dirName,{encoding: 'utf8', withFileTypes: false },(err:any, data:string[]) =>{ if (err) {throw err }else{console.log(data); } });
[ 'app.6605356c.css', 'chunk-vendors.574a9ade.css', 'login.6d2c5898.css' ]
获取给定文件夹中所有内容(文件和文件夹)的绝对路径
没有直接的方法,不过也很简单:
let dirName = 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css'; fs.readdir(dirName,{encoding: 'utf8', withFileTypes: false },(err:any, data:string[]) =>{ if (err) {throw err} else{ for(let i =0; i<data.length;i++){ data[i] = path.join(dirName,data[i]); }; console.log(data); } });
如果withFileTypes
参数为true
,则返回项目中将带有文件类型信息,如:
[ Dirent { name: 'app.6605356c.css', [Symbol(type)]: 1 }, Dirent { name: 'chunk-vendors.574a9ade.css', [Symbol(type)]: 1 }, Dirent { name: 'login.6d2c5898.css', [Symbol(type)]: 1 } ]
注:其相应的同步函数为readFileSync()
,用法相同,如:
let dirName = 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css'; let ary = fs.readdirSync(dirName, 'utf8'); console.log(ary);
[ 'app.6605356c.css', 'chunk-vendors.574a9ade.css', 'login.6d2c5898.css' ]
另外,有对应的同步API为readdirSync()
,其用法基本用法基本相似:
let dirName = 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css'; let a = fs.readdirSync(dirName, 'utf8', false) console.log(a);
[ 'app.6605356c.css', 'chunk-vendors.574a9ade.css', 'login.6d2c5898.css' ]
如果要返回文件夹中所有文件的完整路径,可以和之前用同样的方法:
function getDirItemsAbsPath(dirName:string):string[]{ let absPaths:string[] = []; fs.readdirSync(dirName, 'utf8', false).forEach((elem:string) => { absPaths.push(path.join(dirName,elem)) }); return absPaths } let dirName = 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css'; let dirItemsAbsPath = getDirItemsAbsPath(dirName) console.log(dirItemsAbsPath);
[ 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css\\app.6605356c.css', 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css\\chunk-vendors.574a9ade.css', 'G:\\mobile-flutter\\jcstdio\\assets\\coder\\statics\\css\\login.6d2c5898.css' ]
(15)创建名为 path 指向 target 的链接:symlink()
function callBack(err) { if (err) throw err; } let target = 'G:\\NodeJs\\fs\\a.txt' let path = 'C:\\Users\\a2911\\Desktop\\a_link' fs.symlink(target, path, callBack);
成功执行后,可以看到path
指定处产生了一个链接名为a_link(Windows中也称快捷方式)
该函数也有其对应的同步函数,为:symlinkSync()
用法基本类似。