导航菜单

  • 0.api
  • 0.Async
  • 0.module
  • 1.ES2015
  • 2.Promise
  • 3.Node
  • 4.NodeInstall
  • 5.REPL
  • 6.NodeCore
  • 7.module&NPM
  • 8.Encoding
  • 9.Buffer
  • 10.fs
  • 11.Stream-1
  • 11.Stream-2
  • 11.Stream-3
  • 11.Stream-4
  • 12-Network-2
  • 12.NetWork-3
  • 12.Network-1
  • 13.tcp
  • 14.http-1
  • 14.http-2
  • 15.compress
  • 16.crypto
  • 17.process
  • 18.yargs
  • 19.cache
  • 20.action
  • 21.https
  • 22.cookie
  • 23.session
  • 24.express-1
  • 24.express-2
  • 24.express-3
  • 24.express-4
  • 25.koa-1
  • 26.webpack-1-basic
  • 26.webpack-2-optimize
  • 26.webpack-3-file
  • 26.webpack-4.tapable
  • 26.webpack-5-AST
  • 26.webpack-6-sources
  • 26.webpack-7-loader
  • 26.webpack-8-plugin
  • 26.webpack-9-hand
  • 26.webpack-10-prepare
  • 28.redux
  • 28.redux-jwt-back
  • 28.redux-jwt-front
  • 29.mongodb-1
  • 29.mongodb-2
  • 29.mongodb-3
  • 29.mongodb-4
  • 29.mongodb-5
  • 29.mongodb-6
  • 30.cms-1-mysql
  • 30.cms-2-mysql
  • 30.cms-3-mysql
  • 30.cms-4-nunjucks
  • 30.cms-5-mock
  • 30.cms-6-egg
  • 30.cms-7-api
  • 30.cms-8-roadhog
  • 30.cms-9-yaml
  • 30.cms-10-umi
  • 30.cms-12-dva
  • 30.cms-13-dva-ant
  • 30.cms-14-front
  • 30.cms-15-deploy
  • 31.dva
  • 31.cms-13-dva-antdesign
  • 33.redis
  • 34.unittest
  • 35.jwt
  • 36.websocket-1
  • 36.websocket-2
  • 38.chat-api-1
  • 38.chat-api-2
  • 38.chat-3
  • 38.chat-api-3
  • 38.chat
  • 38.chat2
  • 38.chat2
  • 39.crawl-0
  • 39.crawl-1
  • 39.crawl-2
  • 40.deploy
  • 41.safe
  • 42.test
  • 43.nginx
  • 44.enzyme
  • 45.docker
  • 46.elastic
  • 47.oauth
  • 48.wxpay
  • index
  • 52.UML
  • 53.design
  • index
  • 54.linux
  • 57.ts
  • 56.react-ssr
  • 58.ts_react
  • 59.ketang
  • 59.ketang2
  • 61.1.devops-linux
  • 61.2.devops-vi
  • 61.3.devops-user
  • 61.4.devops-auth
  • 61.5.devops-shell
  • 61.6.devops-install
  • 61.7.devops-system
  • 61.8.devops-service
  • 61.9.devops-network
  • 61.10.devops-nginx
  • 61.11.devops-docker
  • 61.12.devops-jekins
  • 61.13.devops-groovy
  • 61.14.devops-php
  • 61.15.devops-java
  • 61.16.devops-node
  • 61.17.devops-k8s
  • 62.1.react-basic
  • 62.2.react-state
  • 62.3.react-high
  • 62.4.react-optimize
  • 62.5.react-hooks
  • 62.6.react-immutable
  • 62.7.react-mobx
  • 62.8.react-source
  • 63.1.redux
  • 63.2.redux-middleware
  • 63.3.redux-hooks
  • 63.4.redux-saga
  • 63.5.redux-saga-hand
  • 64.1.router
  • 64.2.router-connected
  • 65.1.typescript
  • 65.2.typescript
  • 65.3.typescript
  • 65.4.antd
  • 65.4.definition
  • 66-1.vue-base
  • 66-2.vue-component
  • 66-3.vue-cli3.0
  • 66-4.$message组件
  • 66-5.Form组件
  • 66-6.tree
  • 66-7.vue-router-apply
  • 66-8.axios-apply
  • 66-9.vuex-apply
  • 66-10.jwt-vue
  • 66-11.vue-ssr
  • 66-12.nuxt-apply
  • 66-13.pwa
  • 66-14.vue单元测试
  • 66-15.权限校验
  • 67-1-network
  • 68-2-wireshark
  • 7.npm2
  • 69-hooks
  • 70-deploy
  • 71-hmr
  • 72.deploy
  • 73.import
  • 74.mobile
  • 75.webpack-1.文件分析
  • 75.webpack-2.loader
  • 75.webpack-3.源码流程
  • 75.webpack-4.tapable
  • 75.webpack-5.prepare
  • 75.webpack-6.resolve
  • 75.webpack-7.loader
  • 75.webpack-8.module
  • 75.webpack-9.chunk
  • 75.webpack-10.asset
  • 75.webpack-11.实现
  • 76.react_optimize
  • 77.ts_ketang_back
  • 77.ts_ketang_front
  • 78.vue-domdiff
  • 79.grammar
  • 80.tree
  • 81.axios
  • 82.1.react
  • 82.2.react-high
  • 82.3.react-router
  • 82.4.redux
  • 82.5.redux_middleware
  • 82.6.connected
  • 82.7.saga
  • 82.8.dva
  • 82.8.dva-source
  • 82.9.roadhog
  • 82.10.umi
  • 82.11.antdesign
  • 82.12.ketang-front
  • 82.12.ketang-back
  • 83.upload
  • 84.graphql
  • 85.antpro
  • 86.1.uml
  • 86.2.design
  • 87.postcss
  • 88.react16-1
  • 89.nextjs
  • 90.react-test
  • 91.react-ts
  • 92.rbac
  • 93.tsnode
  • 94.1.JavaScript
  • 94.2.JavaScript
  • 94.3.MODULE
  • 94.4.EventLoop
  • 94.5.文件上传
  • 94.6.https
  • 94.7. nginx
  • 95.1. react
  • 95.2.react
  • 96.1.react16
  • 96.2.fiber
  • 96.3.fiber
  • 97.serverless
  • 98.websocket
  • 100.1.react-basic
  • 101.1.monitor
  • 101.2.monitor
  • 102.java
  • 103.1.webpack-usage
  • 103.2.webpack-bundle
  • 103.3.webpack-ast
  • 103.4.webpack-flow
  • 103.5.webpack-loader
  • 103.6.webpack-tapable
  • 103.7.webpack-plugin
  • 103.8.webpack-optimize1
  • 103.9.webpack-optimize2
  • 103.10.webpack-hand
  • 103.11.webpack-hmr
  • 103.11.webpack5
  • 103.13.splitChunks
  • 103.14.webpack-sourcemap
  • 103.15.webpack-compiler1
  • 103.15.webpack-compiler2
  • 103.16.rollup.1
  • 103.16.rollup.2
  • 103.16.rollup.3
  • 103.16.vite.basic
  • 103.16.vite.source
  • 103.16.vite.plugin
  • 103.16.vite.1
  • 103.16.vite.2
  • 103.17.polyfill
  • 104.1.binary
  • 104.2.binary
  • 105.skeleton
  • 106.1.react
  • 106.2.react_hooks
  • 106.3.react_router
  • 106.4.redux
  • 106.5.redux_middleware
  • 106.6.connected-react-router
  • 106.6.redux-first-history
  • 106.7.redux-saga
  • 106.8.dva
  • 106.9.umi
  • 106.10.ketang
  • 106.11.antdesign
  • 106.12.antpro
  • 106.13.router-6
  • 106.14.ssr
  • 106.15.nextjs
  • 106.16.1.cms
  • 106.16.2.cms
  • 106.16.3.cms
  • 106.16.4.cms
  • 106.16.mobx
  • 106.17.fomily
  • 107.fiber
  • 108.http
  • 109.1.webpack_usage
  • 109.2.webpack_source
  • 109.3.dll
  • 110.nest.js
  • 111.xstate
  • 112.Form
  • 113.redux-saga
  • 114.react+typescript
  • 115.immer
  • 116.pro5
  • 117.css-loader
  • 118.1.umi-core
  • 119.2.module-federation
  • 119.1.module-federation
  • 120.create-react-app
  • 121.react-scripts
  • 122.react-optimize
  • 123.jsx-runtime
  • 124.next.js
  • 125.1.linux
  • 125.2.linux-vi
  • 125.3.linux-user
  • 125.4.linux-auth
  • 125.5.linux-shell
  • 125.6.linux-install
  • 125.7.linux-system
  • 125.8.linux-service
  • 125.9.linux-network
  • 125.10.nginx
  • 125.11.docker
  • 125.12.ci
  • 125.13.k8s
  • 125.14.k8s
  • 125.15.k8s
  • 125.16.k8s
  • 126.11.react-1
  • 126.12.react-2
  • 126.12.react-3
  • 126.12.react-4
  • 126.12.react-5
  • 126.12.react-6
  • 126.12.react-7
  • 126.12.react-8
  • 127.frontend
  • 128.rollup
  • 129.px2rem-loader
  • 130.health
  • 131.hooks
  • 132.keepalive
  • 133.vue-cli
  • 134.react18
  • 134.2.react18
  • 134.3.react18
  • 135.function
  • 136.toolkit
  • 137.lerna
  • 138.create-vite
  • 139.cli
  • 140.antd
  • 141.react-dnd
  • 142.1.link
  • 143.1.gulp
  • 143.2.stream
  • 143.3.gulp
  • 144.1.closure
  • 144.2.v8
  • 144.3.gc
  • 145.react-router-v6
  • 146.browser
  • 147.lighthouse
  • 148.1.basic
  • 148.2.basic
  • 148.3.basic
  • 148.4.basic
  • 148.5.basic
  • 149.1.vite
  • 149.2.vite
  • 149.3.vite
  • 149.4.vite
  • 150.react-window
  • 151.react-query
  • 152.useRequest
  • 153.transition
  • 154.emotion
  • 155.1.formily
  • 155.2.formily
  • 155.3.formily
  • 155.3.1.mobx.usage
  • 155.3.2.mobx.source
  • 156.vue-loader
  • 103.11.mf
  • 157.1.react18
  • 158.umi4
  • 159.rxjs
  • 159.rxjs2
  • 160.bff
  • 161.zustand
  • 162.vscode
  • 163.emp
  • 164.cors
  • 1. fs模块
  • 2. 整体读取文件
    • 2.1 异步读取
    • 2.2 同步读取
  • 3. 写入文件
    • 3.1 异步写入
    • 3.2 同步写入
    • 3.3 追加文件
    • 3.4 拷贝文件
  • 4. 从指定位置处开始读取文件
    • 4.1 打开文件
    • 4.2 读取文件
    • 4.3 写入文件
    • 4.4 同步磁盘缓存
    • 4.5 关闭文件
    • 4.6 拷贝文件
  • 5 目录操作
    • 5.1 创建目录
    • 5.2 判断一个文件是否有权限访问
    • 5.3 读取目录下所有的文件
    • 5.4 查看文件目录信息
    • 5.5 移动文件或目录
    • 5.6 删除文件
    • 5.7 截断文件
    • 5.8 监视文件或目录
  • 6 递归创建目录
    • 6.1 同步创建目录
    • 6.2 异步创建目录
    • 6.3 Async+Await创建目录
  • 7. 递归删除目录
    • 7.1 同步删除目录(深度优先)
    • 7.2 异步删除非空目录(Promise版)
    • 7.3 异步串行删除目录(深度优先)
    • 7.4 异步并行删除目录(深度优先)
    • 7.5 同步删除目录(广度优先)
    • 7.6 异步删除目录(广度优先)
  • 8. 遍历算法
    • 8.1 同步深度优先+先序遍历
    • 8.2 异步深度优先+先序遍历
    • 8.3 同步广度优先+先序遍历
    • 8.4 异步广度优先+先序遍历
  • 8. path模块
  • 9. flags
  • 10. 助记
  • 11. linux权限

1. fs模块 #

  • 在Node.js中,使用fs模块来实现所有有关文件及目录的创建、写入及删除操作。
  • 在fs模块中,所有的方法都分为同步和异步两种实现。
  • 具有sync后缀的方法为同步方法,不具有sync后缀的方法为异步方法。

2. 整体读取文件 #

2.1 异步读取 #

fs.readFile(path[, options], callback)
  • options
    • encoding
    • flag flag 默认 = 'r'

2.2 同步读取 #

fs.readFileSync(path[, options])

3. 写入文件 #

3.1 异步写入 #

fs.writeFile(file, data[, options], callback)
  • options
    • encoding
    • flag flag 默认 = 'w'
    • mode 读写权限,默认为0666
let fs = require('fs');
fs.writeFile('./1.txt',Date.now()+'\n',{flag:'a'},function(){
  console.log('ok');
});

3.2 同步写入 #

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

3.3 追加文件 #

fs.appendFile(file, data[, options], callback)

fs.appendFile('./1.txt',Date.now()+'\n',function(){
  console.log('ok');
})

3.4 拷贝文件 #

function copy(src,target){
  fs.readFile(src,function(err,data){
    fs.writeFile(target,data);
  })
}

4. 从指定位置处开始读取文件 #

4.1 打开文件 #

fs.open(filename,flags,[mode],callback);

  • FileDescriptor 是文件描述符
  • FileDescriptor 可以被用来表示文件
  • in -- 标准输入(键盘)的描述符
  • out -- 标准输出(屏幕)的描述符
  • err -- 标准错误输出(屏幕)的描述符
fs.open('./1,txt','r',0600,function(err,fd){});

4.2 读取文件 #

fs.read(fd, buffer, offset, length, position, callback((err, bytesRead, buffer)))

//前端培训
const fs=require('fs');
const path=require('path');
fs.open(path.join(__dirname,'1.txt'),'r',0o666,function (err,fd) {
    console.log(err);
    let buf = Buffer.alloc(6);
     fs.read(fd,buf,0,6,3,function(err, bytesRead, buffer){
       console.log(bytesRead);//6
       console.log(buffer===buf);//true
       console.log(buf.toString());//峰培
     })
})

4.3 写入文件 #

fs.write(fd, buffer[, offset[, length[, position]]], callback)

const fs=require('fs');
const path=require('path');
fs.open(path.join(__dirname,'1.txt'),'w',0o666,function (err,fd) {
    console.log(err);
    let buf=Buffer.from('前端培训');
     fs.write(fd,buf,3,6,0,function(err, bytesWritten, buffer){
       console.log(bytesWritten);//6
       console.log(buffer===buf);//true
       console.log(buf.toString());//前端培训
     })
})

4.4 同步磁盘缓存 #

fs.fsync(fd,[callback]);

4.5 关闭文件 #

fs.close(fd,[callback]);

let buf = Buffer.from('前端培训');
fs.open('./2.txt', 'w', function (err, fd) {
  fs.write(fd, buf, 3, 6, 0, function (err, written, buffer) {
    console.log(written);
    fs.fsync(fd, function (err) {
      fs.close(fd, function (err) {
          console.log('写入完毕!')
        }
      );
    });
  })
});

4.6 拷贝文件 #

let BUFFER_SIZE=1;
const path=require('path');
const fs=require('fs');
function copy(src,dest,callback) {
    let buf=Buffer.alloc(BUFFER_SIZE);
    fs.open(src,'r',(err,readFd)=>{
        fs.open(dest,'w',(err,writeFd) => {
            !function read() {
                fs.read(readFd,buf,0,BUFFER_SIZE,null,(err,bytesRead) => {
                    bytesRead&&fs.write(writeFd,buf,0,bytesRead,read);
                });
            }()
        })
    });
}
copy(path.join(__dirname,'1.txt'),path.join(__dirname,'2.txt'),()=>console.log('ok'));

5 目录操作 #

5.1 创建目录 #

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

要求父目录必须存在

5.2 判断一个文件是否有权限访问 #

fs.access(path[, mode], callback)

fs.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK, (err) => {
  console.log(err ? 'no access!' : 'can read/write');
});

5.3 读取目录下所有的文件 #

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

5.4 查看文件目录信息 #

fs.stat(path, callback)

  • stats.isFile()
  • stats.isDirectory()
  • atime(Access Time)上次被读取的时间。
  • ctime(State Change Time):属性或内容上次被修改的时间。
  • mtime(Modified time):档案的内容上次被修改的时间。

5.5 移动文件或目录 #

fs.rename(oldPath, newPath, callback)

5.6 删除文件 #

fs.unlink(path, callback)

5.7 截断文件 #

fs.ftruncate(fd[, len], callback)
const fd = fs.openSync('temp.txt', 'r+');
// 截断文件至前4个字节
fs.ftruncate(fd, 4, (err) => {
  console.log(fs.readFileSync('temp.txt', 'utf8'));
});

5.8 监视文件或目录 #

fs.watchFile(filename[, options], listener)
let fs = require('fs');
fs.watchFile('1.txt', (curr, prev) => {
  //parse() 方法可解析一个日期时间字符串,并返回 1970/1/1 午夜距离该日期时间的毫秒数。
  if(Date.parse(prev.ctime)==0){
    console.log('创建');
  }else if(Date.parse(curr.ctime)==0){
    console.log('删除');
  }else if(Date.parse(prev.ctime) != Date.parse(curr.ctime)){
    console.log('修改');
  }
});

6 递归创建目录 #

6.1 同步创建目录 #

let fs=require('fs');
let path=require('path');
function makepSync(dir) {
    let parts=dir.split(path.sep);
    for (let i=1;i<=parts.length;i++){
        let parent=parts.slice(0,i).join(path.sep);
        try {
            fs.accessSync(parent);
        } catch (error) {
            fs.mkdirSync(parent);
        }

    }
}

6.2 异步创建目录 #

function makepAsync(dir,callback) {
    let parts=dir.split(path.sep);
    let i=1;
    function next() {
        if (i>parts.length)
            return callback&&callback();    
        let parent=parts.slice(0,i++).join(path.sep);
        fs.access(parent,err => {
            if (err) {
                fs.mkdir(parent,next);
            } else {
                next();
            }
        });
    }
    next();
}

6.3 Async+Await创建目录 #

async function mkdir(parent) {
    return new Promise((resolve,reject) => {
        fs.mkdir(parent,err => {
            if (err) reject(err);
            else resolve();
        });
    });
}

async function access(parent) {
    return new Promise((resolve,reject) => {
        fs.access(parent,err => {
            if (err) reject(err);
            else resolve();
        });
    });
}
async function makepPromise(dir,callback) {
    let parts=dir.split(path.sep);
    for (let i=1;i<=parts.length;i++){
        let parent=parts.slice(0,i).join(path.sep);
        try {
            await access(parent);
        }catch(err) {
            await mkdir(parent);
        }

    }
}

7. 递归删除目录 #

7.1 同步删除目录(深度优先) #

let fs=require('fs');
let path=require('path')
function rmSync(dir) {
    try {
        let stat = fs.statSync(dir);
        if (stat.isFile()) {
            fs.unlinkSync(dir);
        } else {
            let files=fs.readdirSync(dir);
            files
                .map(file => path.join(dir,file))
                .forEach(item=>rmSync(item));
            fs.rmdirSync(dir);
        }
    } catch (e) {
        console.log('删除失败!');
    }
}
rmSync(path.join(__dirname,'a'));

7.2 异步删除非空目录(Promise版) #

function rmPromise(dir) {
    return new Promise((resolve,reject) => {
        fs.stat(dir,(err,stat) => {
            if (err) return reject(err);
            if (stat.isDirectory()) {
                fs.readdir(dir,(err,files) => {
                    let paths = files.map(file => path.join(dir,file));
                    let promises = paths.map(p=>rmPromise(p));
                    Promise.all(promises).then((() => fs.rmdir(dir,resolve)));
                });
            } else {
                fs.unlink(dir,resolve);
            }
        });
    });
}
rmPromise(path.join(__dirname,'a')).then(() => {
    console.log('删除成功');
})

7.3 异步串行删除目录(深度优先) #

function rmAsyncSeries(dir,callback) {
    setTimeout(() => {
        fs.stat(dir,(err,stat) => {
            if (err) return callback(err);
            if (stat.isDirectory()) {
                fs.readdir(dir,(err,files) => {
                    let paths = files.map(file => path.join(dir,file));
                    function next(index) {
                        if (index>=files.length) return fs.rmdir(dir,callback);
                        let current=paths[index];
                        rmAsyncSeries(current,()=>next(index+1));
                    }
                    next(0);
                });
            } else {
                fs.unlink(dir,callback);
            }
        })
    },1000);
}

console.time('cost');
rmAsyncSeries(path.join(__dirname,'a'),err => {
     console.timeEnd('cost');
})

7.4 异步并行删除目录(深度优先) #

function rmAsyncParallel(dir,callback) {
    setTimeout(() => {
        fs.stat(dir,(err,stat) => {
            if (err) return callback(err);
            if (stat.isDirectory()) {
                fs.readdir(dir,(err,files) => {
                    let paths=files.map(file => path.join(dir,file));
                    if (paths.length>0) {
                        let i=0;
                        function done() {
                            if (++i == paths.length) {
                                fs.rmdir(dir,callback);
                            }
                        }
                      paths.forEach(p=>rmAsyncParallel(p,done));
                    } else {
                        fs.rmdir(dir,callback);
                    }
                });
            } else {
                fs.unlink(dir,callback);
            }
        })
    },1000);
}
console.time('cost');
rmAsyncParallel(path.join(__dirname,'a'),err => {
     console.timeEnd('cost');
})

7.5 同步删除目录(广度优先) #

function rmSync(dir){
    let arr=[dir];
    let index=0;
    while (arr[index]) {
        let current=arr[index++];
        let stat=fs.statSync(current);
        if (stat.isDirectory()) {
            let dirs=fs.readdirSync(current);
            arr=[...arr,...dirs.map(d => path.join(current,d))];
        }
    }
    let item;
    while (null != (item = arr.pop())) {
        let stat = fs.statSync(item);
        if (stat.isDirectory()) {
            fs.rmdirSync(item);
        } else {
            fs.unlinkSync(item);
        }
    }
}

7.6 异步删除目录(广度优先) #

function rmdirWideAsync(dir,callback){
    let dirs=[dir];
    let index=0;
    function rmdir() {
        let current = dirs.pop();
        if (current) {
            fs.stat(current,(err,stat) => {
                if (stat.isDirectory()) {
                    fs.rmdir(current,rmdir);
                } else {
                    fs.unlink(current,rmdir);
                }
            });
        }
    }
    !function next() {
        let current=dirs[index++];
        if (current) {
            fs.stat(current,(err,stat) => {
                if (err) callback(err);
                if (stat.isDirectory()) {
                    fs.readdir(current,(err,files) => {
                        dirs=[...dirs,...files.map(item => path.join(current,item))];
                        next();
                    });
                } else {
                    next();
                }
            });
        } else {
            rmdir();
        }

    }();
}

8. 遍历算法 #

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

    8.1 同步深度优先+先序遍历 #

    function deepSync(dir){
      console.log(dir);
      fs.readdirSync(dir).forEach(file=>{
          let child = path.join(dir,file);
          let stat = fs.statSync(child);
          if(stat.isDirectory()){
              deepSync(child);
          }else{
              console.log(child);
          }
      });
    }

    8.2 异步深度优先+先序遍历 #

    function deep(dir,callback) {
      console.log(dir);
      fs.readdir(dir,(err,files)=>{
          !function next(index){
              if(index == files.length){
                  return callback();
              }
              let child = path.join(dir,files[index]);
              fs.stat(child,(err,stat)=>{
                  if(stat.isDirectory()){
                      deep(child,()=>next(index+1));
                  }else{
                      console.log(child);
                      next(index+1);
                  }
              })
          }(0)
      })
    }

    8.3 同步广度优先+先序遍历 #

    function wideSync(dir){
      let dirs = [dir];
      while(dirs.length>0){
          let current = dirs.shift();
          console.log(current);
          let stat = fs.statSync(current);
          if(stat.isDirectory()){
              let files = fs.readdirSync(current);
              files.forEach(item=>{
                  dirs.push(path.join(current,item));
              });
          }
      }
    }

8.4 异步广度优先+先序遍历 #

// 异步广度遍历
function wide(dir, cb) {
    console.log(dir);
    cb && cb()
    fs.readdir(dir, (err, files) => {
        !function next(i){
            if(i>= files.length) return;
            let child = path.join(dir,files[i]);
            fs.stat(child,(err,stat)=>{
                if(stat.isDirectory()){
                    wide(child, () => next(i+1));
                } else {
                    console.log(child);
                    next(i+1);
                }
            })
        }(0);
    })
}
wide(path.join(__dirname,'a'));

8. path模块 #

path是node中专门处理路径的一个核心模块

  • path.join 将多个参数值字符串结合为一个路径字符串
  • path.basename 获取一个路径中的文件名
  • path.extname 获取一个路径中的扩展名
  • path.sep 操作系统提定的文件分隔符
  • path.delimiter 属性值为系统指定的环境变量路径分隔符
  • path.normalize 将非标准的路径字符串转化为标准路径字符串 特点:
    • 可以解析 . 和 ..
    • 多个杠可以转换成一个杠
    • 在windows下反杠会转化成正杠
    • 如结尾以杠结尾的,则保留斜杠
  • resolve
    • 以应用程序根目录为起点
    • 如果参数是普通字符串,则意思是当前目录的下级目录
    • 如果参数是.. 回到上一级目录
    • 如果是/开头表示一个绝对的根路径
var path = require('path');
var fs = require('fs');
/**
 * normalize 将非标准化的路径转化成标准化的路径
 * 1.解析. 和 ..
 * 2.多个斜杠会转成一个斜杠
 * 3.window下的斜杠会转成正斜杠
 * 4.如果以斜杠会保留
 **/

console.log(path.normalize('./a////b//..\\c//e//..//'));
//  \a\c\

//多个参数字符串合并成一个路径 字符串
console.log(path.join(__dirname,'a','b'));

/**
 * resolve
 * 以就用程序为根目录,做为起点,根据参数解析出一个绝对路径
 *  1.以应用程序为根起点
 *  2... .
 *  3. 普通 字符串代表子目录
 *  4. /代表绝地路径根目录
 */
console.log(path.resolve());//空代表当前的目录 路径
console.log(path.resolve('a','/c'));// /a/b
// d:\c
//可以获取两个路径之间的相对关系
console.log(path.relative(__dirname,'/a'));
// a
//返回指定路径的所在目录
console.log(path.dirname(__filename)); // 9.path
console.log(path.dirname('./1.path.js'));//  9.path
//basename 获取路径中的文件名
console.log(path.basename(__filename));
console.log(path.basename(__filename,'.js'));
console.log(path.extname(__filename));

console.log(path.sep);//文件分隔符 window \ linux /
console.log(path.win32.sep);
console.log(path.posix.sep);
console.log(path.delimiter);//路径 分隔符 window ; linux :

9. flags #

符号 含义
r 读文件,文件不存在报错
r+ 读取并写入,文件不存在报错
rs 同步读取文件并忽略缓存
w 写入文件,不存在则创建,存在则清空
wx 排它写入文件
w+ 读取并写入文件,不存在则创建,存在则清空
wx+ 和w+类似,排他方式打开
a 追加写入
ax 与a类似,排他方式写入
a+ 读取并追加写入,不存在则创建
ax+ 作用与a+类似,但是以排他方式打开文件

10. 助记 #

  • r 读取
  • w 写入
  • s 同步
  • + 增加相反操作
  • x 排他方式
  • r+ w+的区别?
    • 当文件不存在时,r+不会创建,而会导致调用失败,但w+会创建。
    • 如果文件存在,r+不会自动清空文件,但w+会自动把已有文件的内容清空。

11. linux权限 #

文件类型与权限 链接占用的节点(i-node) 文件所有者 文件所有者的用户组 文件大小 文件的创建时间 最近修改时间 文件名称

权限

访问验证

请输入访问令牌

Token不正确,请重新输入