nodejs---fs模块,文件读写操作详解,自定义一个文件写入方法

fs模块导入

Node.js 同时支持 CommonJS 和 ES 模块系统(自 Node.js v12 以来)

// 两种模块导入方式
import * as fs from 'fs';// Es6:这种方式需要在package.json中配置"type": "module"
const fs = require('fs');// commonJs:如果你只有一个单文件js那么你还是要使用这种方式导入

是否使用ES6的导入方式,取决于你是否有一个配置文件,或者就使用require导入

fs的读写文件方法

fs提供的文件操作方法包含3中模式:回调式,阻塞式,promise式

这里使用stat()方法举例,

检查文件信息 stat()

const fs = require('fs');// commonJs
const txt = '../public/file.txt'

// 回调式
fs.stat(txt, (err, stats) => {
  if(err){
    console.log(err.message);
  }
  console.log(stats.isFile());
})

// 阻塞式
try {
  const stats = fs.statSync(txt);
} catch (err) {
  console.error(err);
}
console.log(stats.isFile());

// promise式
async function example() {
  try {
    const stats = await fs.stat(txt);
  } catch (err) {
    console.log(err);
  }
  console.log(stats.isFile());
}
example();

使用后面两种方法时需要使用try,catch来捕获错误,

这里要注意 :如果不存在txt路径的文件,会产生错误,这种错误式 被捕获的err提示的,并非式致命错误(直接终止程序),它会提示你没有这个文件,而后面对这个文件的操作也会无法执行,

读取文件内容 readFile()

// 读取文件, 读取文件内容,并返回一个字符串
fs.readFile(txt, 'utf8', (err, data) => {
  if(err){
    console.log(err.message);
  }
  console.log(data);
}) 

参数:文件路径,读取格式(默认式二进制流格式),回调参数,err错误信息,data读取的数据

同样的,readFile也支持三种模式:回调式,阻塞式,promise式,这里仅展示回调式

写入文件writeFile()

// 写入文件, 写入文件内容,
fs.writeFile(txt, 'hello world', (err) => {
  if(err){
    console.log(err.message);
  }
  console.log('写入成功');
})

参数:文件路径,写入的内容,回调参数,err错误信息

同样的,writeFile也支持三种模式:回调式,阻塞式,promise式,这里仅展示回调式

追加内容appendFile()

fs.appendFile(txt, 'hello world', (err) => {
  if(err){
    console.log(err.message);
  }
  console.log('追加成功');
})

参数:文件路径,写入的内容,回调参数,err错误信息

同样的,appendFile也支持三种模式:回调式,阻塞式,promise式,这里仅展示回调式

注意 writeFile会覆盖原内容,从起始位置开始写入,appendFile不覆盖原内容,从末尾位置开始写入

文件夹操作

判断一个文件夹是否存在
使用 fs.existsSync(),这里exists不推荐使用了,事实上,对于文件夹的操作都建议使用阻塞式,因为文件都必须在文件夹下操作,文件夹没有被获取的话,文件操作就无法正常执行
新建一个文件夹
使用 fs.mkdir() 或 fs.mkdirSync()  创建新文件夹
读取目录的内容
使用 fs.readdir() 或 fs.readdirSync() 读取目录的内容。
重命名文件夹
使用 fs.rename() 或 fs.renameSync()  重命名文件夹。
删除文件夹
使用 fs.rmdir() 或 fs.rmdirSync() 删除文件夹。

新建一个文件夹

这里展示如何新建一个文件夹,其他方法类似,想了解更多可以参考:在 Node.js 中使用文件夹 (nodejs.cn)

const fs = require('fs');
const path = "./public/";

try {
  // 如果没有public文件夹则创建
  if (!fs.existsSync(path)) {
    fs.mkdirSync(path);
  }
} catch (err) {
  console.error(err);
}

封装一个setFile方法

了解了基本的读写操作后我们可以封装一个方法,

该函数接收一个文件名和一个文件内容作为参数,并将文件内容写入指定的文件中(没有则创建),路径是当前目录下新建一个public文件夹,并将文件至于public下面。

/**
 * @param {文件名称} baseName 
 * @param {写入的内容} content 
 * @param {内容是否覆盖} b 默认为false,不覆盖
 */

 setFile(baseName,content,b)
module.exports.setFile = function (baseName, content, b = false) {
  // 如果没有public文件夹则创建
  try {
    if (!fs.existsSync(path)) {
      fs.mkdirSync(path);
      console.log("文件夹 public 创建成功");
    }
  } catch (err) {
    console.log(err);
  }

  // 判断文件是否存在,在open之前判断,回调结果在open之后
  fs.stat(path + baseName, (err) => {
    if (err) {// 文件不存在,产生错误
      // console.log(err);
      console.log(`文件 ${baseName} 创建成功`);
    }
  })

  if (!b) {
    // 不覆盖内容

    // fs.readFile(path + baseName, "utf-8",(err, data) => {
    //   if (err) {
    //     console.error(err);
    //   }
    //   // 读取出原来的内容拼接
    //   content = data + content;

    //   fs.writeFile(path + baseName, content, (err) => {
    //     if (err) {
    //       console.error(err);
    //     }
    //     console.log("写入成功");
    //   })
    // })

    fs.appendFile(path + baseName, content, (err) => {
      if (err) {
        console.error(err);
      } else {
        console.log("写入成功");
      }
    })

  } else {
    fs.writeFile(path + baseName, content, (err) => {
      if (err) {
        console.error(err);
      } else {
        console.log("写入成功");
      }
    })
  }

}

在同目录下新建一个useSetFile.js导入这个方法

// 导出的模块是整个文件,需要通过属性引入使用里面的方法
const setFile = require('./setFile');

const file = 'file.txt';
const content = 'Hello, World!';

setFile.setFile(file, content);

在控制台执行node useSetFile.js

 

可以看到目录下多了一个public文件夹和file.txt文件,并且写入了两个hello,world!

数据流缓冲区读写---open,close,read,write方法

出来file后缀的文件操作方法,fs模块还有基于数据流的读写方法,关于二进制数据流可以参考:

js二进制数据,文件---ArrayBuffer,二进制数组_js arraybuffer()-CSDN博客

// 打开文件,'w+/a+' 获得读,写权限,文件流起始位置在开头/末尾(a相比于a+没有读取权限), 如果文件不存在则创建,读取文件后会覆盖原有文件
fs.open(txt, 'a', (err, fd) => {
  if(err){
    console.log(err.message);
  }
  // 关闭文件, 关闭文件后才能进行其他操作
  fs.close(fd, (err) => {
    if(err){
      console.log(err.message);
    }
    console.log('文件关闭成功');
  })
})



/**
 * fd, 使用fs.open打开成功后返回的文件描述符
 * buffer, 一个Buffer对象,v8引擎分配的一段内存
 * offset, 整数,从缓存区中读取/写入时的初始位置,以字节为单位
 * length, 整数,从缓存区中读取/写入数据的字节数
 * position, 整数,写入/读取文件初始位置;
 * callback(err, written, buffer), 写入操作执行完成后回调函数,written实际写入字节数,buffer被读取的缓存区对象
 */
fs.write(fd, buffer, offset, length, position, callback);
fs.read(fd, buffer, offset, length, position, callback);

整体的使用结构为

open->read/write->close

open开始拿到fd,fd为一个整数,表示打开文件返回的文件描述符,window中又称文件句柄

后续操作以fd为文件标志进行操作

const fs = require('fs');
const path = __dirname+"/public/buffer.txt";// __dirname 当前文件所在目录的绝对路径
const buffer = new Buffer.from("你好");  //每一个汉字utf8编码是3个字节,英文是1个字节

fs.open(path, 'a+', (err, fd) => {
  fs.write(fd,buffer,0,6,0, (err) => {// 0,6,0的含义,0,6从buffer中读取6个字节,0是开始读取的位置,0是写入的位置,写入文件的起始位置  
    if(err){
      console.log(err);
    }else{
      console.log("写入成功");
    }
  })

  fs.read(fd,buffer,0,6,0, (err, bytes) => {// 0,6,0的含义,0,6从buffer中写入6个字节,0是开始写入的位置,0是读取的位置,读取文件的起始位置
    if(err){
      console.log(err);
    }else{
      if(bytes > 0){
        console.log(buffer.slice(0, bytes).toString());//打印buffer中的内容

        fs.read(fd,buffer,0,6,null, (err, bytes) => {// 再次读取fd中的内容时,不标记出读取位置,默认为上次读取结束的位置,'a+'表示每次将位置放置在文件末尾
          if(err){
            console.log(err);
          }else{
            if(bytes > 0){
              console.log(buffer.slice(0, bytes).toString());
            }
          }
        })
      }

      fs.close(fd, (err) => {//结束本次文件读写
        if(err){
          console.log(err);
        }else{
          console.log("关闭文件成功");
        }
      })
    }
  })

});

这种方式的逻辑更加精细,可以控制数据流缓存区的位置进行读写,

值得注意的是,read和write两个方法中的3个整数参数,前两个是指定给buffer数据流缓冲区的 ,最后一个是文件的位置,当你进行read读取时,是对文件进行读取,在将读取的内容写入buffer

当你进行write写入时,是对buffer进行读取,在将读取的内容写入文件 ,两者正好相反但是参数格式一致

完整代码总结和目录结构展示

file.js

// 两种模块导入方式
// import * as fs from 'fs';// Es6:这种方式需要在package.json中配置"type": "module"
const fs = require('fs');// commonJs
const path = require('path');

const txt = '../public/file.txt'
const txtMsg = [
  path.dirname(txt),// 父级文件夹
  path.basename(txt),// 文件名,包括后缀
  path.extname(txt) // 文件后缀(扩展名)
]

let f = 0 ;

txtMsg.forEach(item => {
  console.log(item);
})

// 同一代码块的回调执行顺序是 fs.open -> fs.close ->fs.stat -> fs.writeFile -> fs.readFile 打开文件,关闭文件,查看文件,写入文件,读取文件
// 打开文件,'w+/a+' 获得读,写权限,文件流起始位置在开头/末尾(a相比于a+没有读取权限), 如果文件不存在则创建,读取文件后会覆盖原有文件
fs.open(txt, 'a', (err, fd) => {
  if(err){
    console.log(err.message);
  }
  f = fd;
  console.log(fd); 
})

// 读取文件, 读取文件内容,并返回一个字符串
fs.readFile(txt, 'utf8', (err, data) => {
  if(err){
    console.log(err.message);
  }
  console.log(data);
}) 

// 写入文件, 写入文件内容,
fs.writeFile(txt, 'hello world', (err) => {
  if(err){
    console.log(err.message);
  }
  console.log('写入成功');
})

// 追加文件内容
fs.appendFile(txt, 'hello world', (err) => {
  if(err){
    console.log(err.message);
  }
  console.log('追加成功');
})

// 关闭文件, 关闭文件后才能进行其他操作
fs.close(f, (err) => {
  if(err){
    console.log(err.message);
  }
  console.log('文件关闭成功');
})

// 文件信息
fs.stat(txt, (err, stats) => {
  if(err){
    console.log(err.message);
  }
  console.log(stats.isFile());
})

// 每次执行此文件,会先打开txt.txt文件,(此时内容已清空)关闭文件,写入内容,再读取文件内容

setFile.js

// 封装一个setFile函数,该函数接收一个文件名和一个文件内容作为参数,并将文件内容写入指定的文件中(没有则创建),路径是当前目录下新建一个public文件夹,并将文件至于public下面。
// setFile(baseName,content,b)

const fs = require('fs');
const path = "./public/";

/**
 * @param {文件名称} baseName 
 * @param {写入的内容} content 
 * @param {内容是否覆盖} b 默认为false,不覆盖
 */

module.exports.setFile = function (baseName, content, b = false) {
  // 如果没有public文件夹则创建
  try {
    if (!fs.existsSync(path)) {
      fs.mkdirSync(path);
      console.log("文件夹 public 创建成功");
    }
  } catch (err) {
    console.log(err);
  }

  // 判断文件是否存在,在open之前判断,回调结果在open之后
  fs.stat(path + baseName, (err) => {
    if (err) {// 文件不存在,产生错误
      // console.log(err);
      console.log(`文件 ${baseName} 创建成功`);
    }
  })

  if (!b) {
    // 不覆盖内容

    // fs.readFile(path + baseName, "utf-8",(err, data) => {
    //   if (err) {
    //     console.error(err);
    //   }
    //   // 读取出原来的内容拼接
    //   content = data + content;

    //   fs.writeFile(path + baseName, content, (err) => {
    //     if (err) {
    //       console.error(err);
    //     }
    //     console.log("写入成功");
    //   })
    // })

    fs.appendFile(path + baseName, content, (err) => {
      if (err) {
        console.error(err);
      } else {
        console.log("写入成功");
      }
    })

  } else {
    fs.writeFile(path + baseName, content, (err) => {
      if (err) {
        console.error(err);
      } else {
        console.log("写入成功");
      }
    })
  }
}

useSetFile.js

// 导出的模块是整个文件,需要通过属性引入使用里面的方法
const setFile = require('./setFile');

const file = 'file.txt';
const content = 'Hello, World!';

setFile.setFile(file, content);

buffer.js

const fs = require('fs');
const path = __dirname+"/public/buffer.txt";// __dirname 当前文件所在目录的绝对路径
const buffer = new Buffer.from("你好");  //每一个汉字utf8编码是3个字节,英文是1个字节

fs.open(path, 'a+', (err, fd) => {
  fs.write(fd,buffer,0,6,0, (err) => {// 0,6,0的含义,0,6从buffer中读取6个字节,0是开始读取的位置,0是写入的位置,写入文件的起始位置  
    if(err){
      console.log(err);
    }else{
      console.log("写入成功");
    }
  })

  fs.read(fd,buffer,0,6,0, (err, bytes) => {// 0,6,0的含义,0,6从buffer中写入6个字节,0是开始写入的位置,0是读取的位置,读取文件的起始位置
    if(err){
      console.log(err);
    }else{
      if(bytes > 0){
        console.log(buffer.slice(0, bytes).toString());//打印buffer中的内容

        fs.read(fd,buffer,0,6,null, (err, bytes) => {// 再次读取fd中的内容时,不标记出读取位置,默认为上次读取结束的位置,'a+'表示每次将位置放置在文件末尾
          if(err){
            console.log(err);
          }else{
            if(bytes > 0){
              console.log(buffer.slice(0, bytes).toString());
            }
          }
        })
      }

      fs.close(fd, (err) => {//结束本次文件读写
        if(err){
          console.log(err);
        }else{
          console.log("关闭文件成功");
        }
      })
    }
  })

});

目录结构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/687078.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

肥胖与代谢综合征,膳食纤维干预的相关进展

谷禾健康 肥胖和代谢综合征在全球范围内日益流行,是21世纪人类健康面临的重大威胁之一。据世界卫生组织(WHO)全球数据估计,目前全球约13%(即近65亿)成年人口受肥胖症影响。 肥胖和代谢综合征对健康的危害包括增加患心血管疾病、糖尿病和高血压的风险&…

短视频矩阵系统----可视化剪辑独立开发(采用php)

短视频矩阵系统源头技术开发: 打磨短视频矩阵系统的开发规则核心框架可以按照以下几个步骤进行: 明确系统需求:首先明确系统的功能需求,包括短视频的上传、编辑、发布、播放等环节。确定系统的目标用户和主要的使用场景&#xff…

智能数据分析(1)Lecture 6-8b

Lecture 6: Generative Models 生成模型 vs 判别模型 判别模型(Discriminative Models) 判别模型的主要任务是直接学习输入 x x x 和类别 y y y 之间的关系。它们不关心数据的生成过程,而是直接估计类别的边界。 定义:判别模…

Win10系统无法安装msi文件问题

winR输入services.msc打开服务 找到Windows Installer并启动 输入msiexec /package “msi文件路径”

perccli查看磁盘和Raid卡

1、安装 source /etc/profile chmod 755 /usr/sbin/perccli2、磁盘 perccli /c0 show all3、raid卡 cc perccli /c0 show cc 4、raid卡 pr perccli /c0 show patrolread

安卓手机忘记锁屏密码怎么办?2个方法拯救你的解锁困境!

为了保护手机信息不被他人轻易获取,我们通常会设置锁屏密码。然而,记忆力有时也会捉弄人,即使是最常用的密码,也有可能因为一时的疏忽或遗忘而导致我们无法解锁自己的手机。安卓手机忘记锁屏密码怎么办?不必慌张&#…

镜头效果技术在AI绘画中的革新作用

随着人工智能技术的飞速发展,AI绘画已经成为艺术与科技交汇的前沿领域。在这一领域中,镜头效果技术的应用不仅为艺术家和设计师们提供了全新的创作工具,更在艺术创作中扮演了革命性的角色。本文将深入探讨镜头效果技术在AI绘画中的应用&#…

物联网开发tcp协议之——netty拆包问题

1.前言 tcp协议是物联网开发中比较常见的一种通信协议,而netty则是一tcp通信协议中一个比较优秀的框架。tcp协议是一种长连接的协议,是流式传输的,开发过程中最长遇见的问题就是拆包粘包问题。我目前对接过的物联网系列有智能家居设备&#…

一脉阳光上市圆梦:销售成本高昂,两大创始人的行贿往事与屡屡被罚

《港湾商业观察》施子夫 2024年6月7日,江西一脉阳光集团股份有限公司(以下简称,一脉阳光)将正式在港交所主板挂牌上市(以下简称,一脉阳光;股票代码02522.HK),公司预计发…

【网络安全的神秘世界】Kali安装中文输入法

🌝博客主页:泥菩萨 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 今天就手把手教你如何在kali中安装和配置输入法 首先,打开终端,输入下面这行代码: # sudo apt install ibus ibus-pi…

24年北京网安大会是AI驱动安全?还是驱动安全股票全员下跌?

AI驱动安全,网安一哥疯狂转发 吉祥学安全知识星球🔗除了包含技术干货:Java代码审计、web安全、应急响应等,还包含了安全中常见的售前护网案例、售前方案、ppt等,同时也有面向学生的网络安全面试、护网面试等。 2024年6…

问题:明朝统辖西域的主要措施有( )(2.0分) (多选题) #学习方法#微信#经验分享

问题:明朝统辖西域的主要措施有( )(2.0分) (多选题) A.设立哈密卫 B.册封各地的首领 C.都护统领 D.布局要地 参考答案如图所示

网站建设方案书

网站建设方案书是一个详细的计划,用于指导如何创建一个成功的网站。在这份方案书中,将包括网站的目标,目标受众,用户体验设计,内容策略,技术架构,营销推广等方面的详细计划。以下是一份示例网站…

从零开始学JAVA

一、编写Hello world程序 public class JavaMain1 {//主程序执行入口,main方法public static void main(String[] args){System.out.println("Hello world!");} } 运行结果 Hello world! java编写主程序常见错误: 1、System ---首字母没有…

Vue3入门 - vue3相比于vue2的优点,及如何创建Vue3项目

目录 一、认识Vue3 1. Vue2 选项式 API vs Vue3 组合式API 2. Vue3的优势 二、使用create-vue搭建Vue3项目 1. 认识create-vue 2. 使用create-vue创建项目 3.熟悉项目和关键文件 一、认识Vue3 1. Vue2 选项式 API vs Vue3 组合式API <script>export default …

香蕉派BPI-F3 进迭时空(SpacemiT)K1RISC-V开发板软件下载链接

香蕉派BPI-F3是一款工业级 8核RISC-V开源硬件开发板&#xff0c;它采用进迭时空&#xff08;SpacemiT&#xff09; K1 8核RISC-V芯片设计&#xff0c;CPU集成2.0 TOPs AI计算能力。4G DDR和16G eMMC。2个GbE以太网接口&#xff0c;4个USB 3.0和PCIe M.2接口&#xff0c;支持HDM…

ESP32开发:2、使用Clion+IDF框架新建ESP32工程

文章目录 背景步骤新建工程编译工程下载代码 参考 背景 使用CLIONIDF框架新建ESP32工程。编译工程&#xff0c;并配置下载。首先需要根据教程1、安装好IDF框架&#xff0c;参考如下&#xff1a; IDF环境搭建 步骤 新建工程 首先找到IDF框架安装路径&#xff0c;我这里的如下…

JeeSite 快速开发平台 Vue3 前端版介绍

JeeSite 快速开发平台 Vue3 前端版介绍&#xff1a; 它构建于 Vue3、Vite、Ant-Design-Vue、TypeScript 以及 Vue Vben Admin 等最前沿的技术栈之上&#xff0c;能助力初学者迅速上手并顺利融入团队开发进程。涵盖的模块包括组织机构、角色用户、菜单授权、数据权限、系统参数…

webpack 优化构建速度的插件

1.HardSourceWebpackPlugin本地缓存 HardSourceWebpackPlugin这个插件比DLL动态链接库更优秀 HardSourceWebpackPlugin是webpack的插件&#xff0c;为模块提供中间缓存步骤。为了查看结果&#xff0c;您需要使用此插件运行webpack两次&#xff1a;第一次构建将花费正常的时间…

AI技术变革与企业服务创新

1、AI的技术变革 1&#xff09;AI市场规模 2&#xff09;AI大模型发展历程 3&#xff09;AIGC发展背景 4&#xff09;AIGC技术能力 AIGC的技术架构逻辑上分为基础层、技术层、能力层、应用层、终端层五大板块&#xff0c;其中核心技术层涵盖AI技术群和大模型的融合创新&#…