构建属于你的七牛云文件上传工具:Qiniu Uploader 详解(从 0 到 1 实现)
GitHub 仓库地址:https://github.com/hahala2333/qiniu-upload
📚 简介
在现代 Web 开发中,静态资源的上传和管理是不可避免的需求。为了简化将本地资源上传到七牛云存储的过程,我们构建了 Qiniu Uploader 工具。它具备灵活的配置方式、现代化的构建工具支持(Vite)、兼容多种模块格式以及使用 TypeScript 提供强大的类型支持。本文将手把手带你从 0 开始搭建一个完整的七牛云上传工具,涵盖项目初始化、核心功能实现、打包以及发布到私有仓库的完整流程。
🎯 设计思路与项目规划
在开始编写代码之前,我们需要明确工具的功能和设计思路:
- 支持通过配置文件或直接传入参数配置七牛云账号信息。
- 使用 Vite 构建项目,支持输出 ESM 和 CommonJS 两种模块格式。
- 使用 TypeScript 提供类型支持,提高代码的可读性和可维护性。
🛠 第一步:初始化项目
1️⃣ 创建项目目录
首先,在本地创建一个新的项目目录,并进入该目录:
mkdir qiniu-uploader
cd qiniu-uploader
2️⃣ 初始化 package.json
在项目根目录下运行以下命令,初始化 package.json
文件:
npm init -y
此时,项目目录下会生成一个 package.json
文件。
3️⃣ 安装必要的依赖
接下来,我们需要安装项目所需的依赖:
npm install qiniu vite
npm install -D typescript @types/node tsx
qiniu
:七牛云官方 SDK。vite
:现代化的构建工具。typescript
:TypeScript 编译器。@types/node
:Node.js 的类型定义。tsx
:用于运行 TypeScript 文件的工具。
✏️ 第二步:编写配置文件生成脚本
为了简化用户的配置操作,我们提供一个 CLI 工具来生成默认的配置文件。
1️⃣ 创建 cli
目录和脚本文件
在项目根目录下创建 cli
目录,并在其中创建 init-config.js
文件:
mkdir cli
cd cli
nano init-config.js
2️⃣ 编写配置文件生成脚本
在 cli/init-config.js
中,编写以下代码:
#!/usr/bin/env nodeconst fs = require("fs");const configContent = {accessKey: "your-access-key",secretKey: "your-secret-key",bucket: "your-bucket",zone: "Zone_z1",basePath: "static/assets",distPath: "./dist",
};fs.writeFileSync("qiniu-config.json",JSON.stringify(configContent, null, 2),"utf8"
);
console.log("qiniu-config.json 文件已生成!");
3️⃣ 修改 package.json
将该脚本添加到 package.json
的 bin
字段中,使其可以通过命令行直接运行:
"bin": {"qiniu-config": "cli/init-config.js"
}
4️⃣ 生成配置文件
运行以下命令,生成默认的配置文件:
npx qiniu-config
此时,项目根目录下会生成一个 qiniu-config.json
文件。
💻 第三步:编写核心上传逻辑
接下来,我们开始编写核心的上传逻辑,这部分将是整个工具包的核心功能。
1️⃣ 创建 src/index.ts
在 src
目录下创建 index.ts
文件,用于编写核心的上传逻辑。
mkdir src
cd src
nano index.ts
2️⃣ 编写核心逻辑
在 src/index.ts
中编写核心逻辑的主要功能模块:
✅ 加载配置文件并检查是否缺失的必填字段
- 在构造函数中,首先尝试加载
qiniu-config.json
文件,如果文件存在,则读取配置。 - 如果都存在,则合并配置传入参数会覆盖配置文件中的同名参数
- 检查是否缺失的必填字段
✅ 验证存储空间是否存在
通过七牛云的 SDK 验证存储空间(Bucket)是否存在。
✅ 获取上传 Token
生成上传所需的 Token。
✅ 递归获取本地文件路径
递归获取本地文件夹中所有的文件路径,准备上传。
✅ 上传文件到七牛云
使用七牛云的 SDK 将文件上传至指定的存储空间。
详细代码
import qiniu from "qiniu";
import fs from "fs";
import path from "path";const ZoneMap = {Zone_z0: qiniu.zone.Zone_z0, // 华东Zone_z1: qiniu.zone.Zone_z1, // 华北Zone_z2: qiniu.zone.Zone_z2, // 华南Zone_na0: qiniu.zone.Zone_na0, // 北美Zone_as0: qiniu.zone.Zone_as0, // 东南亚
};export interface UploadOptions {accessKey?: string; // 七牛云 Access KeysecretKey?: string; // 七牛云 Secret Keybucket?: string; // 存储空间名称zone?: keyof typeof ZoneMap; // 存储区域basePath?: string; // 在七牛云存储中添加的路径前缀distPath?: string; // 本地静态资源路径
}export class QiniuUploader {private mac: qiniu.auth.digest.Mac;private config: qiniu.conf.Config;private options: UploadOptions;// 初始化上传类的配置constructor(options?: UploadOptions) {const configFilePath = path.join(process.cwd(), "qiniu-config.json");const fileOptions = QiniuUploader.loadConfigFile(configFilePath);// 合并配置文件和传入参数,优先使用传入参数this.options = { ...fileOptions, ...options };// 3. 验证必填字段const missingFields = this.getMissingRequiredFields();if (missingFields.length > 0) {throw new Error(`Missing required fields: ${missingFields.join(", ")}`);}this.mac = new qiniu.auth.digest.Mac(this.options.accessKey,this.options.secretKey);this.config = new qiniu.conf.Config();this.config.zone = this.options.zone? ZoneMap[this.options.zone]: qiniu.zone.Zone_z1; // 默认华东}// 检查缺失的必填字段private getMissingRequiredFields(): string[] {const requiredFields = ["accessKey", "secretKey", "bucket", "distPath"];const missingFields: string[] = [];for (const field of requiredFields) {if (!this.options[field as keyof UploadOptions]) {missingFields.push(field);}}return missingFields;}// 静态方法:加载配置文件private static loadConfigFile(configFilePath: string): Partial<UploadOptions> {if (!fs.existsSync(configFilePath)) {return {};}try {const fileContent = fs.readFileSync(configFilePath, "utf-8").trim();// 如果文件内容为空,则返回一个空对象if (!fileContent) {return {};}const config = JSON.parse(fileContent);return config;} catch (error: any) {throw new Error(`Failed to load configuration file: ${error.message}`);}}// 验证存储空间是否存在private async verifyBucket(): Promise<boolean> {const bucketManager = new qiniu.rs.BucketManager(this.mac, this.config);return new Promise((resolve, reject) => {// 调用 getBucketInfo 方法bucketManager.getBucketInfo(this.options.bucket,(err, respBody, respInfo) => {if (err) {return reject(err); // 网络或 SDK 错误}if (respInfo.statusCode === 200) {resolve(true); // Bucket 存在} else if (respInfo.statusCode === 631) {resolve(false); // Bucket 不存在} else {reject(new Error(`Unexpected status code: ${respInfo.statusCode}`));}});});}// 获取上传 Tokenprivate getUploadToken(): string {const options = {scope: this.options.bucket,expires: 3600,};const putPolicy = new qiniu.rs.PutPolicy(options);return putPolicy.uploadToken(this.mac);}// 上传方法public async upload(): Promise<void> {// 验证存储空间是否存在const bucketExists = await this.verifyBucket();if (!bucketExists) {throw new Error(`Bucket "${this.options.bucket}" does not exist.`);}// 获取上传 Tokenconst uploadToken = this.getUploadToken();// 创建上传器const formUploader = new qiniu.form_up.FormUploader(this.config);// 设置上传时的额外参数 默认不设置任何参数const putExtra = new qiniu.form_up.PutExtra();// 获取所有待上传的文件路径const files = this.getFiles(this.options.distPath);// 逐个上传文件for (const file of files) {// 计算目标路径(key)const key = this.options.basePath? path.join(this.options.basePath,path.relative(this.options.distPath, file)): path.relative(this.options.distPath, file);await new Promise((resolve, reject) => {formUploader.putFile(uploadToken,key,file,putExtra,(err, body, info) => {if (err) return reject(err);if (info.statusCode === 200) {console.log(`Uploaded: ${key}`);resolve(body);} else {reject(body);}});});}}// 通过递归方法获取所有需要上传的文件路径。private getFiles(dir: string): string[] {const files: string[] = [];const entries = fs.readdirSync(dir, { withFileTypes: true });for (const entry of entries) {const fullPath = path.join(dir, entry.name);if (entry.isDirectory()) {files.push(...this.getFiles(fullPath));} else {files.push(fullPath);}}return files;}
}
✅ 验证核心功能
编写一个测试文件来验证上传功能是否正常工作:
1️⃣ 创建 test.ts
在项目根目录下创建 test.ts
文件:
import { QiniuUploader } from "./src/index";(async () => {try {const uploader = new QiniuUploader();await uploader.upload();console.log("Upload completed successfully!");} catch (error) {console.error("Upload failed:", error);}
})();
2️⃣ 配置 package.json
的导出字段
"scripts": {"dev": "tsx test.ts"},
运行以下命令进行测试:
npm run dev
🛠 第四步:如何配置 Vite 打包工具
1️⃣ 配置 vite.config.ts
文件
为了支持 ESM 和 CommonJS 两种格式,我们可以通过 Vite 的 build.lib
配置来实现。具体配置如下:
vite.config.ts
import { defineConfig } from "vite";
import path from "path";export default defineConfig({build: {lib: {entry: path.resolve(__dirname, "src/index.ts"), // 工具库的入口文件name: "QiniuUploader", // 打包后的全局变量名称fileName: (format) => `index.${format === "es" ? "mjs" : "cjs.js"}`, // 输出的文件名formats: ["es", "cjs"], // 同时输出 ESM 和 CommonJS 两种格式},rollupOptions: {external: ["qiniu", "fs", "path"], // 指定外部依赖,不打包进最终文件output: {globals: {qiniu: "qiniu", // 配置全局变量},},},},
});
解释:
entry
:工具库的入口文件,通常是src/index.ts
。name
:为全局变量命名,适用于在浏览器中直接引入。fileName
:根据模块格式不同,分别输出index.mjs
(ESM 格式)和index.cjs.js
(CommonJS 格式)。formats
:指定打包的模块格式,可以是["es", "cjs"]
。
2️⃣ 配置 TypeScript 类型文件的输出
为了让用户在使用工具库时获得 TypeScript 类型提示,我们需要配置 TypeScript 编译器 输出类型声明文件。
配置 tsconfig.json
文件
{"compilerOptions": {"target": "ESNext","module": "ESNext","declaration": true, // 启用类型声明文件的生成"emitDeclarationOnly": true, // 只生成类型声明文件"outDir": "dist", // 指定输出目录"moduleResolution": "node","allowSyntheticDefaultImports": true,"esModuleInterop": true,"resolveJsonModule": true},"include": ["src/**/*.ts"] // 指定要编译的文件
}
解释:
declaration
:启用类型声明文件的生成(.d.ts
)。emitDeclarationOnly
:仅输出类型声明文件,不生成 JavaScript 文件。outDir
:指定输出目录为dist
,将类型声明文件输出到打包目录中。include
:指定编译的文件路径。
3️⃣ 添加打包脚本
在 package.json
文件中,添加以下脚本用于执行打包命令:
修改 package.json
"scripts": {"build": "vite build && tsc"
}
解释:
vite build
:使用 Vite 构建工具库。tsc
:运行 TypeScript 编译器,仅输出类型声明文件。
4️⃣ 配置 package.json
的导出字段
为了让用户能够根据项目的模块类型自动选择 ESM 或 CommonJS 格式,我们需要在 package.json
文件中配置 exports
字段:
修改 package.json
{"main": "dist/index.cjs.js", // CommonJS 入口文件"module": "dist/index.mjs", // ESM 入口文件"types": "dist/index.d.ts", // 类型声明文件入口"exports": {".": {"import": "./dist/index.mjs", // ESM 格式的导出路径"require": "./dist/index.cjs.js" // CommonJS 格式的导出路径}}
}
解释:
main
:指定 CommonJS 格式的入口文件。module
:指定 ESM 格式的入口文件。types
:指定类型声明文件的入口文件。exports
:根据模块类型动态导出对应的文件路径。
5️⃣ 执行打包命令
配置完成后,运行以下命令生成打包文件和类型声明文件:
npm run build
打包完成后,dist
目录下将生成以下文件:
dist/
├── index.cjs.js # CommonJS 格式的文件
├── index.mjs # ESM 格式的文件
└── index.d.ts # 类型声明文件
完整的 package.json
{"name": "qiniu-upload","version": "1.0.0","description": "A library for uploading files to Qiniu Cloud","main": "dist/index.cjs.js","module": "dist/index.mjs","types": "dist/index.d.ts","license": "MIT","author": "haha","files": ["dist","README.md","cli/init-config.js"],"exports": {".": {"import": "./dist/index.mjs","require": "./dist/index.cjs.js"}},"scripts": {"build": "vite build && tsc","dev": "tsx test.ts"},"bin": {"qiniu-config": "cli/init-config.js"},"dependencies": {"qiniu": "^7.14.0"},"devDependencies": {"@types/node": "^22.10.5","tsx": "^4.19.2","vite": "^6.0.7"}
}
🚀 第五步:发布到私有仓库
1️⃣ 登录私有仓库
运行以下命令,登录你的私有仓库:
npm login --registry=https://your-private-registry.com/
2️⃣ 发布工具库
运行以下命令,将工具库发布到私有仓库:
npm publish
至此,你的七牛云文件上传工具库已经成功发布到私有仓库,可以在其他项目中通过 NPM 进行安装和使用。
✅ 如何使用
1️⃣ 在 ESM 项目中验证
创建一个新的 ESM 项目,并通过 import
语法引入工具库:
import { QiniuUploader } from 'qiniu-uploader';const uploader = new QiniuUploader();
await uploader.upload();
2️⃣ 在 CommonJS 项目中验证
创建一个新的 CommonJS 项目,并通过 require
语法引入工具库:
const { QiniuUploader } = require('qiniu-uploader');const uploader = new QiniuUploader();
uploader.upload().then(() => {console.log('Upload complete!');
}).catch(console.error);
3️⃣ 在 TypeScript 项目中使用
import { QiniuUploader, UploadOptions } from "qiniu-upload";const options: UploadOptions = {accessKey: "your-access-key",secretKey: "your-secret-key",bucket: "your-bucket",distPath: "./dist",
};const uploader = new QiniuUploader(options);await uploader.upload();
相关文章:
构建属于你的七牛云文件上传工具:Qiniu Uploader 详解(从 0 到 1 实现)
GitHub 仓库地址:https://github.com/hahala2333/qiniu-upload 📚 简介 在现代 Web 开发中,静态资源的上传和管理是不可避免的需求。为了简化将本地资源上传到七牛云存储的过程,我们构建了 Qiniu Uploader 工具。它具备灵活的配置…...
Spring Boot 项目中集成 Kafka-03
在 Spring Boot 项目中集成 Kafka 有多种方式,适应不同的应用场景和需求。以下将详细介绍几种常用的集成方法,包括: 使用 Spring Kafka (KafkaTemplate 和 KafkaListener)使用 Spring Cloud Stream 与 Kafka Binder使用 Spring for Apache K…...
如何在2025年创建一个网站:使用US Domain Center和WordPress的终极指南
在本指南中,我们将向你展示如何正确地使用US Domain Center和WordPress创建一个网站。无论你是要启动一个个人博客,还是一个在线商店,我们都会提供简单易懂的步骤指导。无需技术技能 — — 只需按照我们的简单步骤操作,你就能在今…...
LLM 训练中存储哪些矩阵:权重矩阵,梯度矩阵,优化器状态
LLM 训练中存储哪些矩阵 目录 LLM 训练中存储哪些矩阵深度学习中梯度和优化器是什么在 LLM 训练中通常会存储以下矩阵: 权重矩阵:这是模型的核心组成部分。例如在基于 Transformer 架构的 LLM 中,每一层的多头注意力机制和前馈神经网络都会有相应的权重矩阵。以 BERT 模型为…...
【JVM】总结篇之对象内存布局 执行引擎
文章目录 对象内存布局对象的实例化对象的内存布局对象的方问定位 执行引擎 对象内存布局 对象的实例化 new对象流程?(龙湖地产) 对象创建方法,对象的内存分配。(360安全) 1.判断对象对应的类是否加载、链…...
机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型
机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型 目录 机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型1 过拟合和欠拟合1.1 过拟合1.2 欠拟合 2 正则化惩罚2.1 概念2.2 函数2.3 正则化种类 3 K折交叉验证3.1 概念3.2 图片理解3.3 函数导入3.4 参数理解 4 训练模型K折交…...
【图像处理】OpenCv + Python 实现 Photoshop 中的色彩平衡功能
前言 这是使用 python 和 OpenCv 实现的 Photoshop 中色彩平衡功能的代码,可以设置阴影,高光和中间调的色调参数来调整图片的色彩平衡。 参考文章二也有 python 版本的代码实现,虽然中间调的部分貌似没有实现,但是理论部分讲解还…...
基于vue框架的的校园快递管理系统x0xm0(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
系统程序文件列表 项目功能:学生,校园跑腿,快递代取,代取进度,评价信息 开题报告内容 基于Vue框架的校园快递管理系统开题报告 一、研究背景与意义 随着电子商务的蓬勃发展,校园快递业务急剧增长,成为校园生活中不可或缺的一部分。然而&a…...
【Vim Masterclass 笔记05】第 4 章:Vim 的帮助系统与同步练习(L14+L15+L16)
文章目录 Section 4:The Vim Help System(Vim 帮助系统)S04L14 Getting Help1 打开帮助系统2 退出帮助系统3 查看具体命令的帮助文档4 查看帮助文档中的主题5 帮助文档间的上翻、下翻6 关于 linewise7 查看光标所在术语名词的帮助文档8 关于退…...
智能体(Agent)如何具备自我决策能力的机理与实现方法
一、智能体自我决策能力的机理 从人工智能和控制理论的角度看,智能体能够“自我决策”的核心在于其 “感知–认知–行动” 的循环过程,以及在此过程中引入自主学习与自主优化的机制。经过优化与补充,智能体具备自我决策能力的机理可以分解为…...
Redis 数据库源码分析
Redis 数据库源码分析 我们都知道Redis是一个 <key,value> 的键值数据库,其实也就是一个 Map。如果让我来实现这样一个 Map,我肯定是用数组,当一个 key 来的时候,首先进行 hash 运算,接着对数据的 length 取余&…...
vue3 css实现文字输出带光标显示,文字输出完毕,光标消失的效果
Vue实现过程如下: <template><div ><p ref"dom_element" class"typing" :class"{over_fill: record_input_over}"></p></div> </template> <script setup> import {onMounted, ref} from…...
【Leetcode】731. 我的日程安排表 II
文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接🔗 实现一个程序来存放你的日程安排。如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排。 当三个日程安排有一些时间上的交叉时(例如三个日程…...
浅谈棋牌游戏开发流程四:核心业务逻辑(二)——房间匹配与对局流程
一、前言:让玩家轻松坐上“牌桌” 在上一篇文章中,我们深入探讨了用户系统与登录流程,了解了如何让“陌生人”转变为游戏中的“正式玩家”。接下来,我们将迈向游戏的核心环节——房间匹配与对局流程。这是玩家实际参与游戏、互动…...
大学生HTML5期末作业 Web前端网页制作 html5+css3+js html+css网页设计 美食 美食模版2个页面
大学生HTML5期末作业 Web前端网页制作 html5css3js htmlcss网页设计 美食 美食模版2个页面 网页作品代码简单,可使用任意HTML辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修…...
Java100道面试题
1.JVM内存结构 1. 方法区(Method Area) 方法区是JVM内存结构的一部分,用于存放类的相关信息,包括: 类的结构(字段、方法、常量池等)。字段和方法的描述,如名称、类型、访问修饰符…...
MySQL 日志简介
总览 MySQL Server 有以下⼏种⽇志,可以记录服务器正在发⽣的活动。 ⽇志类型⽇志信息 ⼀般查询⽇志 (General query log) 已建⽴的客⼾端连接和从客⼾端接收到的语句 错误⽇志 (Error log) mysqld在启动、运⾏或停⽌时遇到的问题 慢查询⽇志 (Slow query log) 执⾏…...
ubuntu清理磁盘
ubuntu清理磁盘脚本: #!/bin/bash#shell脚本用#作注释行,但是第一行的#!/bin/bash例外sudo apt-get clean sudo rm -rf /tmp/* sudo rm -rf /var/cache/*cd /var/log/ sudo du -h -d 1 rm -rf ./*cd ~/.cache sudo du -h -d 1 rm -rf ./*apt…...
鸿蒙APP之从开发到发布的一点心得
引言: 做鸿蒙开发大概有1年左右时间了,从最开始的看官方文档、看B站视频,到后来成功发布两款个人APP(房贷计算极简版、时简时钟 轻喷,谢谢)。简单描述一下里边遇到的坑以及一些经历吧。 学习鸿蒙开发 个…...
C++二十三种设计模式之享元模式
C二十三种设计模式之享元模式 一、组成二、特点三、目的四、缺点五、示例代码 一、组成 抽象享元类:声明操作方法。 具体享元类:使用内部数据和外部数据来实现操作方法。 享元管理者类:创建和管理具体享元对象。 二、特点 1、创建享元对象…...
基于Python的音乐播放器 毕业设计-附源码73733
摘 要 本项目基于Python开发了一款简单而功能强大的音乐播放器。通过该音乐播放器,用户可以轻松管理自己的音乐库,播放喜爱的音乐,并享受音乐带来的愉悦体验。 首先,我们使用Python语言结合相关库开发了这款音乐播放器。利用Tkin…...
基于32单片机的智能语音家居
一、主要功能介绍 以STM32F103C8T6单片机为控制核心,设计一款智能远程家电控制系统,该系统能实现如下功能: 1、可通过语音命令控制照明灯、空调、加热器、窗户及窗帘的开关; 2、可通过手机显示和控制照明灯、空调、窗户及窗帘的开…...
【C语言程序设计——入门】C语言入门与基础语法(头歌实践教学平台习题)【合集】
目录😋 ⚙️C语言环境配置:Windows配置C语言环境(超级详细) <第1关:程序改错> 任务描述 相关知识 1. 头文件的引用 2. 基本语法规则 编程要求 测试说明 通关代码 测试结果 <第2关:scanf 函数>…...
基于Springboot的知名作家交流系统
博主介绍:java高级开发,从事互联网行业多年,熟悉各种主流语言,精通java、python、php、爬虫、web开发,已经做了多年的设计程序开发,开发过上千套设计程序,没有什么华丽的语言,只有实…...
服务器数据恢复—离线盘数超过热备盘数导致raidz阵列崩溃的数据恢复
服务器数据恢复环境&故障: 一台配有32块硬盘的服务器在运行过程中突然崩溃不可用。经过初步检测,基本上确定服务器硬件不存在物理故障。管理员重启服务器后问题依旧。需要恢复该服务器中的数据。 服务器数据恢复环境: 1、将服务器中硬盘…...
conda安装及demo:SadTalker实现图片+音频生成高质量视频
1.安装conda 下载各个版本地址:https://repo.anaconda.com/archive/ win10版本: Anaconda3-2023.03-1-Windows-x86_64 linux版本: Anaconda3-2023.03-1-Linux-x86_64 Windows安装 环境变量 conda -V2.配置conda镜像源 安装pip conda…...
内蒙古水系详细很全shp格式arcgis软件无偏移坐标下载后内容测评
标题中的“内蒙古水系详细很全shp格式arcgis软件无偏移坐标”指的是一个地理信息系统(GIS)数据集,该数据集详细记录了内蒙古地区的水系信息,并以ESRI公司的标准矢量数据格式——Shapefile(.shp)进行存储。S…...
RK3588平台开发系列讲解(系统篇)Linux Kconfig的语法
文章目录 一、什么是Kconfig二、config模块三、menuconfig四、menu 和 endmenu五、choice 和 endchoice六、source七、depends on八、default九、help十、逻辑表达式沉淀、分享、成长,让自己和他人都能有所收获!😄 一、什么是Kconfig Kconfig的语法及代码结构非常简单。本博…...
c#使用SevenZipSharp实现压缩文件和目录
封装了一个类,方便使用SevenZipSharp,支持加入进度显示事件。 双重加密压缩工具范例: using SevenZip; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.…...
【C++数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】
目录😋 任务描述 相关知识 1. 二叉排序树的基本概念 2. 二叉排序树节点结构体定义 3. 创建二叉排序树 4. 判断是否为二叉排序树 5. 递归查找关键字为 6 的结点并输出查找路径 6. 删除二叉排序树中的节点 测试说明 通关代码 测试结果 任务描述 本关任务&a…...
C# 服务生命周期:Singleton、Scoped、Transient
文章目录 1、概念:服务生命周期单例 (Singleton) :作用域 (Scoped) :瞬态 (Transient) : 2、对 Scoped 和 Transient 进一步辨析Scoped 生命周期Transient 生命周期选择哪种生命周期 1、概念:服务生命周期 单例 (Singleton) : 整个应用程序生命周期中只有一个实例被创建并共享…...
如何让用户在网页中填写PDF表格?
在网页中让用户直接填写PDF表格,可以大大简化填写、打印、扫描和提交表单的流程。通过使用复选框、按钮和列表等交互元素,PDF表格不仅让填写过程更高效,还能方便地在电脑或移动设备上访问和提交数据。 以下是在浏览器中显示可填写PDF表单的四…...
w140体育馆使用预约平台的设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
Linux(Ubuntu)下ESP-IDF下载与安装完整流程(4)
接前一篇文章:Linux(Ubuntu)下ESP-IDF下载与安装完整流程(3) 本文主要看参考官网说明,如下: 快速入门 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 Linux 和 macOS 平台工具链的标准设置 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 前边几回讲解了第一步 —— …...
PDF预览插件
PDF预览插件 可用于当前页面弹窗形式查看,可增加一些自定义功能 pdf预览插件 代码块: pdfobject.js <div class="pdfwrap"><div class="item"><h3>笑场</h3><div class="tags"><p>李诞</p><i&…...
【微服务】2、网关
Spring Cloud微服务网关技术介绍 单体项目拆分微服务后的问题 服务地址问题:单体项目端口固定(如黑马商城为8080),拆分微服务后端口各异(如购物车808、商品8081、支付8086等)且可能变化,前端难…...
计算机网络--路由表的更新
一、方法 【计算机网络习题-RIP路由表更新-哔哩哔哩】 二、举个例子 例1 例2...
网络安全抓包
#知识点: 1、抓包技术应用意义 //有些应用或者目标是看不到的,这时候就要进行抓包 2、抓包技术应用对象 //app,小程序 3、抓包技术应用协议 //http,socket 4、抓包技术应用支持 5、封包技术应用意义 总结点:学会不同对象采用…...
字玩FontPlayer开发笔记8 Tauri2文件系统
字玩FontPlayer开发笔记8 Tauri2文件系统 字玩FontPlayer是笔者开源的一款字体设计工具,使用Vue3 ElementUI开发,源代码: github: https://github.com/HiToysMaker/fontplayer gitee: https://gitee.com/toysmaker/fontplayer 笔记 字玩目…...
http源码分析
一、HttpURLConnection http连接池源码分析 二、HttpClient 连接池,每个路由最大连接数 三、OkHttp okhttp的连接池与socket连接...
【vim】vim常用操作总结
vim常用操作总结 一,简介二,操作介绍2.1 命令模式2.1.1 删除(剪切)光标所在行2.1.2 复制2.1.3 粘贴2.1.4 跳到行末2.1.5 跳到行首2.1.6 撤销操作 2.2 视图模式2.3 命令模式2.4 编辑模式 三,总结 一,简介 在…...
【学Rust开发CAD】1 环境搭建
文章目录 一、搭建C/C编译环境二、安装Rust三、配置 PATH 环境变量四、验证安装结果五、安装编辑工具 一、搭建C/C编译环境 Rust 的编译工具依赖 C 语言的编译工具,这意味着你的电脑上至少已经存在一个 C 语言的编译环境。如果你使用的是 Linux 系统,往…...
RK3588开发笔记-spi接口调试
目录 前言 一、SPI接口简介 二、原理图连接 三、设备树配置 四、spi调试 五、spi应用软件接口 总结 前言 在嵌入式系统开发中,SPI(Serial Peripheral Interface)接口作为一种同步、全双工、多设备、多主机的通信协议,广泛应用于连接各种外围设备,如ADC、DAC、数据存…...
AlphaPi相关硬件驱动提取
初涉硬件编程,在咸鱼上搞了几块AlphaPi和microbit的板鼓捣了一下,alphapi生态不完善,网上又无任何文档,搞封闭,可玩性实在有限,但貌似相关扩展板是可以插microbit的,于是想把这些扩展版用microb…...
【Unity3D】Text文本文字掉落效果
相关技术:Text、TextMesh、Rigidbody(刚体)、BoxCollider(碰撞体)、TextGenerator、文本网格、文字网格 原理:使用UGUI Text获取其文字的每个字符网格坐标,转世界坐标生成对应的3D文本(TextMesh…...
MySQL内置函数详解
MySQL内置函数详解 1. 字符串函数 1.1 基本字符串处理 -- 字符串长度 SELECT LENGTH(Hello MySQL); -- 返回11-- 字符串大小写转换 SELECT LOWER(HELLO), UPPER(hello); -- 返回 hello, HELLO-- 字符串截取 SELECT SUBSTRING(MySQL Database, 1, 5); -- 返回 MySQL SELEC…...
【网络安全设备系列】9、WAF(Web应用防火墙)
0x00 定义: Web应用防火墙是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一种设备。 WAF需要部署在Web服务器的前面,串行接入,不仅在硬件性能上要求高,而且不能影响Web服务,所以HA功能、Bypass功能都是必…...
Express 加 sqlite3 写一个简单博客
例图: 搭建 命令: 前提已装好node.js 开始创建项目结构 npm init -y package.json:{"name": "ex01","version": "1.0.0","main": "index.js","scripts": {"test": &q…...
【C++数据结构——图】图的邻接矩阵和邻接表的存储(头歌实践教学平台习题)【合集】
目录😋 任务描述 相关知识 1. 带权有向图 2. 图的邻接矩阵 3. 图的邻接表 测试说明 通关代码 测试结果 任务描述 本关任务:编写一个程序实现图的邻接矩阵和邻接表的存储。 相关知识 为了完成本关任务,你需要掌握: 带权有向图…...
基于单片机的直流稳压电源的设计(论文+源码)
1.系统方案设计 在本次直流稳压电源的设计中,其关键指标如下: 系统输入电压220V交流系统输出直流0到12V可调,步进可以达到0.1V电流最大输出可以到2A具有短路保护功能可以通过液晶或者数码管等显示设备显示当前输出电压 2. 电路图...