C#实现HTTP服务器:处理文件上传---解析MultipartFormDataContent
完整项目托管地址:https://github.com/sometiny/http
HTTP还有重要的一块:文件上传。
这篇文章将详细讲解下,前面实现了同一个链接处理多个请求,为了方便,我们独立写了一个HTTP基类,专门处理HTTP请求。
https://github.com/sometiny/http/blob/main/src/Http/HttpServerBase.cs
本类实现了简单的路由功能,路由功能后续可以使用正则或path2regexp去处理,以处理更复杂的路由请求。
增加了对静态文件的处理,没匹配到的路由都会进入OnResource逻辑。
增加了WebRoot和UploadTempDir的设置,WebRoot目录下的静态文件在HTTP请求时都会自动加载,不需要单独写路由。
UploadTempDir用来临时保存上传的文件。
1、上传简介
上传文件时,使用Content-Type: multipart/form-data; boundary=[BOUNDARY]标头来告诉服务器,请求实体为multipart/form-data编码。
服务器根据编码协议解析multipart/form-data的内容即可,其中[BOUNDARY]为一个请求实体“块”的结束或开始标识,用于解析实体内容。
在浏览器中,为form标签增加enctype="multipart/form-data"属性时,浏览器会自动生成对应的上传标头。
例如下面的标头,为Chrome浏览器生成的:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuHXBXxnxXp0aCz08
2、上传时到底传送了什么格式的数据
话不多说,直接上代码,直观点。
先从这里https://github.com/sometiny/http/tree/main/bin/Release把web目录及其内容放到你自己的Debug或Release编译结果目录下。
实现一个测试服务器
注意,继承的是HttpServerBase基类,在OnReceivedPost方法显示下浏览器发送的内容。
public class HttpServer : HttpServerBase
{public HttpServer() : base(){//设置Web根目录//方便输出静态文件WebRoot = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web"));UplaodTempDir = AppDomain.CurrentDomain.BaseDirectory + "uploads";//注册一些路由RegisterRoute("/", OnIndex);RegisterRoute("/post", OnReceivedPost);}/// <summary>/// 首页路由处理程序,跳转到index.html/// </summary>/// <param name="request"></param>/// <param name="stream"></param>private bool OnIndex(HttpRequest request, Stream stream){//跳转到页面HttpResponser responser = new ChunkedResponser(301);responser.ContentType = "text/html; charset=utf-8";responser["Location"] = "/index.html";responser.Write(stream, "Redirect To '/index.html'");responser.End(stream);return true;}/// <summary>/// 处理POST数据/// </summary>/// <param name="request"></param>/// <param name="stream"></param>/// <returns></returns>private bool OnReceivedPost(HttpRequest request, Stream stream){HttpResponser responser = new ChunkedResponser();responser.ContentType = "text/html; charset=utf-8";responser.Write(stream, "<style type=\"text/css\">body{font-size:12px;}</style>");responser.Write(stream, "<h4>上传表单演示</h4>");responser.Write(stream, $"<a href=\"/index.html\">返回</a><br />");responser.Write(stream, $"ContentType:{request.ContentType}<br />");responser.Write(stream, $"Boundary:{request.Boundary}<br />");///这里输出下浏览器发送来的请求responser.Write(stream, $"<pre>{Encoding.UTF8.GetString( request.RequestBody)}</pre>");responser.End(stream);return true;}
}
运行服务器,浏览器访问:http://127.0.0.1:4189/index.html
,展示如下一个表单。
我们什么都不上传,直接点提交,看看服务器收到些什么内容。
绿色部分就是我们收到的请求实体内容。
编码分析
实例中的[BOUNDARY]为:----WebKitFormBoundarydyAItGK9UU5xVhZq
3、首行:--[BOUNDARY]\r\n 在boundary前面补两个中横线(-)。
首行读取完毕后,即开始表单项的读取。
4、非文件表单项:
每行一个标头,直到空行,空行后表单内容开始。这里跟Http请求
Content-Disposition: form-data; name="name"测试hello world!
------WebKitFormBoundarydyAItGK9UU5xVhZq
说明:
Content-Disposition: form-data; name="[表单项名称]"\r\n\r\n[内容]\r\n--[BOUNDARY]
5、文件表单项
标头的读取和结束标志跟上面的一致。
只是Content-Disposition会多一个filename属性,因为我们没选择文件,filename值为空。
同时,会提供一个Content-Type标头来标识文件类型。
不排除序应用程序会提供更多的标头,我们只要读取到空行,关心我们需要的标头即可。
Content-Disposition: form-data; name="image"; filename=""
Content-Type: application/octet-stream------WebKitFormBoundarydyAItGK9UU5xVhZq
说明:
Content-Disposition: form-data; name="[表单项名称]"; filename=""\r\nContent-Type: application/octet-stream\r\n\r\n[文件内容]\r\n--[BOUNDARY]
6、如何确定结束标识之后是下一个表单项,还是请求实体的结尾。
读取到表单内容结束标识后,再往前读取两个字节。
如果两个字节为\r\n,代表后面还有其他的表单项。
如果两个字节为--,代表所有表单项已读取完毕,请求实体也读完了。
7、实现上传请求实体的解析。
解析使用了两个类。
将请求实体解析为Form和Files:https://github.com/sometiny/http/blob/main/src/Http/Utils/HttpMultipartFormDataParser.cs
Multipart数据读取的辅助流:https://github.com/sometiny/http/blob/main/src/Http/Streams/MultipartReadStream.cs
辅助流里面实现了核心的数据解析,内部用到了BoyerMoore字符串查找算法。
我们主要是讲解协议原理,协议解析这部分可以不用关心,我写的数据解析也可能不是很严格(我不会告诉你,我写完后就看不懂了)。
修改我们上面实现的服务器中OnReceivePost方法,我们这次把上传的表单和文件列出来。
private bool OnReceivedPost(HttpRequest request, Stream stream)
{HttpResponser responser = new ChunkedResponser();responser.ContentType = "text/html; charset=utf-8";responser.Write(stream, "<style type=\"text/css\">body{font-size:12px;}</style>");responser.Write(stream, "<h4>上传表单演示</h4>");responser.Write(stream, $"<a href=\"/index.html\">返回</a><br />");responser.Write(stream, $"ContentType:{request.ContentType}<br />");responser.Write(stream, $"Boundary:{request.Boundary}<br />");#region 输出解析后的上传内容responser.Write(stream, $"<h5>上传表单数据:</h5>");foreach (string formName in request.Form.Keys){responser.Write(stream, $"{formName}: {request.Form[formName]}<br />");}responser.Write(stream, $"<h5>上传文件列表:</h5>");foreach (FileItem file in request.Files){responser.Write(stream, $"{file.Name}: {file.FileName}, {file.TempFile}<br />");}#endregion#region 输出解析前的上传内容,不能同时与上面代码块运行//responser.Write(stream, $"<pre style=\"font-family:'microsoft yahei',arial; color: green\">{Encoding.UTF8.GetString( request.RequestBody)}</pre>");#endregionresponser.End(stream);return true;
}
运行服务器,浏览器访问:http://127.0.0.1:4189/index.html
,现在我们选择几个文件,为了方便演示,建议选择有少量文本的文本文件。
头像我选择了两个文件,微信选择了一个。
提交表单。下面可以看到,服务器正确处理了表单数据和三个文件数据。
FileItem
对象保存了表单名,文件名,文件类型和文件的临时保存路径,可以将文件移动到应用实际的目录。
移除对OnReceivedPost中对输出解析前的上传内容
代码块的注释,并且把输出解析后的上传内容
代码块注释掉,刷新页面,可以查看原始未解析的数据。可以对照我们前面对上传数据的编码分析
查看下。
8、总结
1、文件上传主要是增加了Content-Type的设置,使服务器能正确处理上传的内容。
2、请求实体的解析部分,因为不像HttpRequest一样有Content-Length来标识具体的长度,只能用boundary去分析什么时候开始解析,什么时候结束解析。
3、对于上传的请求,请求实体解析后,ResponseBody就取不到内容了,所以要想看到请求的具体内容,不能调用Form或Files方法,因为这两个方法一旦调用,上传请求就会被自动解析了。
如果使用第三方去解析的话---HttpMultipartParser,无论.net framwork 版本还是net core版本都可以使用,参考地址: https://github.com/Http-Multipart-Data-Parser/Http-Multipart-Data-Parser,reader/parser of the HTTP multipart/form-data content sent from Windows Runtime via MultipartFormDataContent class. nuget 包管理器直接搜索安装即可使用。
MultipartReader---http://dul.codeplex.com/ ,ASP.NET reader/parser of the HTTP multipart/form-data content sent from Windows Runtime via MultipartFormDataContent class. nuget 包管理器直接搜索安装即可使用。
原文链接:C#实现HTTP服务器:(10)处理文件上传_c#请求浦发银行公共文件上传接口-CSDN博客
相关文章:
C#实现HTTP服务器:处理文件上传---解析MultipartFormDataContent
完整项目托管地址:https://github.com/sometiny/http HTTP还有重要的一块:文件上传。 这篇文章将详细讲解下,前面实现了同一个链接处理多个请求,为了方便,我们独立写了一个HTTP基类,专门处理HTTP请求。 ht…...
【hadoop】远程调试环境
根据上一节,我们已经安装完成hadoop伪分布式环境 hadoop集群环境配置_jdk1.8 441-CSDN博客 还没安装的小伙伴可以看看这个帖子 这一节我们要实现使用vscode进行远程连接,并且完成java配置与测试 目录 vscode 配置远程 安装java插件 新建java项目 …...
检索增强生成(RAG):强化 AI 智能体的知识 “武装”
技术点目录 第一章、智能体(Agent)入门第二章、基于字节Coze 构建智能体(Agent)第三章、基于其他平台构建智能体(Agent)第四章、国内外智能体(Agent)经典案例详解第五章、大语言模型应用开发框架LangChain入门第六章、基于LangChain的大模型API接入第七章…...
使用 Provider 和 GetX 实现 Flutter 局部刷新的几个示例
1. 使用 Provider 实现局部刷新 示例 1:ChangeNotifier Consumer 通过 ChangeNotifier 和 Consumer 实现局部刷新。 import package:flutter/material.dart; import package:provider/provider.dart;void main() {runApp(ChangeNotifierProvider(create: (_) &g…...
notepad++ 正则表达式
注意:Notepad正则表达式字符串最长不能超过69个字符 \ 转义字符 如:要使用 “\” 本身, 则应该使用“\\” \t Tab制表符 注:扩展和正则表达式都支持 \r 回车符CR 注:扩展支持,正则表达式不支持 \n 换行符…...
一起学大语言模型-通过ollama搭建本地大语言模型服务
文章目录 Ollama的github地址链接安装下载需求配置更改安装目录安装更改下载的模型存储位置Ollama一些目录说明日志目录 运行一个模型测试下测试下更改服务监听地址和端口号 Ollama的github地址链接 https://github.com/ollama/ollama 安装 下载 mac安装包下载地址࿱…...
webpack配置详解+项目实战
webpack在vue中的配置,适合想重新认知webpack的你 webpack配置-初级配置 1、配置入口和出口文件 2、配置loader 3、配置eslint(可组装js、jsx检查工具) 4、配置babel(将高级的js语法转换成低版本的js语法) 5、使用 ht…...
【学习笔记】文件上传漏洞--js验证、mime验证、.user.ini、短标签、过滤、文件头
概念 文件上传漏洞 什么是文件上传漏洞? 文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。 这里上传的文件可以是木马,病毒,恶意脚…...
经典卷积神经网络LeNet实现(pytorch版)
LeNet卷积神经网络 一、理论部分1.1 核心理论1.2 LeNet-5 网络结构1.3 关键细节1.4 后期改进1.6 意义与局限性二、代码实现2.1 导包2.1 数据加载和处理2.3 网络构建2.4 训练和测试函数2.4.1 训练函数2.4.2 测试函数2.5 训练和保存模型2.6 模型加载和预测一、理论部分 LeNet是一…...
【VM虚拟机ip问题】
我就是我,不一样的烟火。 文章目录 前言一、启动VM虚拟机1. 开启虚拟机2. 输入账号密码登录3. 依次输入指令 二、主机ping地址测试1. ping ip地址-成功 三、安装-MobaXterm_Personal_21.51. 点击Session2. 选择SSH连接3. 输入信息4. 首次进入5. 连接成功 总结 前言 …...
【计算机视觉】YOLO语义分割
一、语义分割简介 1. 定义 语义分割(Semantic Segmentation)是计算机视觉中的一项任务,其目标是对图像中的每一个像素赋予一个类别标签。与目标检测只给出目标的边界框不同,语义分割能够在像素级别上区分不同类别,从…...
【C++游戏引擎开发】《线性代数》(3):矩阵乘法的SIMD优化与转置加速
一、矩阵乘法数学原理与性能瓶颈 1.1 数学原理 矩阵乘法定义为:给定两个矩阵 A ( m n ) \mathrm{A}(mn) A(mn)和 B ( n p ) \mathrm{B}(np) B(np),它们的乘积 C = A B \mathrm{C}=AB C=AB 是一个 m p \mathrm{m}p mp 的矩阵,其中: C i , j = ∑ k = 1…...
聚焦交易能力提升!EagleTrader 模拟交易系统打造交易成长新路径
在全球市场波动加剧的背景下,交易者面临的挑战已不仅限于技术分析层面。许多交易者在实盘操作中常因情绪干扰导致决策变形,如何构建科学的交易心理与风险控制体系成为行业关注焦点。 国内自营交易考试EagleTrader运用自己研发的模拟交易系统,…...
文件分片上传
1前端 <inputtype"file"accept".mp4"ref"videoInput"change"handleVideoChange"style"display: none;">2生成hash // 根据整个文件的文件名和大小组合的字符串生成hash值,大概率确定文件的唯一性fhash(f…...
C#Lambda表达式与委托关系
1. 核心关系图示 A[委托] --> B[提供方法容器] B --> C[Lambda表达式] C --> D[委托实例的语法糖] A --> E[类型安全约束] C --> F[编译器自动生成委托实例] 2. 本质联系 2.1 类型关系 Lambda表达式是编译器生成的委托实例表达式自动匹配符合签名的…...
机器翻译和文本生成评估指标:BLEU 计算公式
📌 BLEU 计算公式 BLEU 主要由**n-gram精确匹配率(Precision)和长度惩罚(Brevity Penalty, BP)**组成。 1️⃣ n-gram 精确匹配率 计算不同长度的 n-gram(1-gram, 2-gram, ..., n-gram)在生成…...
24 python 类
在办公室里,类就像一个部门(如销售部、财务部),定义了该部门员工的共同属性(姓名、职位)和行为(处理客户、提交报表)。 一、面向对象技术简介 作为一个要入门码农的牛马࿰…...
pycharm与python版本
python 3.6-3.9 pycharm 2021版本搭配最好 python 3.8 pycharm 2019版本搭配最好 pycharm各版本下载...
23种设计模式-结构型模式-外观
文章目录 简介问题解决方案示例代码总结 简介 也称:门面模式、Facade。外观是一种结构型设计模式,能为程序库、框架或其他复杂类提供一个简单的接口。 问题 假设你必须在代码中使用某个复杂的库或框架中的众多对象。正常情况下,你需要负责…...
open3d教程 (三)点云的显示
官方文档位置: Visualization - Open3D 0.19.0 documentationhttps://www.open3d.org/docs/release/tutorial/visualization/visualization.html核心方法: o3d.visualization.draw_geometries([几何对象列表]) import open3d as o3dprint("Load …...
node.js、npm相关知识
Node.js 是一个基于 Chrome V8 JavaScript 引擎 构建的开源、跨平台的 JavaScript 运行时环境,主要用于服务器端编程。它允许开发者使用 JavaScript 编写高性能的后端服务,突破了 JavaScript 仅在浏览器中运行的限制。 npm(Node Package Man…...
大象如何学会太空漫步?美的:科技领先、To B和全球化
中国企业正处在转型的十字路口。一边是全新的技术、全新的市场机遇;一边是转型要面临的沉重负累和巨大投入,无数中国制造、中国品牌仍在寻路,而有的人已经走至半途。 近日,美的集团交出了一份十分亮眼的2024年财报。数据显示&…...
Go红队开发— 收官工具
文章目录 免责声明个人武器开发美观输出Whois查询反查ip目录扫描子域名爆破被动扫描主动扫描(字典爆破)CDN检测 免责声明 💡 本博客绝不涉及任何非法用途。 💡 使用者风险自担,违规后果自负。 💡 守法为先,技术向善。 …...
Android 应用程序包的 adb 命令
查看所有已安装应用的包名 命令:adb shell pm list packages说明:该命令会列出设备上所有已安装应用的包名。可以通过管道符|结合grep命令来过滤特定的包名,例如adb shell pm list packages | grep com.pm,这将只显示包名中包含co…...
北京南文观点:后糖酒会营销,以战略传播重构品牌信心坐标
第112届全国糖酒会落下帷幕,参展品牌面临一个关键命题。如何在流量洪流中沉淀品牌价值?北京南文(全称:南文乐园科技文化(北京)有限公司)认为,糖酒会的结束恰是算法时代品牌认知战的真…...
Qt - findChild
findChild 1. 函数原型2. 功能描述3. 使用场景4. 示例代码5. 注意事项6. 总结 在 Qt 中,每个 QObject 都可以拥有子对象,而 QObject 提供的模板函数 findChild 就是用来在对象树中查找满足特定条件的子对象的工具。下面我们详细介绍一下它的使用和注意事…...
2025年3月个人工作生活总结
本文为 2025年3月工作生活总结。 研发编码 一个curl下载失败问题的记录 问题: 某程序,指定IP和账户密码配置,再使用curl库连接sftp服务器,下载文件。在CentOS系统正常,但在某国产操作系统中失败,需要用命…...
Spring Boot 七种事务传播行为只有 REQUIRES_NEW 和 NESTED 支持部分回滚的分析
Spring Boot 七种事务传播行为支持部分回滚的分析 支持部分回滚的传播行为 REQUIRES_NEW:始终开启新事务,独立于外部事务,失败时仅自身回滚。NESTED:在当前事务中创建保存点(Savepoint),可局部…...
NVIDIA工业设施数字孪生中的机器人模拟
工业设施数字孪生中的机器人模拟 文章目录 工业设施数字孪生中的机器人模拟数字孪生技术的价值NVIDIA Omniverse平台工业机器人仿真的核心组件示例一:使用Isaac Sim创建基本机器人场景示例二:机器人运动规划和轨迹执行示例三:传感器集成与感知…...
docker安装jenkins
docker安装jenkins 1.安装javaJDK 服务器安装javaJDK ,因为我的服务器是直接集成了宝塔面板,我就直接从宝塔面板去安装JDK 最好安装17的JDK,因为后面会安装jenkins,需要17的版本 1.2查看安装是否完成 java --version 安装成功如下&#x…...
量子计算与人工智能融合的未来趋势
最近研学过程中发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。 在当今科技飞速发展…...
人工智能在生物医药-新版ChatGPT-4o辅助一键生成机制图
新版ChatGPT-4o辅助一键生成机制图 作为一位生物医学教授专家,我将基于PubMed最新研究和科研大数据信息,遵循您的要求,一步一步进行思考和预测。 核心问题:乳酸化修饰促进肾透明细胞癌(ccRCC)恶性进展的机…...
支持 MCP 协议的开源 AI Agent 项目
关键要点 研究表明,目前有多个开源 AI Agent 项目支持 MCP 协议,包括 ChatMCP、HyperChat、5ire 和 Cherry Studio 等。这些项目主要用于聊天或桌面助手,允许通过 MCP 协议连接外部数据和工具。MCP 协议是 2024 年 11 月由 Anthropic 开源的…...
JavaRedis和数据库相关面试题
JavaRedis面试题 1. Redis是什么以及Redis为什么快? Redis(Remote Dictionary Server)是一个开源的内存键值数据库,支持多种数据结构(如字符串、哈希、列表、集合等),并提供持久化、复制、…...
Android开发RxJava3延迟操作
Android开发RxJava3延迟操作 直接上代码: /*** param timeMillis 毫秒单位* desc : 延迟多少毫秒操作,* 注:它和Activity生命周期绑定,界面关闭了不会再执行delayTodoListener.delayTodo()* author : congge on 2021-03-25 15:31**/p…...
android 设置状态栏背景
一 让activity ui界面和手机状态栏一样的背景 要让 Activity 的 UI 界面和手机状态栏具有相同的背景颜色,并且能够随着深色模式和非深色模式的切换而改变颜色,你可以按照以下步骤操作: 1. 让 Activity 和 状态栏背景颜色一致 使用 window.s…...
vue 常见优化手段
文章目录 vue常见的优化手段前言使用key(避免明明相同的dom,每次更新都要重新生成)使用冻结的对象(避免无意义的响应式数据)使用函数式组件(减少vue组件实例的生成)vue3vue2使用计算属性(减少数据计算的次数)非实时绑定的表单项(避免表单过多触发监听事件)保持对象的…...
vue生命周期、钩子以及跨域问题简介
Vue 的生命周期是指 Vue 实例从创建到销毁的整个过程。在这个过程中,Vue 提供了一系列的生命周期钩子(Lifecycle Hooks),允许开发者在特定的时间点执行代码。以下是 Vue 的生命周期和钩子的简单说明: Vue 的生命周期阶…...
主相机绑定小地图
资源初始化:在类中通过 property 装饰器定义主相机、小地图相机、小地图精灵等资源属性,便于在编辑器中赋值。在 start 方法里,当确认这些资源存在后,创建渲染纹理并设置其大小,将渲染纹理与小地图相机关联,…...
关于音频采样率,比特,时间轴的理解
是的,你的理解完全正确!-ar、-af aresampleasync1000 和 -b:a 64k 分别用于控制音频的采样率、时间戳调整和比特率。它们各自有不同的作用,但共同确保音频的质量和同步性。下面我将详细解释每个参数的作用和它们之间的关系。 1. -ar 参数 作用…...
三、FFmpeg学习笔记
FFmpeg是一个开源、跨平台的多媒体处理框架,能够实现音视频的录制、转换、剪辑、编码、解码、流媒体传输、过滤与后期处理等几乎所有常见的多媒体操作。其强大之处在于几乎支持所有的音视频格式、编解码器和封装格式,是业界公认的“瑞士军刀”。 FFmp…...
什么是 Java 泛型
一、什么是 Java 泛型? 泛型(Generics) 是 Java 中一种强大的编程机制,允许在定义类、接口和方法时使用类型参数。通过泛型,可以将数据类型作为参数传递,从而实现代码的通用性和类型安全。 简单来说&…...
从 WPF 到 MAUI:跨平台 UI 开发的进化之路
一、引言 在软件开发领域,用户界面(UI)开发一直是至关重要的环节。随着技术的不断发展,开发者对于创建跨平台、高性能且美观的 UI 需求日益增长。Windows Presentation Foundation(WPF)和 .NET Multi - pl…...
Docker学习之dockerfile篇(day8)
文章目录 前言一、问题描述二、具体内容1. Docker 镜像原理2. Docker 镜像制作3. Dockerfile 概念Dockerfile 的基本结构: 4. Dockerfile 关键字5. Docker 实战案例5.1 基于 Nginx 构建 Web 服务器 6. 验证与总结6.1 验证 Dockerfile6.2 总结 前言 Docker 是一种轻…...
Kotlin 作用域函数:apply、let、run、with、also
在 Kotlin 开发中,作用域函数(Scope Functions)是一组能让代码更简洁、更函数式的高阶函数。它们通过不同的作用域规则和返回值设计,解决了对象配置、空安全处理、链式操作等常见场景问题。本文将结合核心特性、代码示例和对比表格…...
Java 线程池与 Kotlin 协程 高阶学习
以下是Java 线程池与 Kotlin 协程 高阶学习的对比指南,结合具体代码示例,展示两者在异步任务处理中的差异和 Kotlin 的简化优势: 分析: 首先,我们需要回忆Java中线程池的常见用法,比如通过ExecutorService创…...
C++学习笔记(三十三)——forward_list
一、std::forward_list (1) forward_list与其适用场景 std::forward_list 是 C的STL中的单向链表(Singly Linked List),它相比 std::list(双向链表)更轻量,适用于仅需要单向遍历的场景。 主要特点&#…...
ROS订阅相机图像识别颜色并发布识别信息
一、前言 区别于之前的直接驱动相机,这里改为读取图像话题进行处理,原因是如果opencv驱动相机后只能单一使用,就限制了其他识别功能(除非将原始图像发布出来),所以这里改成可以读取任意相机图像话题的方法…...
Redis-15.在Java中操作Redis-Spring Data Redis使用方式-操作集合类型的数据
一.操作集合类型的数据 package com.sky.test;import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.*;import j…...
第十一届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组
1.字串排序 不会做,感觉挺难的,有兴趣的可以看下面题解 #include <iostream> #include <string.h> using namespace std; int V; int len;//符合交换次数V,字符串长度最小值 int now; //当前已经构造好的那一部分字符串逆序对个数…...