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)格式存储在磁盘上,这种格式支持…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
