19.4.6 读写数据库中的二进制数据

news2025/2/13 7:11:16

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。

需要北风数据库的请留言自己的信箱。

北风数据库中,类别表的图片字段在【数据表视图】中显示为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#教程 目录

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2297231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MapReduce到底是个啥?

在聊 MapReduce 之前不妨先看个例子&#xff1a;假设某短视频平台日活用户大约在7000万左右&#xff0c;若平均每一个用户产生3条行为日志&#xff1a;点赞、转发、收藏&#xff1b;这样就是两亿条行为日志&#xff0c;再假设每条日志大小为100个字节&#xff0c;那么一天就会产…

Winform自定义控件与案例 - 构建炫酷的自定义环形进度条控件

文章目录 1、控件效果2、案例实现1、代码实现2、代码解释3、使用示例 4、总结 1、控件效果 2、案例实现 1、代码实现 代码如下&#xff08;示例&#xff09;&#xff1a; using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; …

【SpringBoot苍穹外卖】debugDay03.5

1、AOP面向切面编程 1. Target(ElementType.METHOD) 作用&#xff1a;指定自定义注解可以应用的目标范围。 参数&#xff1a;ElementType 是一个枚举类&#xff0c;定义了注解可以应用的目标类型。 ElementType.METHOD 表示该注解只能用于方法上。 其他常见的 ElementType 值…

flink实时集成利器 - apache seatunnel - 核心架构详解

SeaTunnel&#xff08;原名 Waterdrop&#xff09;是一个分布式、高性能、易扩展的数据集成平台&#xff0c;专注于大数据领域的数据同步、数据迁移和数据转换。它支持多种数据源和数据目标&#xff0c;并可以与 Apache Flink、Spark 等计算引擎集成。以下是 SeaTunnel 的核心架…

视频理解新篇章:Mamba模型的探索与应用

人工智能咨询培训老师叶梓 转载标明出处 想要掌握如何将大模型的力量发挥到极致吗&#xff1f;叶老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具&#xff08;限时免费&#xff09;。 1小时实战课程&#xff0c;您将学习到如何轻松上手并有效利用 Llama Facto…

分形几何表明数学一直存在有首、末的无穷序列

分形几何表明数学一直存在有首、末的无穷序列。一有穷长直线段S可变为锯齿状图形G而由无穷多无穷短直线段连接而成。G和S一样有左、右两个端点。

Python接口自动化测试—接口数据依赖

一般在做自动化测试时&#xff0c;经常会对一整套业务流程进行一组接口上的测试&#xff0c;这时候接口之间经常会有数据依赖&#xff0c;那又该如何继续呢&#xff1f; 那么有如下思路&#xff1a; 抽取之前接口的返回值存储到全局变量字典中。初始化接口请求时&#xff0c;…

C++ 实践扩展(Qt Creator 联动 Visual Studio 2022)

​ 这里我们将在 VS 上实现 QT 编程&#xff0c;实现如下&#xff1a; 一、Vs 2022 配置&#xff08;若已安装&#xff0c;可直接跳过&#xff09; 点击链接&#xff1a;​​​​​Visual Studio 2022 我们先去 Vs 官网下载&#xff0c;如下&#xff1a; 等待程序安装完成之…

Java中性能瓶颈的定位与调优方法

Java中性能瓶颈的定位与调优方法 Java作为一种高效、跨平台的编程语言&#xff0c;广泛应用于企业级应用、服务器端开发、分布式系统等领域。然而&#xff0c;在面对大量并发、高负载的生产环境时&#xff0c;Java应用的性能瓶颈问题往往会暴露出来。如何定位并优化这些性能瓶…

openbmc sdbusplus接口使用(持续更新...)

1.说明 本节介绍如何使用sdbusplus&#xff0c;用来对应不同的场景。 可以参考之前的文章: https://blog.csdn.net/wit_yuan/article/details/145192471 建议阅读本篇文章一定要仔细阅读sd-bus specification 2.说明 2.1 简单server服务注册 本节参考: https://gitee.com…

2.12寒假作业

web&#xff1a;[HDCTF 2023]Welcome To HDCTF 2023 可以直接玩出来 但是这边还是看一下怎么解吧&#xff0c;看一下js代码&#xff0c;在js.game里面找到一个类似brainfuck加密的字符串 解密可以得到答案&#xff0c;但是后面我又去了解了一下let函数let命令、let命令 let命…

GitHub项目推荐--适合练手的13个C++开源项目

1 C 那些事 这是一个适合初学者从入门到进阶的仓库&#xff0c;解决了面试者与学习者想要深入 C及如何入坑 C的问题。 除此之外&#xff0c;本仓库拓展了更加深入的源码分析&#xff0c;多线程并发等的知识&#xff0c;是一个比较全面的 C 学习从入门到进阶提升的仓库。 项目…

【2025 Nature】AI 生成材料算法 MatterGen 文章要点

文章目录 1. MatterGen 框架2. 评价基础模型生成能力的指标3. MatterGen 基础生成能力表现4. MatterGen 定向生成能力表现i. 指定晶体化学式ii. 指定标量性质1. 每个性质微调一次。2. 两个性质联合微调 5. 实验合成6. 模型细节 这篇文档简单介绍 MatterGen 论文亮点。 标题&…

时间序列分析(三)——白噪声检验

此前篇章&#xff1a; 时间序列分析&#xff08;一&#xff09;——基础概念篇 时间序列分析&#xff08;二&#xff09;——平稳性检验 一、相关知识点 白噪声的定义&#xff1a;白噪声序列是一种在统计学和信号处理中常见的随机过程&#xff0c;由一系列相互独立、具有相同…

[前端] axios网络请求二次封装

一、场景描述 为什么要对axios网络请求进行二次封装? 解决代码的复用&#xff0c;提高可维护性。 —这个有两个方案&#xff1a;一个是二次封装一个是实例化。&#xff08;设置一些公共的参数&#xff0c;然后进行请求&#xff09; 为什么可以解决代码的复用&#xff1a; 这是…

【学术投稿-2025年计算机视觉研究进展与应用国际学术会议 (ACVRA 2025)】CSS样式解析:行内、内部与外部样式的区别与优先级分析

简介 2025年计算机视觉研究进展与应用&#xff08;ACVRA 2025&#xff09;将于2025年2月28-3月2日在中国广州召开&#xff0c;会议将汇聚世界各地的顶尖学者、研究人员和行业专家&#xff0c;聚焦计算机视觉领域的最新研究动态与应用成就。本次会议将探讨前沿技术&#xff0c;…

麒麟信安系统隔核后iperf网络测试影响说明

1、背景介绍 采用麒麟信安系统&#xff0c;在飞腾平台&#xff08;X86平台类似&#xff09;上进行了系统核隔离&#xff0c;修改了grub.cfg配置文件中的启动项增加isolcpus2-63 操作&#xff0c;隔核后发现40G网络iperf测试存在影响。 测试命令 taskset -c 16-23 iperf -s -…

WPF进阶 | WPF 资源管理与本地化:多语言支持与资源复用

WPF进阶 | WPF 资源管理与本地化&#xff1a;多语言支持与资源复用 前言一、WPF 资源管理基础1.1 什么是 WPF 资源1.2 资源的定义与存储位置1.3 资源的引用方式 二、资源字典的深入应用2.1 创建资源字典2.2 在应用程序中合并资源字典2.3 资源字典的层级结构与合并顺序 三、WPF …

数据结构与算法-动态规划-区间dp(石子合并,环形石子合并,凸多边形的划分,加分二叉树,棋盘分割)

概念 区间动态规划&#xff08;Interval Dynamic Programming&#xff09;是动态规划的一个分支&#xff0c;它在处理一些与区间相关的最优解问题上非常有效。以下从基本概念、解题步骤、经典例题、优缺点等方面为你详细介绍&#xff1a; 基本概念&#xff1a;区间 DP 的核心…

32单片机学习记录4之串口通信

32单片机学习记录4之串口通信 前置 STM32的GPIO口有通用模式&#xff0c;复用模式&#xff0c;模拟模式三种&#xff0c;加上输入输出就是有6中对应的模式。 我学习了通用模式&#xff0c;会使用GPIO口使用一些简单外设&#xff0c;如LED&#xff0c;独立按键&#xff0c;红外…