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࿱…...
PlantUml常用语法
PlantUml常用语法,将从类图、流程图和序列图这三种最常用的图表类型开始。 类图 基础语法 在 PlantUML 中创建类图时,你可以定义类(Class)、接口(Interface)以及它们之间的关系,如继承&#…...
MapReduce到底是个啥?
在聊 MapReduce 之前不妨先看个例子:假设某短视频平台日活用户大约在7000万左右,若平均每一个用户产生3条行为日志:点赞、转发、收藏;这样就是两亿条行为日志,再假设每条日志大小为100个字节,那么一天就会产…...
Winform自定义控件与案例 - 构建炫酷的自定义环形进度条控件
文章目录 1、控件效果2、案例实现1、代码实现2、代码解释3、使用示例 4、总结 1、控件效果 2、案例实现 1、代码实现 代码如下(示例): using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; …...
【SpringBoot苍穹外卖】debugDay03.5
1、AOP面向切面编程 1. Target(ElementType.METHOD) 作用:指定自定义注解可以应用的目标范围。 参数:ElementType 是一个枚举类,定义了注解可以应用的目标类型。 ElementType.METHOD 表示该注解只能用于方法上。 其他常见的 ElementType 值…...
分享在职同时准备系统分析师和教资考试的时间安排
(在职、时间有限、同时备考系统分析师考试和小学信息技术教资面试),以下是详细的备考计划,确保计划的可行性和通过性。 一、总体安排 时间分配: 每周周末(2天)用于系统分析师考试备考。工作日晚…...
flink实时集成利器 - apache seatunnel - 核心架构详解
SeaTunnel(原名 Waterdrop)是一个分布式、高性能、易扩展的数据集成平台,专注于大数据领域的数据同步、数据迁移和数据转换。它支持多种数据源和数据目标,并可以与 Apache Flink、Spark 等计算引擎集成。以下是 SeaTunnel 的核心架…...
视频理解新篇章:Mamba模型的探索与应用
人工智能咨询培训老师叶梓 转载标明出处 想要掌握如何将大模型的力量发挥到极致吗?叶老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具(限时免费)。 1小时实战课程,您将学习到如何轻松上手并有效利用 Llama Facto…...
分形几何表明数学一直存在有首、末的无穷序列
分形几何表明数学一直存在有首、末的无穷序列。一有穷长直线段S可变为锯齿状图形G而由无穷多无穷短直线段连接而成。G和S一样有左、右两个端点。...
DeepSeek 的 API 服务引入 WPS Office
以下是将 DeepSeek 的 API 服务引入 WPS Office 的通用集成教程。以调用 DeepSeek 的 AI 功能(如文本生成、数据分析)为例,假设你需要通过 WPS 的宏或插件调用外部 API: 准备工作 注册 DeepSeek 账号并获取 API Key 访问 DeepSe…...
Python接口自动化测试—接口数据依赖
一般在做自动化测试时,经常会对一整套业务流程进行一组接口上的测试,这时候接口之间经常会有数据依赖,那又该如何继续呢? 那么有如下思路: 抽取之前接口的返回值存储到全局变量字典中。初始化接口请求时,…...
C++ 实践扩展(Qt Creator 联动 Visual Studio 2022)
这里我们将在 VS 上实现 QT 编程,实现如下: 一、Vs 2022 配置(若已安装,可直接跳过) 点击链接:Visual Studio 2022 我们先去 Vs 官网下载,如下: 等待程序安装完成之…...
分布式系统知识点总结
一、一致性协议 ¥1. CAP理论 CAP理论是分布式系统设计中的一套指导原则,它指出在网络分区的情况下,一个分布式系统最多只能同时满足以下三点中的两点: 一致性(Consistency):所有节点在同一时…...
Java中性能瓶颈的定位与调优方法
Java中性能瓶颈的定位与调优方法 Java作为一种高效、跨平台的编程语言,广泛应用于企业级应用、服务器端开发、分布式系统等领域。然而,在面对大量并发、高负载的生产环境时,Java应用的性能瓶颈问题往往会暴露出来。如何定位并优化这些性能瓶…...
openbmc sdbusplus接口使用(持续更新...)
1.说明 本节介绍如何使用sdbusplus,用来对应不同的场景。 可以参考之前的文章: https://blog.csdn.net/wit_yuan/article/details/145192471 建议阅读本篇文章一定要仔细阅读sd-bus specification 2.说明 2.1 简单server服务注册 本节参考: https://gitee.com…...
2.12寒假作业
web:[HDCTF 2023]Welcome To HDCTF 2023 可以直接玩出来 但是这边还是看一下怎么解吧,看一下js代码,在js.game里面找到一个类似brainfuck加密的字符串 解密可以得到答案,但是后面我又去了解了一下let函数let命令、let命令 let命…...
GitHub项目推荐--适合练手的13个C++开源项目
1 C 那些事 这是一个适合初学者从入门到进阶的仓库,解决了面试者与学习者想要深入 C及如何入坑 C的问题。 除此之外,本仓库拓展了更加深入的源码分析,多线程并发等的知识,是一个比较全面的 C 学习从入门到进阶提升的仓库。 项目…...
【识别摄像头野外动物场景行为】
识别野外动物摄像头下的行为及动作,主要依赖于摄像头的拍摄质量、动物的行为特征以及可能的智能图像识别技术。以下是对这一过程的详细分析: 一、摄像头的作用与拍摄质量 监控与记录:野外动物摄像头,如红外相机,被广泛…...
Linux inode 详解
简介 索引节点(Index Node)是 Linux/类unix 系统文件系统上的一种数据结构,用于存储有关文件或目录的元数据。它包含文件的所有信息,除了文件名和数据。inode 在文件系统如何存储和检索数据方面起着至关重要的作用。 当在 Linux…...
程序员升级进阶之路
熟悉业务、项目代码、工作流程,积极吸取技术资料接需求,画流程图,(伪代码),详细设计明确职业发展方向【很重要】求精:写代码前的技术方案设计 写代码并不难,关键是要明确为什么要写…...
linux下c++连接mysql
1、下载mysql客户端使用的库文件 sudo apt install libmysqlclient-dev 头文件一般在 /usr/include/mysql/ 下 库文件一般在 /usr/lib/x86_64-linux-gnu/ 下 2、mysql c api开发者指南 >>>>官方连接 3、API使用实例 #include<mysql/mysql.h> #include&…...
C语言基础入门:1.3编译流程与调试基础
编译流程与调试基础 ——从源代码到可执行文件的魔法解密 一、编译四重奏:代码的变身之旅 C程序的编译过程如同汽车组装流水线,分为四个精密阶段: 预处理(Preprocessing) gcc -E hello.c -o hello.i # 生成预处理文件…...
AcWing 792. 高精度减法
题目来源: AcWing - 算法基础课 题目内容: 给定两个正整数(不含前导 0),计算它们的差,计算结果可能为负数。 输入格式 共两行,每行包含一个整数。 输出格式 共一行,包含所求的…...
Python爬虫实战:获取51job职位信息,并做数据分析
注意:以下内容仅供技术研究,请遵守目标网站的robots.txt规定,控制请求频率避免对目标服务器造成过大压力! 1. 环境准备 python import requests from bs4 import BeautifulSoup import pandas as pd import re import matplotlib.pyplot as plt 2. 爬虫核心代码(带反爬…...
【2025 Nature】AI 生成材料算法 MatterGen 文章要点
文章目录 1. MatterGen 框架2. 评价基础模型生成能力的指标3. MatterGen 基础生成能力表现4. MatterGen 定向生成能力表现i. 指定晶体化学式ii. 指定标量性质1. 每个性质微调一次。2. 两个性质联合微调 5. 实验合成6. 模型细节 这篇文档简单介绍 MatterGen 论文亮点。 标题&…...
时间序列分析(三)——白噪声检验
此前篇章: 时间序列分析(一)——基础概念篇 时间序列分析(二)——平稳性检验 一、相关知识点 白噪声的定义:白噪声序列是一种在统计学和信号处理中常见的随机过程,由一系列相互独立、具有相同…...
STM32-知识
一、Cortex-M系列双指针 Cortex-M系列的MSP与PSP有一些重要的区别,双指针是为了保证OS的安全性和稳健性。本质上,区别于用户程序使用PSP,操作系统和异常事件单独使用一个MSP指针的目的,是为了保证栈数据不会被用户程序意外访问或…...
将Mac上Python程序的虚拟环境搬到Windows
1. 导出Mac上Python虚拟环境的依赖 cd py && source venv/bin/activate && pip freeze > requirements.txt 2. 在Windows上创建一个新的虚拟环境 python -m venv venv 3. 激活虚拟环境 venv\Scripts\activate 4. 安装依赖 pip install -r requiremen…...
[前端] axios网络请求二次封装
一、场景描述 为什么要对axios网络请求进行二次封装? 解决代码的复用,提高可维护性。 —这个有两个方案:一个是二次封装一个是实例化。(设置一些公共的参数,然后进行请求) 为什么可以解决代码的复用: 这是…...
对前端的技术进行分层
前端相比较后端而言,由于其发展历史和浏览器的标准不一,导致其看上去简单,但是深入起来又很复杂,在最开始学习的时候,我们往往是了解一下三剑客和vue、react的api就开始上手工作了,但是到后面会发现&#x…...
