深入浅出Nodejs中的大文件读写

news2024/11/16 13:29:42

笔者最近在做一些node端的文件读写和分片上传工作,在这个过程中,发现node读取的文件如果超过2G,超过了读取Blob最大值,会出现读取异常,此外在node中读写文件也受服务器RAM的限制等,需要分片读取,本人记录一下遇到的问题以及解决问题的经过。
  • node中的文件读写
  • node文件读写RAM和Blob大小的限制
  • 其他

一、node中的文件读写

1.1 常规文件读写

常规的,如果我们要读取一个比较小的文件,可以直接通过:
const fs = require('fs')
let data = fs.readFileSync("./test.png")
console.log(data,123)
//输出data = <Buffer 89 50 4e ...> 
一般而言,同步的方法不是很推荐,因为js/nodejs是单线程的,同步的方法会阻塞主线程。最新版的node直接提供了fs.promise,可以结合async/await直接使用:
const fs = require('fs')
const readFileSync = async () => {let data = await fs.promises.readFile("./test.png")console.log(data,123)
}
readFileSync()
//输出data = <Buffer 89 50 4e ...> 

这里通过异步的方法调用不会阻塞主线程,多个文件读取的IO也可以并行进行等。

1.2 Stream文件读写

常规的文件读写,我们会把文件一次性的读取到内存中,这种方法时间效率和内存效率都很低,时间效率低是指必须要一次性读取完毕后才能执行后续才做,内存效率低是指必须把这个文件都一次性读取放入内存中,很占用内存。因此这种情况下,我们一般使用Stream来进行文件的读取:
const fs = require('fs')
const readFileTest = () => {var data = ''var rs = fs.createReadStream('./test.png');rs.on('data', function(chunk) {data += chunk;console.log(chunk) });rs.on('end',function(){console.log(data);});rs.on('error', function(err){console.log(err.stack); });
}
readFileTest()
// data = <Buffer 89 50 64 ...> 

通过Steam来进行文件读写,可以提高内存效率和时间效率。

  • 内存效率:在处理数据之前,不需要在内存中加载大量(或整个)数据
  • 时间效率:一旦有了数据,就可以开始处理,这大大减少开始处理数据的时间,而不必等到整个数据加载完毕再进行处理。

Stream的文件还支持第二种写法:

const fs = require('fs')
const readFileTest = () => {var data = ''var chunk;var rs = fs.createReadStream('./test.png');rs.on('readable', function() {while ((chunk=rs.read()) != null) {data += chunk;}});rs.on('end', function() {console.log(data)});
};
readFileTest() 

二、node文件读写RAM和Blob大小的限制

2.1 基础问题

在读取大文件时,会有读取文件大小的限制,比如我们现在在读取一个2.5G的视频文件:
const fs = require('fs')
const readFileTest = async () => {let data = await fs.promises.readFile("./video.mp4")console.log(data)
}
readFileTest() 

执行上述的代码会报错:

RangeError [ERR_FS_FILE_TOO_LARGE]: File size (2246121911) is greater than 2 GB

我们可能会想到,通过设置option,NODE\_OPTIONS='--max-old-space-size=5000',此时5000M>2.5G,但是报错还是没有消失,也就是说通过Options无法改变node读取文件的大小限制。

上述是常规的方式读取大文件,如果通过Steam的方式读取还会有文件大小的限制嘛? 比如:
const fs = require('fs')
const readFileTest = () => {var data = ''var rs = fs.createReadStream('./video.mp4');rs.on('data', function(chunk) {data += chunk; });rs.on('end',function(){console.log(data);});rs.on('error', function(err){console.log(err.stack); });
}
readFileTest() 

如上方式读取一个2.5G的文件不会有异常,不过要注意的是这边有一个报错:

data += chunk;^

RangeError: Invalid string length 

此时是因为data的长度超过了最大限制,比如2048M等。因此在用Steam处理的时候,在对读取结果的保存时,要注意文件的大小,千万不能超过默认的Buffer的最大值。上述这种情况,我们不用data += chunk将数据全部保存在一个大的data中,我们可以边读取边处理。

2.2 分片读取

createReadStream在读取文件的过程中,其实也可以分段读取,这种分段读取的方法也可以做为大文件读取的备选项。特别是在并发读取的时候有一定的优点,可以提升文件读取和处理的速度。

createReadStream接受第二个参数{start,end}。我们可以通过fs.promises.stat来获取文件的大小,然后确定分片,最后分片一次读取,比如:

1.获取文件大小

const info = await fs.promises.stat(filepath) const size = info.size 

2.按照指定的SIZE分片(比如128M一个分片)

 const SIZE = 128 * 1024 * 1024let sizeLen = Math.floor(size/SIZE)let total = sizeLen +1 ;for(let i=0;i<=sizeLen;i++){if(sizeLen ===i){console.log(i*SIZE,size,total,123)readStremfunc(i*SIZE,size,total)}else{console.log(i*SIZE,(i+1)*SIZE,total,456)readStremfunc(i*SIZE,(i+1)*SIZE-1,total)}}//分片后【0,128M】,【128M, 256M】... 

3.实现读取函数

const readStremfunc = () => {const readStream =fs.createReadStream(filepath,{start:start,end:end})readStream.setEncoding('binary')let data = ''readStream.on('data', chunk => {data = data + chunk})readStream.end('data', () => {...})
} 
值得注意的是fs.createReadStream(filepath,{start,end}),start和end是前闭后闭的,比如fs.createReadSteam(filepath,{start:0,end:1023})读取的是\[0,1023\]一共1024个bit。

三、其他

3.1 扩展浏览器端的大文件读写

前面将了大文件在nodejs中的读取,那么在浏览器端会读取大文件会有什么问题吗?

浏览器在本地读取大文件时,之前有类似FileSaver、[StreamSaver](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fjimmywarting%2FStreamSaver.js "https://github.com/jimmywarting/StreamSaver.js")等方案,不过在浏览器本身添加了File的规范,使得浏览器本身就默认和优化了Stream的读取。我们不需要做额外的工作,相关的工作:[github.com/whatwg/fs。](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fwhatwg%2Ffs%25E3%2580%2582 "https://github.com/whatwg/fs%E3%80%82") 不过不同的版本会有兼容性的问题,我们还是可以通过FileSaver等进行兼容。

3.2 请求静态资源大文件

如果是在浏览器中获取静态资源大文件,一般情况下只需要通过range分配请求即可,一般的CDN加速域名,不管是阿里云还是腾讯云,对于分片请求都支持的很好,我们可以将资源通过cdn加速,然后在浏览器端直接请求cdn加速有的资源。

分片获取cdn静态资源大文件的步骤为,首先通过head请求获取文件大小:
const getHeaderInfo = async (url: string) => {const res: any = await axios.head(url + `?${Math.random()}`);return res?.headers;
};
const header = getHeaderInfo(source_url)
const size = header['content-length'] 

我们可以从header中的content-length属性中,获取文件的大小。然后进行分片和分段,最后发起range请求:

const getRangeInfo = async (url: string, start: number, end: number) => {const data = await axios({method: 'get',url,headers: {range: `bytes=${start}-${end}`,},responseType: 'blob',});return data?.data;}; 

在headers中指定 range: bytes=${start}-${end},就可以发起分片请求去获取分段资源,这里的start和end也是前闭后闭的。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

2022年认证杯SPSSPRO杯数学建模A题(第二阶段)人员的紧急疏散求解全过程文档及程序

2022年认证杯SPSSPRO杯数学建模 A题 人员的紧急疏散求解 原题再现&#xff1a; 在过去的几十年里&#xff0c;由于大规模集会活动的数量和规模的增加&#xff0c;紧急疏散的问题变得越来越重要。通过有限宽度的门或狭窄通道进行疏散是最值得关注的情况之一。为了更好地理解各…

.Net Maui 开发之路(1): APP基本设置(图标、应用名称)

.Net Maui APP基本设置(图标、应用名称) 前言一、App显示名称设置二、App显示图标设置三、App加载动画设置四、App透明状态栏设置总结前言 最终实现的显示效果如下图 提示:以下是本篇文章正文内容,下面案例可供参考 一、App显示名称设置 1、在项目上右键,选择编辑项目文…

02 DevOps 之 Jenkins

1. 什么是CICD 推荐阅读&#xff1a;CICD原理及流程 CICD面试题 在要介绍jenkins之前&#xff0c;我们需要了解CICD是什么&#xff1f; Continuous Integration (CI) 持续集成 Continuous Delivery (CD) 持续交付 Continuous Deployment (CD) 持续部署 1.1 持续集成 持续集成…

Echarts折线图隐藏markPoint只显示最大值和最小值的文本,且只在该两点显示symbol

算是一个比较偏门的需求吧&#xff0c;具体UED给的设计图效果如下&#xff1a; 看起来非常简单&#xff0c;但实际实现起来……也确实简单&#xff0c;就是步骤多一点~ 我们知道Echarts提供的markPoint标注最大值和最小值是会有一个水滴图案的&#xff1a; 首先要做的就是隐藏这…

进程状态和优先级【Linux】

1.进程状态的分类 在Linux内核中&#xff0c;进程状态分为七大类&#xff0c;不同的状态有不同的含义。 下面的状态在kernel中定义&#xff1a; /* * The task state array is a strange "bitmap" of * reasons to sleep. Thus "running" is zero, and *…

深度学习笔记--Transformer中position encoding的源码理解与实现

1--源码 import torch import math import numpy as np import torch.nn as nnclass Pos_Embed(nn.Module):def __init__(self, channels, num_frames, num_joints):super().__init__()# 根据帧序和节点序生成位置向量pos_list [] for tk in range(num_frames):for st in ran…

感知机的认识和简单的实现

一、感知机perceptron 1.1 感知机的信号 只有0和1两种取值 1.2 神经元会计算传递过来的信号总和 只有当信号总和超过某个界限的时候&#xff0c;神经元才会被激活 1.3 信号权重 不同的权重对应的信号的重要性越高 二、常见的逻辑电路 与门与非门或门 2.1 思考 使用感…

@Scope与@RefreshScope注解

在SpringIOC中&#xff0c;我们熟知的BeanScope有单例&#xff08;singleton&#xff09;、原型&#xff08;prototype&#xff09;&#xff0c; Bean的Scope影响了Bean的管理方式&#xff0c;例如创建Scopesingleton的Bean时&#xff0c;IOC会保存实例在一个Map中&#xff0c;…

nest.js创建以及error相关问题

开始之前&#xff0c;你可以使用 Nest CLI 创建项目&#xff0c;也可以克隆一个 starter project&#xff08;两者的结果是一样的&#xff09;。 若要使用 Nest CLI 构建项目&#xff0c;请运行以下命令。这将创建一个新的项目目录&#xff0c;并使用核心的 Nest 文件和支撑模…

我把 CPU 三级缓存的秘密,藏在这 8 张图里

本文已收录到 GitHub AndroidFamily&#xff0c;有 Android 进阶知识体系&#xff0c;欢迎 Star。技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 进 Android 面试交流群。 前言 大家好&#xff0c;我是小彭。 在上一篇文章里&#xff0c;我们聊到了计算机存储器系统的金…

盘点机PDA搭配蓝牙便携打印机,条码标签打印,超市仓库条码管理,条码标签纸

null使用盘点机PDA&#xff0c;搭配蓝牙便携打印机&#xff0c;移动打印条码标签的操作和设置。对于商品本身没有条码的商品&#xff0c;比如&#xff1a;外购回来无条码的商品&#xff0c;工厂自己生产出来的成品&#xff0c;那么这种就需要打印商品条码进行粘贴&#xff0c;即…

Spring Security认证之登录表单配置

本文内容来自王松老师的《深入浅出Spring Security》&#xff0c;自己在学习的时候为了加深理解顺手抄录的&#xff0c;有时候还会写一些自己的想法。 自定义登录页面 文接上篇&#xff0c;这一篇学习如何自定义登录表单。我们创建一个Spring Boot项目之后&#xff0c;还是一样…

windows docker 及 k8s 环境搭建

docker 环境搭建 下载 docker 下载 docker for desktop&#xff0c; , 配置 镜像源 开通 kubenates 功能 注册一个 docker hub 账号 记住账号密码&#xff0c; 将来拉取镜像要用到&#xff0c; 在 docker for desktop 中登录该账号 kubenates 环境搭建 docker 中开通 k8…

nginx服务器

一、介绍 Nginx (engine x) 是一个高性能的HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点&#xff08;俄文&#xff1a;Рамблер&#xff09;开发的&#xff0c;第一个公开版本0.1.0发布于2…

用户管理系统(2)

2.实现添加功能:有两个和后端交互的接口 根据用户的身份显示登陆界面: 进行插入操作: 1)在我们的前端直接获取到用户名&#xff0c;密码&#xff0c;确认密码&#xff0c;年龄&#xff0c;QQ&#xff0c;邮箱&#xff0c;判断他们是否为空&#xff0c;检测密码和确认密码是否一…

docker 第二次学习笔记

一、dockers简介 docker官网&#xff1a;https://www.docker.com 1.1 docker定义 docker是一种容器化技术&#xff0c;用来更好的构建和发布应用。 二、docker安装 2.1 方法1 centos7.x系统的安装 官网安装步骤&#xff1a;https://docs.docker.com/engine/install/cento…

IDEA中,maven项目下,lombok插件 ,添加lombok.jar, Maven项目下lombok依赖配置

IDEA中&#xff0c;maven项目下&#xff0c;lombok插件 &#xff0c;添加lombok.jar, Maven项目下lombok依赖配置 Maven 项目的创建 在IDEA 21版中&#xff0c;Maven项目无需下载其他版本&#xff0c;查看有无Maven&#xff0c;如果没有下载 安装 首先打开IDEA &#xff0c;点…

​ 详解Linux内核通信-proc文件系统

使用 /proc 文件系统来访问 Linux 内核的内容&#xff0c;这个虚拟文件系统 在内核空间和用户空间之间打开了一个通信窗口&#xff1a; /proc 文件系统是一个虚拟文件系统&#xff0c;通过它可以使用一种新的方法在 Linux内核空间和用户间之间进行通信。在 /proc 文件系统中&…

MySQL事务和索引

✏️作者&#xff1a;银河罐头 &#x1f4cb;系列专栏&#xff1a;MySQL &#x1f332;“种一棵树最好的时间是十年前&#xff0c;其次是现在” 目录索引概念使用索引在MySQL中的数据结构事务概念mysql的隔离级别索引 概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所…

一图看懂,阿里云飞天企业版如何支持政企数智创新

杭州&#xff0c;2022年11月5日 – 今日&#xff0c;在云栖大会专有云技术和应用实践论坛&#xff0c;阿里云重磅发布飞天企业版在建云、管云、用云方面的全面升级&#xff0c;并邀请行业专家、政企客户代表和合作伙伴面向未来十年共话新一代政企IT发展趋势&#xff0c;分享阿里…