当前位置: 首页 > news >正文

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 读写数据库中的二进制数据

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

如何在 Elasticsearch 中设置向量搜索 - 第二部分

作者&#xff1a;来自 Elastic Valentin Crettaz 了解如何在 Elasticsearch 中设置向量搜索并执行 k-NN 搜索。 本文是三篇系列文章中的第二篇&#xff0c;深入探讨了向量搜索&#xff08;也称为语义搜索&#xff09;的复杂性以及它在 Elasticsearch 中的实现方式。 第一部分重…...

【CXX-Qt】0 Rust与Qt集成实践指南(CXX-Qt)

CXX-Qt 是一个用于在 Rust 和 Qt 之间实现安全互操作的库。与通常的 Rust Qt 绑定不同&#xff0c;它提供了一种不同的方式来桥接 Qt 代码和 Rust 代码。CXX-Qt 认识到 Qt 和 Rust 代码具有不同的习惯&#xff0c;因此不能直接从一个语言包装到另一个语言。相反&#xff0c;它使…...

C++ 设计模式-适配器模式

适配器模式示例,包括多电压支持、类适配器实现、安全校验等功能: #include <iostream> #include <memory> #include <stdexcept>// 抽象目标接口:通用电源接口 class PowerOutlet {public:virtual ~PowerOutlet() = default;virtual int outputPower() c…...

【Elasticsearch】文本分析Text analysis概述

文本分析概述 文本分析使 Elasticsearch 能够执行全文搜索&#xff0c;搜索结果会返回所有相关的结果&#xff0c;而不仅仅是完全匹配的结果。 如果你搜索“Quick fox jumps”&#xff0c;你可能希望找到包含“A quick brown fox jumps over the lazy dog”的文档&#xff0c…...

【IDEA】2017版本的使用

目录 一、常识 二、安装 1. 下载IDEA2017.exe 2. 安装教程 三、基本配置 1. 自动更新关掉 2. 整合JDK环境 3. 隐藏.idea文件夹和.iml等文件 四、创建Java工程 1. 新建项目 2. 创建包结构&#xff0c;创建类&#xff0c;编写main主函数&#xff0c;在控制台输出内容。…...

ES6 Proxy 用法总结以及 Object.defineProperty用法区别

Proxy 是 ES6 引入的一种强大的拦截机制&#xff0c;用于定义对象的基本操作&#xff08;如读取、赋值、删除等&#xff09;的自定义行为。相较于 Object.defineProperty&#xff0c;Proxy 提供了更灵活、全面的拦截能力。 1. Proxy 语法 const proxy new Proxy(target, hand…...

数据结构——【二叉树模版】

#思路 1、二叉树不同于数的构建&#xff0c;在树节点类中&#xff0c;有数据&#xff0c;左子结点&#xff0c;右子节点三个属性&#xff0c;在树类的构造函数中&#xff0c;添加了变量maxNodes&#xff0c;用于后续列表索引的判断 2.GetTreeNode()函数是常用方法&#xff0c;…...

关闭浏览器安全dns解决访问速度慢的问题

谷歌浏览器加载速度突然变慢了&#xff1f;检查安全DNS功能(DoH)是否被默认开启。 谷歌浏览器在去年已经推出安全DNS功能(即DoH) , 启用此功能后可以通过加密的DNS增强网络连接安全性。例如查询请求被加密后网络运营商将无法嗅探用户访问的地址&#xff0c;因此对于增强用户的…...

【AIGC】语言模型的发展历程:从统计方法到大规模预训练模型的演化

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;语言模型的发展历程&#xff1a;从统计方法到大规模预训练模型的演化1 统计语言模型&#xff08;Statistical Language Model, SLM&#xff09;&#xff1a;统…...

Spring Boot 中的事务管理:默认配置、失效场景及集中配置

Spring Boot 提供了强大的事务管理功能&#xff0c;基于 Spring 的 Transactional 注解。本文将详细介绍事务的默认配置、事务失效的常见场景、以及事务的几种集中配置方式&#xff0c;并给出相应的代码片段。 一、事务的默认配置 在 Spring Boot 中&#xff0c;默认情况下&am…...

DeepSeek 助力 Vue 开发:打造丝滑的进度条

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

deepseek的CoT优势、两阶段训练的有效性学习笔记

文章目录 1 DeepSeek的CoT思维链的优势1.2 open-r1的CoT训练数据1.3 ReAct任务与CoT任务适用场景 2 AI推理方向&#xff1a;deepseek与deepmind的两条路线的差异2.1 PRM与ORM的两大学派分支的差异2.2 DeepSeek-R1的两阶段训练概述 1 DeepSeek的CoT思维链的优势 DeepSeek跟之前…...

分享在职同时准备系统分析师和教资考试的时间安排

&#xff08;在职、时间有限、同时备考系统分析师考试和小学信息技术教资面试&#xff09;&#xff0c;以下是详细的备考计划&#xff0c;确保计划的可行性和通过性。 一、总体安排 时间分配&#xff1a; 每周周末&#xff08;2天&#xff09;用于系统分析师考试备考。工作日晚…...

浅谈Java Spring Boot 框架分析和理解

Spring Boot是一个简化Spring开发的框架&#xff0c;它遵循“约定优于配置”的原则&#xff0c;通过内嵌的Tomcat、Jetty或Undertow等容器&#xff0c;使得开发者能够快速构建独立运行的、生产级别的基于Spring框架的应用程序。Spring Boot包含了大量的自动配置功能&#xff0c…...

【开发心得】CentOS7编译Redis7.4.2打包RPM完整方案

概述 由于最近客户需要解决redis版本升级问题&#xff0c;故而全网寻找安全版本&#xff0c;redis7.4.x版本求而为果&#xff0c;只能自己编译了。 截止发文时间2025-02-12 最新稳定版的redis版本号为7.4.2 Security fixes (CVE-2024-46981) Lua script commands may lead t…...

【网络安全】常见网络协议

1. 网络协议概述 网络协议是网络上两个或多个设备使用的一组规则&#xff0c;用于描述传输顺序和数据结构。网络协议充当数据包中信息附带的指令。这些指令告诉接收设备如何处理数据。协议就像一种通用语言&#xff0c;让世界各地的设备能够相互通信和理解。 尽管网络协议在网…...

电路笔记(元器件):AD 5263数字电位计(暂记)

AD5263 是四通道、15 V、256位数字电位计&#xff0c;可通过SPI/I2C配置具体电平值。 配置模式&#xff1a; W引脚作为电位器的抽头&#xff0c;可在A-B之间调整任意位置的电阻值。也可将W与A(或B)引脚短接&#xff0c;A-W间的电阻总是0欧姆&#xff0c;通过数字接口调整电位器…...

MongoDB 的使用场景

一、内容管理系统 1. 博客平台 文章内容、作者信息、标签、评论等数据结构多样&#xff0c;MongoDB 的无模式特性可轻松应对。比如 WordPress 等博客系统&#xff0c;使用 MongoDB 能灵活存储不同格式和长度的文章内容&#xff0c;以及与文章相关的各种元数据。 2. 新闻网站…...

MongoDB 是什么

MongoDB 是一款文档型数据库&#xff0c;属于 NoSQL 数据库范畴。 一、基本概念 MongoDB 以文档的形式存储数据&#xff0c;文档类似于 JSON 对象&#xff0c;由键值对组成&#xff0c;它以 BSON&#xff08;Binary JSON&#xff09;格式存储在磁盘上&#xff0c;这种格式支持…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...