Node fs模块

1. fs 模块

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

2. 整体读取文件

2.1 异步读取

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

2.2 同步读取

fs.readFileSync(path[, options])
fs.readFileSync(path[, options])

3. 写入文件

3.1 异步写入

fs.writeFile(file, data[, options], callback)
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");
});
let fs = require("fs");
fs.writeFile("./1.txt", Date.now() + "\n", { flag: "a" }, function () {
  console.log("ok");
});

3.2 同步写入

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

3.3 追加文件

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

fs.appendFile("./1.txt", Date.now() + "\n", function () {
  console.log("ok");
});
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);
  });
}
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) {});
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());
  });
});
//  前端笔记
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()); //  前端笔记
  });
});
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("写入完毕!");
      });
    });
  });
});
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")
);
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");
});
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);
fs.rename(oldPath, newPath, callback);

5.6 删除文件

fs.unlink(path, callback);
fs.unlink(path, callback);

5.7 截断文件

fs.ftruncate(fd[, len], callback)
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"));
});
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)
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("修改");
  }
});
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);
    }
  }
}
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();
}
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);
    }
  }
}
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"));
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("删除成功");
});
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");
});
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");
});
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);
    }
  }
}
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();
    }
  })();
}
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
    
          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);
        }
      });
    }
    
    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);
      });
    }
    
    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));
          });
        }
      }
    }
    
    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"));
// 异步广度遍历
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 :
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+会自动把已有文件的内容清空。