前端培训-中级阶段(47)- Node.js 10.x文件模块

简介: 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。

使用 Node.js 很大一部分的使用场景是,写个小脚本批量处理一下重复无聊的任务。比如说:


  1. 获取所有 json 内容,然后过滤出想要的数据。


  1. 把所有图片压缩一下,然后放入压缩包中。


  1. 把字体文件提取压缩一下。


  1. 把所有文件重命名一下。


这些任务中我们都需要访问文件系统,之前在浏览器环境中其实是没有文件系统概念的,今天我们来学一哈。


Node.js 文件模块



我们可以使用 fs 来操作文件系统。

const fs = require('fs');


回调方式


所有的文件系统操作都具有同步的(10.x 有,历史也有)、回调的(10.x 有,历史也有)、以及基于 promise(12.x 开始就有了,历史没有) 的形式。


同步


同步的形式会阻止 Node.js 事件循环和进一步的 JavaScript 执行,直到操作完成。

异常会被立即地抛出,可以使用 try…catch 处理,也可以冒泡。


const fs = require('fs');
try {
  fs.unlinkSync('文件');
  console.log('已成功地删除文件');
} catch (err) {
  // 处理错误
}


异步


异步的形式总是把完成回调作为其最后一个参数。


传给完成回调的参数取决于具体方法,但第一个参数总是预留给异常。 如果操作被成功地完成,则第一个参数会为 nullundefined


const fs = require('fs');
fs.unlink('文件', (err) => {
  if (err) throw err;
  console.log('已成功地删除文件');
});


promise


基于 Promise 的操作会返回 Promise(当异步操作完成时会被解决)。


const fs = require('fs/promises');
(async function(path) {
  try {
    await fs.unlink(path);
    console.log(`已成功地删除文件 ${path}`);
  } catch (error) {
    console.error('出错:', error.message);
  }
})('文件');


文件路径


支持 字符串(常用Path库就对了)、Buffer(为了兼容)、URL(需要 new URL('file:///C:/') 为入参。可以用相对路径 (process.cwd() 可以查看当前路径),绝对路径。


字符串形式


在 Windows 上,Node.js 遵循独立驱动器工作目录的概念。 当使用没有反斜杠的驱动器路径时,可以观察到此行为。 例如, fs.readdirSync('C:\\') 可能会返回与 fs.readdirSync('C:') 不同的结果。 详见此 MSDN 页面


bVcHhwE.webp.jpg


一般我们使用 Path 库:

  1. 可以直接看一下最终地址
  2. 可以正确使用当前系统的路径分隔符,Unix系统是"/",Windows系统是""。


bVcHhw5.webp.jpg


URL 形式


bVcHhyU.webp.jpg


// 在 Windows 上:
// - 带有主机名的 WHATWG 文件的 URL 会转换为 UNC 路径。
// file://主机名/文件 => 主机名文件
fs.readFileSync(new URL('file://主机名/文件'));
// - 带有驱动器号的 WHATWG 文件的 URL 会转换为绝对路径。
// file:///C:/文件 => C:文件
fs.readFileSync(new URL('file:///C:/文件'));


API


目录 dir 类


fs.readdirSync() 同步获取目录


fs.readdir() 异步获取目录


当调用 fs.readdir()fs.readdirSync()withFileTypes 选项设置为 true)时,则生成的数组会使用 fs.Dirent 对象(而不是字符串或 Buffer)填充。

fs.mkdir(path[, options], callback) 异步地创建目录。


回调会传入可能的异常、以及创建的第一个目录的路径(如果 recursivetrue), (err, [path])。可选的 options 参数可以是整数(指定 mode(权限和粘滞位))、或对象(具有 mode 属性和 recursive 属性(指示是否要创建父目录))。


path 是已存在的目录时,调用 fs.mkdir() 仅在 recursive 为 false 时才会导致错误。


fs.mkdirSync(path[, options]) 同步地创建目录。 返回 undefined,或创建的第一个目录的路径(如果 recursivetrue)。 这是 fs.mkdir() 的同步版本。


监听 fs.FSWatcher 类


fs.watch() 每当指定监视的文件被修改时,会触发 'change' 事件。


// 使用 fs.watch()监听器的示例。
fs.watch('./tmp', { 
        encoding: 'buffer'
    }, (eventType, filename) => {
  if (filename) {
    console.log(filename);
  }
});


读取流 fs.ReadStream 类


使用 fs.createReadStream() 函数创建并返回的 fs.ReadStream 实例。


fs.createReadStream(path[, options])




写入流 fs.WriteStream 类


使用 fs.createWriteStream() 函数创建并返回的 fs.WriteStream 实例。

fs.createWriteStream(path[, options])





文件信息 fs.Stats 类


fs.Stats 对象提供了关于文件的信息。在遍历的时候我们会判断文件类型,如果是文件就打开,如果是目录就递归


fs.stat()fs.lstat()fs.fstat()、以及它们的同步方法返回的对象都是此类型。 如果传给这些方法的 options 中的 bigint 为 true,则数值会是 bigint 型而不是 number 型,并且该对象还会包含额外的纳秒级精度的属性(以 Ns 为后缀)。


  1. stats.isDirectory() 如果 fs.Stats 对象描述文件系统目录,则返回 true


  1. stats.isFile() 如果 fs.Stats 对象描述普通的文件,则返回 true


  1. stats.size 文件的大小(以字节为单位)。


  1. stats.mtime 表明上次修改此文件的时间戳。
    stats.mtimeMs 表明上次修改此文件的时间戳,以 POSIX 纪元以来的毫秒数表示。


  1. stats.birthtime 表示此文件的创建时间的时间戳。
    stats.birthtimeMs 表明此文件的创建时间的时间戳,以 POSIX 纪元以来的毫秒数表示。


文件属性的时间值#


中英对照


atimeMsmtimeMsctimeMsbirthtimeMs 属性是保存相应时间(以毫秒为单位)的数值。 它们的精度取决于平台。 当将 bigint: true 传给生成该对象的方法时,属性将会是 bigint 型,否则它们将会是数字型


atimeNsmtimeNsctimeNsbirthtimeNs 属性是保存相应时间(以纳秒为单位)的 bigint。 仅当将 bigint: true 传给生成该对象的方法时,它们才会出现。 它们的精度取决于平台。


atimemtimectimebirthtime 是对应时间的 Date 对象。 Date 值和数值没有关联性。 赋值新的数值、或者改变 Date 的值,都将不会影响到对应的属性。


stat 对象中的时间具有以下语义:

  • atime "访问时间" - 上次访问文件数据的时间。由 mknod(2)utimes(2)read(2) 系统调用更改。




  • birthtime "创建时间" - 创建文件的时间。当创建文件时设置一次。 在不支持创建时间的文件系统上,该字段可能改为保存 ctime1970-01-01T00:00Z(即 Unix 纪元时间戳 0)。 在这种情况下,该值可能大于 atimemtime。 在 Darwin 和其他的 FreeBSD 衍生系统上,也可能使用 utimes(2) 系统调用将 atime 显式地设置为比 birthtime 更早的值。


在 Node.js 0.12 之前,在 Windows 系统上 ctime 保存 birthtime。 从 0.12 开始, ctime 不再是“创建时间”,而在 Unix 系统上则从来都不是。

获取权限访问 fs.access、fs.accessSync


除了判断权限,还可以判断是否存在。不过我们一般可以直接 fs.open() 直接去处理 err 。通常,仅在不直接使用文件时(例如当其可访问性是来自其他进程的信号时),才检查文件的可访问性。


在 Windows 上,目录上的访问控制策略(ACL)可能会限制对文件或目录的访问。 但是, fs.access() 函数不检查 ACL,因此即使 ACL 限制用户读取或写入,也可能报告路径是可访问的。


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



  • mode<integer> 默认值: fs.constants.F_OK



测试用户对 path 指定的文件或目录的权限。 mode 参数是一个可选的整数,指定要执行的可访问性检查。 查看文件可访问性的常量了解 mode 的可选值。 可以创建由两个或更多个值按位或组成的掩码(例如 fs.constants.W_OK | fs.constants.R_OK)。


文件


  1. fs.open(path[, flags[, mode]], callback) 异步地打开文件。
    fs.openSync(path[, flags, mode]) 同步打开文件


  1. fs.read(fd, buffer, offset, length, position, callback)fd 指定的文件中读取数据,写入到 buffer 中。

fs.readSync(fd, buffer, offset, length, position) 同步版本,从指定 fs 中读取数据


fs.readFile(path[, options], callback) 异步地读取文件的全部内容。
fs.readFileSync(path[, options]) 同步版本,读取文件全部内容


  1. fs.appendFile(path, data[, options], callback) 异步地追加数据到文件,如果文件尚不存在则创建文件。 data 可以是字符串或 Buffer

fs.appendFileSync(path, data[, options]) 同步地将数据追加到文件,如果文件尚不存在则创建该文件。 data 可以是字符串或 Buffer


// 直接针对文件追加
fs.appendFileSync('文件.txt', '追加的数据', 'utf8');
// 先打开文件,然后针对文件描述符追加
fd = fs.openSync('文件.txt', 'a');
fs.appendFileSync(fd, '追加的数据', 'utf8');


  1. fs.copyFile(src, dest[, mode], callback) 异步地将 src 拷贝到 dest。 默认情况下,如果 dest 已经存在,则覆盖它。 除了可能的异常,回调函数没有其他参数。 Node.js 不保证拷贝操作的原子性。 如果在打开目标文件用于写入后发生错误,则 Node.js 将尝试删除目标文件。

fs.copyFileSync(src, dest[, mode]) 同步


  1. fs.rename(oldPath, newPath, callback) 异步地把 oldPath 文件重命名为 newPath 提供的路径名。 如果 newPath 已存在,则覆盖它。 除了可能的异常,完成回调没有其他参数。

fs.renameSync(oldPath, newPath) 同步版本,文件重命名


  1. fs.write(fd, buffer[, offset[, length[, position]]], callback) 写入 bufferfd 指定的文件。不等待回调就对同一个文件多次使用 fs.write() 是不安全的。 对于这种情况,建议使用 fs.createWriteStream()


示例



获取目录下所有图片,并上传到服务器


const FormData = require('form-data');
const fetch = require('node-fetch');
var fs = require('fs');
var path = require('path');
var dirPath = 'cdn-transform'
var filePath = path.resolve(`./node-upload-img/${dirPath}`);
//文件遍历方法
function fileDisplay(filePath){
    fs.readdir(filePath,function(err,files){
        if(err){
            console.warn(err)
        }else{
            files.forEach(function(filename){
                var filedir = path.join(filePath, filename);
                var buffer = fs.readFileSync(filedir)
                var formData = new FormData();
                var fileName = `${filename}`
                var url =  `www.lilnong.top/upload/fe-up/${dirPath}/${fileName}`;
                formData.append('file', buffer, `${fileName}`);
                fetch('http://www.lilnong.top/upload',{
                    headers: formData.getHeaders(),
                    method: 'post',
                    body: formData
                })
                .then(v=>v.text())
                .then(v=>{
                    console.log('http://www.lilnong.top/upload', url, v)
                })
            })
        }
    });
}
fileDisplay(filePath)


递归遍历所有json


const readDir = (entry, paths = []) => {
    const dirInfo = fs.readdirSync(entry);
    dirInfo.forEach(item=>{
        const location = path.join(entry,item);
        const info = fs.statSync(location);
        if(info.isDirectory()){
            console.log(`dir:${location}`);
            readDir(location, [item]);
        }else{
            if(/.json$/.test(location)){
                readFile(location, paths)
            }
        }
    })
}
console.log('__dirname', __dirname)
readDir(__dirname);
function readFile(path, pathKey){
    return console.log(path, pathKey);
})


相关文章
|
20天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
17天前
|
JavaScript 前端开发 Java
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
springboot解决js前端跨域问题,javascript跨域问题解决
|
19天前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
29 5
|
17天前
|
缓存 前端开发 JavaScript
JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式
本文深入解析了JavaScript前端路由的实现原理及其在单页应用中的重要性,涵盖前端路由概念、基本原理、常见实现方式(Hash路由和History路由)、优点及挑战,并通过实际案例分析,帮助开发者更好地理解和应用这一关键技术,提升用户体验。
47 1
|
21天前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
31 4
|
1月前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
1月前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
31 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
1月前
|
JavaScript 前端开发 开发者
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第27天】在前端开发领域,Vue.js和Angular是两个备受瞩目的框架。本文对比了两者的优劣,Vue.js以轻量级和易上手著称,适合快速开发小型到中型项目;Angular则由Google支持,功能全面,适合大型企业级应用。选择时需考虑项目需求、团队熟悉度和长期维护等因素。
41 1
|
1月前
|
JavaScript 前端开发 API
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第26天】前端技术的飞速发展让开发者在构建用户界面时有了更多选择。本文对比了Vue.js和Angular两大框架,介绍了它们的特点和优劣,并给出了在实际项目中如何选择的建议。Vue.js轻量级、易上手,适合小型项目;Angular结构化、功能强大,适合大型项目。
31 1
|
1月前
|
前端开发 JavaScript UED
"前端小技巧大揭秘:JS如何将后台时间戳秒变亲切小时前、分钟前,让用户秒懂,提升互动体验!"
【10月更文挑战第23天】在Web开发中,将后台返回的时间戳转换为“小时前”、“分钟前”、“刚刚”等友好的时间描述是常见需求。本文介绍如何用JavaScript实现这一功能,通过计算当前时间和时间戳的差值,返回相应的描述,提升用户体验。
31 1