fs模块(一)

FS

FS 是file system的缩写,fs 模块可以实现与硬盘的交互,例如文件的创建、删除、重命名、移动,还有文件内容的写入、读取,以及文件夹的相关操作。在 Node.js 种,fs 模块提供了异步和同步两种方式操作文件。

基本使用

writeFile

函数定义
fs.writeFile(filename, data[, options], callback)

在编程中,[, options] 这种语法通常用来表示函数或方法的参数是可选的。这种语法在多种编程语言的文档中常见,特别是在描述函数签名时。

  • 方括号 [] 内的参数意味着这个参数不是调用函数时必须提供的,它有一个默认值或者在函数内部被忽略,如果调用者没有显式地提供它。
    data[, options] 这种写法时,data 是必需参数。
参数
  • filename:要写入数据的文件的路径,这是一个必需参数。
  • data:要写入文件的数据,可以是字符串、Buffer 或者是一个包含这些类型的数组,这也是一个必需参数。
  • options:这是一个可选参数,可以是一个对象,用于指定编码、文件模式等选项。如果省略,Node.js 会使用默认值。options 对象可以包含以下属性:
    • encoding:指定数据的字符编码。如果 data 是 Buffer,则此选项会被忽略。
    • mode:设置文件的权限。默认值是 0o666,并且这个值会受到进程的 umask 影响。
    • flag:指定文件操作的模式。默认是 'w',表示写入模式,如果文件存在则覆盖。
  • callback:这是一个可选的回调函数,当数据写入完成后被调用。回调函数没有参数,或者有一个可能表示写入过程中发生的错误的参数。
示例
异步写入

异步写入不会阻塞其他操作,执行完毕后通过回调函数通知结果。这是在 Node.js 中推荐的做法,因为它避免了阻塞事件循环,尤其是在处理大文件或网络 I/O 时更为重要。

const fs = require('fs');fs.writeFile('./fs.txt', 'Hello, Node.js!','utf8',err=>{if(err) {console.log('写入失败', err);return;}else {console.log('写入成功')}
})

在这个例子中,fs.writeFile()接收四个参数:文件路径、要写入的内容、文件编码(默认为'utf8',这里显式指定)以及一个回调函数,如果写入过程发生错误,回调函数的第一个参数会接收到错误信息;如果没有错误,则第二个参数会是null,表示写入成功。
展示一个示例模拟在没有写入权限的情况下尝试异步写入文件,并捕获及打印错误信息。假设我们尝试向一个需要管理员权限才能写入的位置写入文件,这通常会导致权限错误。

const fs = require('fs');// 假设一个需要较高权限才能写入的路径
const restrictedPath = '/user/restricted/path/example.txt';// 要写入的内容
const content = 'Hello, Node.js!';// 使用fs.writeFile()进行异步写入,并捕获可能的错误
fs.writeFile(restrictedPath, content, 'utf8', (err) => {if (err) {// 打印错误信息console.error('写入文件时遇到错误:', err);} else {console.log('文件写入成功');}
});

在这个示例中,如果运行此脚本的用户没有对/user/restricted/path/目录的写入权限,fs.writeFile()将会在回调函数中返回一个错误对象。错误对象通常会包含错误码和描述信息,可以帮助我们识别问题所在。错误输出可能类似于:

写入文件时遇到错误: { Error: EACCES: permission denied, open '/some/restricted/path/example.txt'errno: -13,code: 'EACCES',syscall: 'open',path: '/some/restricted/path/example.txt' }

这个错误信息表明了错误类型为EACCES,即权限被拒绝,同时还提供了其他详细信息如错误号(errno)、发生错误的系统调用(syscall)和相关的文件路径。

同步写入

虽然同步写入在某些特定场景下可能更直观,但请注意它会阻塞其他操作直到完成,这在Node.js中通常不鼓励使用,因为它会影响程序的整体性能和响应性。

const fs = require('fs');// 文件路径
const filePath = 'example.txt';// 要写入的内容
const content = 'Hello, Node.js!';// 使用fs.writeFileSync()方法进行同步写入
try {fs.writeFileSync(filePath, content, 'utf8');console.log('文件写入成功');
} catch (err) {console.error('写入文件时出错:', err);
}

这里,fs.writeFileSync()同样接收文件路径、内容和编码作为参数,但它会立即执行并阻塞后续代码,直到写入完成。如果发生错误,会抛出异常,因此需要使用try...catch语句来捕获并处理错误。

Q:如何理解同步异步?
A:现在用js定时器来简单理解一下同步和异步

// 实际上Node.js没有“同步定时器”的概念,但为了对比,我们构想一个理论上的场景
function synchronousTimer(ms) {// 假设的同步等待ms毫秒// 在这个等待期间,线程会被阻塞,无法执行其他任务// Node.js实际上没有这样的同步定时功能,这里在模拟同步const start = Date.now();while (Date.now() - start < ms) {}console.log("时间到了!");
}console.log("开始计时...");
synchronousTimer(2000); // 理论上如果这是同步的,会阻塞2秒
console.log("计时结束!"); // 这句话只有在“定时器”结束后才会打印

异步定时器, setTimeoutsetInterval

console.log("开始计时...");setTimeout(function() {console.log("时间到了!");
}, 2000); // 2秒后执行回调console.log("计时设置完成,但不等待,继续执行...");

在这个Node.js示例中,setTimeout函数安排了一个回调函数在2秒后执行,但是它立即返回,不会阻塞当前执行流程。因此,"计时设置完成,但不等待,继续执行…“这一行代码会立刻打印出来,然后过了2秒后,才会打印"时间到了!”。

  • 异步性: setTimeout的非阻塞性质体现了Node.js的异步处理方式,它允许程序在等待某个事件(这里是时间到达)时继续执行其他任务,而不是原地等待。
  • 事件循环: 这种机制依赖于Node.js的事件循环,它会在适当的时候(即设定的时间过去后)将回调函数加入到待处理队列,从而在不阻塞主线程的前提下执行。

appendFile

fs.appendFile是Node.js模块中的一个方法,用于在现有文件的末尾追加内容,如果文件不存在则会创建新文件。这个方法非常适合记录日志或累计数据的场景,因为它不会覆盖原有文件内容。

基本语法:
fs.appendFile(file, data[, options], callback)
参数说明:
  • flie:必填,一个字符串,表示要写入的文件路径。
  • data: 必填,要追加到文件的数据。如果是字符串,则会按照options.encoding(默认为utf8)进行编码。
  • options: 可选,一个对象,可以包含以下属性:
    • encoding: 指定写入数据的字符编码,默认utf8
    • mode:指定文件权限,默认为0o666且会受到umask的影响。
    • flag:指定文件打开方式,默认为a(追加模式)。
  • callback: 当使用回调风格时必填,一个函数,当操作完成时调用,传递可能的错误作为第一个参数。

A:解释一下mode

mode(文件模式):在Linux和类Unix系统中,文件模式(或文件权限)是一个用来控制谁可以读、写或执行文件的系统。文件权限通常用八进制数表示,每个数字代表不同的权限级别:
4:可读
2:可写
1:可执行
例如,0o666 表示:
第一个数字 6 代表文件所有者拥有读和写权限(4+2=6)
第二个数字 6 代表与文件所有者同组的用户拥有读和写权限
第三个数字 6 代表其他用户也拥有读和写权限

A :解释一下umask

umask(用户文件创建掩码):是一个系统设置,用于决定新创建的文件和目录的默认权限。它是通过从最大权限(通常是 0o777 即所有权限)中减去一个值来工作的。
例如,如果 umask 设置为 0022:
对于文件,最大权限 0o777 减去 umask 的 0022 得到 0o755。这意味着新创建的文件默认权限是所有者有全部权限(读、写、执行),而同组用户和其他用户只有读和执行权限。
对于目录,最大权限 0o777 减去 umask 的 0022 得到 0o755。这意味着新创建的目录默认权限是所有者有全部权限,而同组用户和其他用户只有读和执行权限,但不允许其他人在此目录下创建新文件或目录。

A:解释一下node.js下的mode

fs.appendFile 中的 mode
在Node.js的fs.appendFile函数中,mode参数允许你指定新创建文件的权限,如未指定mode,Node.js将使用默认的0o666。然而,实际的文件权限还会收到进程的umask影响,这意味着最终的文件权限将是0o666减去umask的值。
例如:
umask是0022,那么即使fs.appendFile使用的是默认的0o666模式,实际的文件权限将是0o644(0o666 - 0022),这意味着所有者可以读写权限,但其他用户只读文件。

示例代码:
回调风格
const fs = require('fs');fs.appendFile('example.txt', '这是追加的内容\n', (err) => {if (err) {console.error('追加文件时出错:', err);} else {console.log('内容已成功追加到文件!');}
});
Promise风格
const fs = require('fs').promises;async function appendContentToFile() {try {await fs.appendFile('example.txt', '这是通过Promise追加的内容\n');console.log('内容已成功追加到文件!');} catch (err) {console.error('追加文件时出错:', err);}
}appendContentToFile();
fs.writeFile风格追加内容
const fs = require('fs');fs.writeFile('example.txt', '这是追加内容\n', {flag: 'a'},(err)=> {if (err) {console.error('追加文件时出错:', err);} else {console.log('内容已成功追加到文件!');}
})

createWriteStream

fs.createWriteStream是Node.js中fs模块提供的一个函数,用于创建一个写入流(Writable Stream),可以向文件中写入数据。**程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数,**这个函数非常适合处理需要写入大量数据的任务,从而避免一次性将所有数据加载到内存中。
文件写入在计算机中是一个非常常见的操作,下面的场景都用到了文件写入。

  • 下载文件
  • 安装软件
  • 保存程序日志,如git
  • 编辑器保存文件
  • 视频录制

当需要持久化保存数据的时候,应该相当文件写入。在计算机编程中,“流式”(Stream)是一种数据处理方式,它允许程序以连续的方式读取或写入数据,而不需要一次性将所有数据加载到内存中。

函数定义

fs.createWriteStream(path[, options])

参数
  • path:要写入数据的文件的路径。可以是绝对路径或相对路径。
  • options:一个可选对象,包含以下属性:
    • flags:文件操作标志。默认值为 'w',表示写入模式。其他选项包括 'a'(追加模式)等。
    • encoding:指定写入数据的字符编码,默认为 'utf8'
    • fd:文件描述符,如果提供了这个值,createWriteStream 将使用这个描述符而不是打开一个新的文件。
    • mode:设置文件的权限,默认值是 0o666,并且这个值会受到进程的 umask 影响。
    • start:指定文件开始写入的位置。如果文件不存在,将从位置 0 开始写入;如果文件已存在,这个值表示从文件的哪个位置开始写入。
返回值

fs.createWriteStream 返回一个 stream.Writable 类的实例,这个实例是 Node.js 流接口的一部分,提供了写入数据的方法和事件。

流的方法
  • write(chunk[, endcoding][, callback]):向流中写入数据,chunk是要写入的数据快,encoding是数据的字符编码,callback是写入完成后的回调函数。
  • end([callback]):结束写入流,如果提供了回调函数,当流关闭时将会被调用。
流的事件
  • open:当写入流成功打开文件时触发。
  • close:当写入流关闭时触发。
  • error:如果在写入过程中发生错误,将触发此事件。
  • drain:当写入流的缓冲区被清空,可以继续写入数据时触发。
  • finish:当所有写入操作完成,并且没有更多的写入操作时触发。
示例
// createWriteStream
const fs = require("fs");const ws = fs.createWriteStream('./流式写入.txt');ws.write('从前从前\n');
ws.write('有个人爱你很久\n');ws.end()// 完整参数
const fs = require('fs');
const path = 'output.txt';// 创建一个写入流
const writeStream = fs.createWriteStream(path, {flags: 'a', // 追加模式encoding: 'utf8', // 使用 utf8 编码mode: 0o644, // 设置文件权限
});// 写入数据
writeStream.write('Hello, Node.js!', 'utf8', () => {console.log('数据已写入');
});// 结束写入
writeStream.end(() => {console.log('写入流已关闭');
});

Q:end是必须的吗?
A:不是,但建议写上。
在 Node.js 的流式接口中,end 方法用于结束可写流(Writable Stream)的写入操作。调用 end 方法是可选的,但通常推荐使用它,原因如下:

  • 结束信号:end 方法告诉流,没有更多的数据要写入了。这对于流知道何时关闭或完成其操作是很重要的。
  • 触发 finish 事件:调用 end 方法会触发 finish 事件,你可以监听这个事件来执行一些清理工作或后续操作。
const fs = require("fs");const ws = fs.createWriteStream('./流式写入.txt');// 监听 `finish` 事件
ws.on('finish', () => {console.log('所有数据已写入,写入操作完成。');});ws.write('从前从前\n');
ws.write('有个人爱你很久\n');ws.end();
  • 资源释放:对于某些类型的流,如文件写入流,调用 end 方法可以确保文件被正确关闭,释放系统资源。
  • 避免内存泄漏:如果你不调用 end,流可能会保持打开状态,这可能导致内存泄漏或其他问题。

然而,有一些情况下,你可能不需要显式调用·end

  • 自动结束:如果你使用的是 fs.createWriteStream 并且没有提供任何数据给流,流会自动结束。
  • 流已关闭:如果流已经因为其他原因(如发生错误)关闭,就不需要再次调用 end。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TIME_WAIT的危害

前言 该文章主要讨论下TIME_WAIT的存在意义和潜在危害&#xff0c;以及解决措施。 具体内容 首先看一下下面这幅图 这幅图来自《TCP IP详解卷1&#xff1a;协议 原书第2版中文》TCP状态变迁图。 TIME_WAIT存在意义 可靠的终止TCP连接。 保证让迟来的TCP报文有足够的时间被…

【YOLOv10改进[注意力]】添加注意力CascadedGroupAttention(2023) + 含全部代码和详细修改方式 + 手撕结构图 + 全网首发

本文将进行使用注意力CascadedGroupAttention的实践,助力YOLOv10目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法。 改进前和改进后的参数对比: 目录 一 CascadedGroupAttention 二 使用注意力CascadedGroupAttention 1 整体…

KVB投资安全小知识:你知道情绪面、技术面与基本面的关系吗?

摘要&#xff1a;当涉及到金融市场分析时&#xff0c;情绪面、技术面和基本面是三个重要的方面。它们相互交织&#xff0c;共同影响着市场的走势和投资者的决策。下面我来详细解释它们之间的关系。 情绪面的影响 情绪面指的是投资者情绪和市场情绪&#xff0c;它反映了市场参与…

springboot+vue+mybatis酒店管理系统+PPT+论文+讲解+售后

基于Spring框架的小型宾馆旅客信息管理系统采用B/S结构、java开发语言、以及Mysql数据库等技术。系统主要分为管理员和用户二部分&#xff0c;管理员&#xff1a;首页、个人中心、用户管理、客房类型管理、客房信息管理、客房预订管理、入住登记管理、退房评价管理、系统管理&a…

深度解析服务发布策略之滚动发布

目录 什么是滚动发布 滚动发布的优点 滚动发布的注意事项 滚动发布的实现步骤 小结 在软件开发和运维中&#xff0c;发布新版本是一个风险较高的操作。为了降低风险&#xff0c;提高发布的稳定性和可靠性&#xff0c;通常会采取一系列的技术策略&#xff0c;其中滚动发布&…

QSharedMemory使用详解

QSharedMemory 是 Qt 提供的一个类&#xff0c;用于在多个进程之间共享内存。它可以让您在不同的进程间传递数据&#xff0c;而无需通过文件或网络来进行传输。下面是 QSharedMemory 的详细用法和相关知识点。 一、基本概念 共享内存&#xff1a;共享内存是一块可以被多个进程…

UML的9中图例概述

1. 用例图 (Use Case Diagram) 用例图描述了系统与外部用户&#xff08;参与者&#xff09;之间的交互。它主要用于捕捉系统的功能需求。 - 主要元素&#xff1a;用例&#xff08;Use Case&#xff09;、参与者&#xff08;Actor&#xff09;、关联&#xff08;Association&…

Qt6之调色板QPaletee

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言Qt之调色板 QPalette什么是 QPalette&#xff1f;QPalette 的作用如何使用 QPaletteQPalette可设置的部分常规操作示例代码和运行效果图 总结 前言 在开发 Qt …

数据治理:数据提取过程中的合规性与安全性

数据治理&#xff1a;数据提取过程中的合规性与安全性 随着数字化时代的到来&#xff0c;数据已经成为企业运营和决策的核心驱动力。然而&#xff0c;在数据提取的过程中&#xff0c;确保数据的合规性和安全性成为了企业面临的重要挑战。数据治理作为一种系统的方法&#xff0…

【C语言】C语言入门宝典:核心概念全解析

. C语言专栏 | C专栏 &#x1f449; 个人主页 &#x1f448; 前言 此篇文章我们主要是宏观的了解一下什么是C语言&#xff0c;C语言里面有那些知识点&#xff0c;所有的知识点我们此篇只是以入门为主&#xff0c;点到为止&#xff0c;简单易懂&#xff0c;后期的文章会一 一详…

嵌入式交叉编译:frp

参考 LINUX FRP下载编译_linux编译frpc-CSDN博客 编译 make -f Makefile.cross-compiles 检查 $ make -f Makefile.cross-compiles Build darwin-amd64... Build darwin-amd64 done Build darwin-arm64... Build darwin-arm64 done Build freebsd-amd64... Build freebsd-…

谷神前端组件增强:原组件

wait // 等待 function wait (component, key, callback) {if (component?.inited) {callback()} else {selfPage[${key}_callback] selfPage[${key}_callback] ?? []selfPage[${key}_callback].push(callback)} }run // 执行 function run (component, key) {let arr […

ubuntu18.04 + openssl + engine + pkcs11+ softhsm2 双向认证测试

安装环境 openssl 1.1.1 pkcs11-tool &#xff08;由sudo apt-get install opensc 安装&#xff09; libpksc11 &#xff08;需源码安装apt install 只有libp11, 源码安装才有 libpksc11.so&#xff09; softhsm2 &#xff08;由sudo apt-get install softhsm2 libsofthsm2-de…

三种方案解决:ImportError: DLL load failed while importing _cext: 找不到指定的模块

一、 pip install msvc-runtime某篇帖子里的&#xff0c;用这个解决问题的人还挺多&#xff0c;但我试了没用 二、 安装最新版vc 三、 numpyMKL https://github.com/cgohlke/numpy-mkl-wheels/

Servlet实践操作

Servlet运行原理 Tomcat 的代码内置了 main 方法&#xff0c;当我们启动 Tomcat 的时候&#xff0c;就是从 Tomcat 的 main 方法开始执行的 被 WebServlet 注解修饰的类会在 Tomcat 启动的时候就被获取并集中管理 Tomcat 通过反射这样的语法机制来创建被 WebServlet 注解修饰…

PCB设计隐藏的陷进

1、BGA芯片的开窗和过油设计。 加工工艺中&#xff0c;范式过孔都需要盖油设计&#xff0c;实心焊盘需要开窗设计&#xff0c;坚决不能盖油。 2、通孔设计的互联连通性 比如H3芯片的wifi设计&#xff0c;实际上是没有联通的&#xff0c;虽然四层板的中间层有焊盘&#xff0c;但…

操作系统-进程调度

进程调度 文章目录 进程调度前言进程和作业区别CPU调度程序抢占调度调度程序上下文切换 调度准则调度算法 前言 对于单处理器系统&#xff0c;同一时间只能有一个进程可以运行&#xff0c;其他的进程都应该等待&#xff0c;知道CPU空闲可以调度为止。 多道程序的目标是&#…

lua的GC

关于lua的gc云风大佬在 Lua GC 的源码剖析 系列文章中讲得很清楚&#xff0c;这里做一下简单的记录。 分步gc lua使用的是一种三色标记清除算法&#xff08;tri-color incremental mark & sweep&#xff09;&#xff0c;大体步骤如下&#xff1a; 初始阶段&#xff0c;所…

【FreeRTOS】估算栈的大小

参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》 目录 估算栈的大小回顾简介计算说明估计函数用到的栈有多大合计 估算栈的大小 回顾 上一篇文章链接&#xff1a;http://t.csdnimg.cn/Cc8b4 传送门: 上一篇文章 上一篇文章创建的三个任务 /* 创建任务&#xff1a;声 *…

22.HandlerPipeline

ChannelHandler用来处理Channel上的各种事件,分为入站和出站两种。 所有的ChannelHandler被连成一串,就是Pipeline。 入站处理器通常是ChannelInboundHandlerAdapter的子类,主要用来读取客户端数据,写回结果。 出站处理器通常是ChannelOutboundHandlerAdapter的子类,主…