19.4.6 读写数据库中的二进制数据
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
需要北风数据库的请留言自己的信箱。
北风数据库中,类别表的图片字段在【数据表视图】中显示为Bitmap Image:

图19-30 图片字段的数据显示为Bitmap Image
它是一个OLE对象,实际就是一个字节数组:

图19-30 图片字段在设计视图中为OLE对象
双击某一个类别的Bitmap Image 可以打开画图查看图片:

图19-32 双击默认会使用画图打开
对于Access数据库中保存的二进制数据,应该使用OleDbCommand的ExecuteReader方法加参数SequentialAccess来打开获得对应的OleDbDataReader对象。
SequentialAccess不会加载整行,而是使 OleDbDataReader将数据作为流来加载。然后可以使用GetBytes或GetChars方法来指定开始读取操作的字节位置以及正在返回的数据的有限的缓冲区大小。尽管无需读取每个字段,但是需要按照字段的返回顺序读取它们。 一旦已经读过返回的数据流中某个位置的内容,就不能再从 OleDbDataReader中读取该位置或该位置之前的数据。
【例 19.13】【项目:code19-013】读取数据表中的图片。
根据BMP文件的格式可知,BMP前两个字节是BMP文件头,为"BM",对应的十六进制值为 42 4D,由于北风数据库中的数据表使用的是OLE对象方式保存图片,所以它在BMP数据基础上增加了其它的数据。在获得图片字段数据后,只需要查找42 4D开始的位置,获得开始位置之后的数据就可以还原这个BMP图像了。
具体的代码如下:
……代码略
private void Form1_Load(object sender, EventArgs e)
{
//建立OleDbConnection对象实例
conn = new OleDbConnection();
//设置OleDbConnection的连接字符串
conn.ConnectionString = "Provider = Microsoft.Jet.OLEDB.4.0;data source=C:\\lessons\\Northwind.mdb;";
//打开数据连接
conn.Open();
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
OleDbCommand command = new OleDbCommand();
command.CommandText = "select 类别名称 from 类别";
command.Connection = conn;
//从类别表中获得类别名称并增加到ComboBox1中
OleDbDataReader reader = command.ExecuteReader();
if (reader.HasRows)
while (reader.Read())
comboBox1.Items.Add(reader.GetString(0));
reader.Close();
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
OleDbCommand command = new OleDbCommand();
command.CommandText = "select 图片 from 类别 where 类别名称='" + comboBox1.Text + "'";
command.Connection = conn;
//使用OleDbDataReader读取图片,使用SequentialAccess模式
OleDbDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess & CommandBehavior.SingleResult & CommandBehavior.SingleRow);
try
{
//存放从字段获得的数据
byte[] fieldsData = new byte[] { };
//每次从字段读取的字节数组
byte[] buffer;
//每次从字段读取的字节数组的长度
int bufferLength = 1024;
buffer = new byte[bufferLength];
//每次使用OleDbDataReader的GetBytes方法时返回实际读取字节数的长度
long readLength;
int pos = 0;
//开始读取
reader.Read();
//读取数据,数据较小时可以使用
fieldsData =(byte[]) reader[0];
或者将上一句代码替换为
循环读取数据,数据较大的时候使用
//while (true)
//{
// //使用GetBytes方法读取数据
// readLength = reader.GetBytes(0, pos * bufferLength, buffer, 0, bufferLength);
// int imgDataLength;
// imgDataLength = fieldsData.Length;
// //保留fieldsData原来的数据基础上扩大fieldsData的大小
// Array.Resize(ref fieldsData,imgDataLength + (int)readLength);
// //将新读取的数据拷贝到fieldsData
// Array.Copy(buffer, 0, fieldsData, imgDataLength, readLength);
// //如果实际读取数据的长度小于设定的长度,那么表示已经读取完毕,退出循环
// if (readLength < bufferLength)
// break;
// pos += 1;
//}
//判断是否包含Bmp的标志 BM,即对应的十六进制值为 42 4D
int bmpSign = -1;
for(int i = 0; i< fieldsData.Length - 1;i++)
{
if( fieldsData[i] == 0x42 & fieldsData[i + 1] == 0x4D)
{
bmpSign = i;
break;
}
}
if(bmpSign == -1)
{
MessageBox.Show("不是有效的图片文件");
return;
}
//从fieldsData中提取出图像的数据保存到imgData
byte[] imgData = new byte[fieldsData.Length - bmpSign];
Array.Copy(fieldsData, bmpSign, imgData, 0, imgData.Length);
//使用字节数组初始化一个MemoryStream对象
System.IO.MemoryStream ms = new System.IO.MemoryStream(imgData);
//从流获得一个image对象
Image img = Image.FromStream(ms);
pictureBox1.Image = img;
//关闭流
ms.Close();
}
catch( Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
//关闭OleDbDataReader
reader.Close();
}
}
运行结果如下图所示:

图19-33 显示类别图片
注意:以上操作是比较常见读取二进制数据值的一种操作,还可以使用以下代码:
fieldsData =(byte[]) reader[0];
替换while { }部分的代码。系统将获得指定字段里面的数据并自动转换为相应的数据类型的值。以上代码更简洁,可以在知道字段对应数据较少的情况下使用以上代码。
【例 19.14】【项目:code19-014】向数据表中写入图片。
private void btnChooseImage_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "所有图片|*.png;*.jpg;*.gif";
if (ofd.ShowDialog() != DialogResult.OK)
return;
picType.Image = Image.FromFile(ofd.FileName);
}
private void btnAdd_Click(object sender, EventArgs e)
{
//检查数据是否符合要求
if (txtType.Text.Trim() == "")
return;
if (txtTypeInfo.Text.Trim() == "")
return;
if (picType.Image == null)
return;
OleDbCommand odcommand = new OleDbCommand();
//更新数据表的SQL语句
odcommand.CommandText = "insert into 类别(类别名称,说明,图片) values(@typename,@typeinfo,@imgType)";
odcommand.Connection = conn;
//添加相应的数据参数
odcommand.Parameters.Add("@typename", OleDbType.VarChar);
odcommand.Parameters["@typename"].Value = txtType.Text;
odcommand.Parameters.Add("@typeinfo", OleDbType.VarChar);
odcommand.Parameters["@typeinfo"].Value = txtTypeInfo.Text;
//按照数据表中类别的图片大小172*120建立图片
Bitmap bmp = new Bitmap(172, 120);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(picType.Image, new Rectangle(0, 0, 172, 120), new Rectangle(0, 0, picType.Image.Width, picType.Image.Height), GraphicsUnit.Pixel);
g.Dispose();
System.IO.MemoryStream ms = new System.IO.MemoryStream();
//将图片以bmp格式保存到内存流中
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
//从内存流将数据保存到字节数组
byte[] imgBuff = new byte[ms.Length];
ms.Position = 0;
imgBuff = ms.ToArray();
ms.Close();
//添加数据参数,这里使用LongVarBinary类型
odcommand.Parameters.Add("@imgType", OleDbType.LongVarBinary);
//对应的数据为字节数组
odcommand.Parameters["@imgType"].Value = imgBuff;
//执行ExecuteNonQuery
odcommand.ExecuteNonQuery();
}
运行结果如下图所示:

图19-34 向类别表中新增数据
由于这里只是保存的图片本身数据,而不是像类别表中图片字段是一个OLE对象,还添加有附加数据,所以,新增的图片数据不能像原有数据一样可以被画图程序打开。但是,使用【例 19.13】中的代码是可以正确显示图片的。
学习更多vb.net知识,请参看vb.net 教程 目录
学习更多C#知识,请参看C#教程 目录
相关文章:
19.4.6 读写数据库中的二进制数据
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 需要北风数据库的请留言自己的信箱。 北风数据库中,类别表的图片字段在【数据表视图】中显示为Bitmap Image࿱…...
如何在 Elasticsearch 中设置向量搜索 - 第二部分
作者:来自 Elastic Valentin Crettaz 了解如何在 Elasticsearch 中设置向量搜索并执行 k-NN 搜索。 本文是三篇系列文章中的第二篇,深入探讨了向量搜索(也称为语义搜索)的复杂性以及它在 Elasticsearch 中的实现方式。 第一部分重…...
【CXX-Qt】0 Rust与Qt集成实践指南(CXX-Qt)
CXX-Qt 是一个用于在 Rust 和 Qt 之间实现安全互操作的库。与通常的 Rust Qt 绑定不同,它提供了一种不同的方式来桥接 Qt 代码和 Rust 代码。CXX-Qt 认识到 Qt 和 Rust 代码具有不同的习惯,因此不能直接从一个语言包装到另一个语言。相反,它使…...
C++ 设计模式-适配器模式
适配器模式示例,包括多电压支持、类适配器实现、安全校验等功能: #include <iostream> #include <memory> #include <stdexcept>// 抽象目标接口:通用电源接口 class PowerOutlet {public:virtual ~PowerOutlet() = default;virtual int outputPower() c…...
【Elasticsearch】文本分析Text analysis概述
文本分析概述 文本分析使 Elasticsearch 能够执行全文搜索,搜索结果会返回所有相关的结果,而不仅仅是完全匹配的结果。 如果你搜索“Quick fox jumps”,你可能希望找到包含“A quick brown fox jumps over the lazy dog”的文档,…...
【IDEA】2017版本的使用
目录 一、常识 二、安装 1. 下载IDEA2017.exe 2. 安装教程 三、基本配置 1. 自动更新关掉 2. 整合JDK环境 3. 隐藏.idea文件夹和.iml等文件 四、创建Java工程 1. 新建项目 2. 创建包结构,创建类,编写main主函数,在控制台输出内容。…...
ES6 Proxy 用法总结以及 Object.defineProperty用法区别
Proxy 是 ES6 引入的一种强大的拦截机制,用于定义对象的基本操作(如读取、赋值、删除等)的自定义行为。相较于 Object.defineProperty,Proxy 提供了更灵活、全面的拦截能力。 1. Proxy 语法 const proxy new Proxy(target, hand…...
数据结构——【二叉树模版】
#思路 1、二叉树不同于数的构建,在树节点类中,有数据,左子结点,右子节点三个属性,在树类的构造函数中,添加了变量maxNodes,用于后续列表索引的判断 2.GetTreeNode()函数是常用方法,…...
关闭浏览器安全dns解决访问速度慢的问题
谷歌浏览器加载速度突然变慢了?检查安全DNS功能(DoH)是否被默认开启。 谷歌浏览器在去年已经推出安全DNS功能(即DoH) , 启用此功能后可以通过加密的DNS增强网络连接安全性。例如查询请求被加密后网络运营商将无法嗅探用户访问的地址,因此对于增强用户的…...
【AIGC】语言模型的发展历程:从统计方法到大规模预训练模型的演化
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 💯前言💯语言模型的发展历程:从统计方法到大规模预训练模型的演化1 统计语言模型(Statistical Language Model, SLM):统…...
Spring Boot 中的事务管理:默认配置、失效场景及集中配置
Spring Boot 提供了强大的事务管理功能,基于 Spring 的 Transactional 注解。本文将详细介绍事务的默认配置、事务失效的常见场景、以及事务的几种集中配置方式,并给出相应的代码片段。 一、事务的默认配置 在 Spring Boot 中,默认情况下&am…...
DeepSeek 助力 Vue 开发:打造丝滑的进度条
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
deepseek的CoT优势、两阶段训练的有效性学习笔记
文章目录 1 DeepSeek的CoT思维链的优势1.2 open-r1的CoT训练数据1.3 ReAct任务与CoT任务适用场景 2 AI推理方向:deepseek与deepmind的两条路线的差异2.1 PRM与ORM的两大学派分支的差异2.2 DeepSeek-R1的两阶段训练概述 1 DeepSeek的CoT思维链的优势 DeepSeek跟之前…...
分享在职同时准备系统分析师和教资考试的时间安排
(在职、时间有限、同时备考系统分析师考试和小学信息技术教资面试),以下是详细的备考计划,确保计划的可行性和通过性。 一、总体安排 时间分配: 每周周末(2天)用于系统分析师考试备考。工作日晚…...
浅谈Java Spring Boot 框架分析和理解
Spring Boot是一个简化Spring开发的框架,它遵循“约定优于配置”的原则,通过内嵌的Tomcat、Jetty或Undertow等容器,使得开发者能够快速构建独立运行的、生产级别的基于Spring框架的应用程序。Spring Boot包含了大量的自动配置功能,…...
【开发心得】CentOS7编译Redis7.4.2打包RPM完整方案
概述 由于最近客户需要解决redis版本升级问题,故而全网寻找安全版本,redis7.4.x版本求而为果,只能自己编译了。 截止发文时间2025-02-12 最新稳定版的redis版本号为7.4.2 Security fixes (CVE-2024-46981) Lua script commands may lead t…...
【网络安全】常见网络协议
1. 网络协议概述 网络协议是网络上两个或多个设备使用的一组规则,用于描述传输顺序和数据结构。网络协议充当数据包中信息附带的指令。这些指令告诉接收设备如何处理数据。协议就像一种通用语言,让世界各地的设备能够相互通信和理解。 尽管网络协议在网…...
电路笔记(元器件):AD 5263数字电位计(暂记)
AD5263 是四通道、15 V、256位数字电位计,可通过SPI/I2C配置具体电平值。 配置模式: W引脚作为电位器的抽头,可在A-B之间调整任意位置的电阻值。也可将W与A(或B)引脚短接,A-W间的电阻总是0欧姆,通过数字接口调整电位器…...
MongoDB 的使用场景
一、内容管理系统 1. 博客平台 文章内容、作者信息、标签、评论等数据结构多样,MongoDB 的无模式特性可轻松应对。比如 WordPress 等博客系统,使用 MongoDB 能灵活存储不同格式和长度的文章内容,以及与文章相关的各种元数据。 2. 新闻网站…...
MongoDB 是什么
MongoDB 是一款文档型数据库,属于 NoSQL 数据库范畴。 一、基本概念 MongoDB 以文档的形式存储数据,文档类似于 JSON 对象,由键值对组成,它以 BSON(Binary JSON)格式存储在磁盘上,这种格式支持…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
