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#教程 目录

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

sqli-lab靶场学习(六)——Less18-22(User-Agent、Referer、Cookie注入)

前言 前面的关卡&#xff0c;都是直接在输入框或者浏览器的地址栏上做文章即可。但本文这几关&#xff0c;需要用工具拦截请求修改请求头部才行。 Less18&#xff08;User-Agent注入&#xff09; 本关的注入点在User-Agent。我们在用户名和密码框中输入admin/admin后&#xf…

uniapp 使用 鸿蒙开源字体

uniapp vue3 使用 鸿蒙开源字体 我的需求是全局使用鸿蒙字体。 所以&#xff1a; 0. 首先下载鸿蒙字体&#xff1a; 鸿蒙资源 下载后解压&#xff0c;发现里面有几个文件夹&#xff1a; 字体名称说明Sans默认的鸿蒙字体&#xff0c;支持基本的多语言字符&#xff08;包括字…

【ESP32指向鼠标】——icm20948与esp32通信

【ESP32指向鼠标】——icm20948与esp32通信 ICM-20948介绍 ICM-20948 是一款由 InvenSense&#xff08;现为 TDK 的一部分&#xff09;生产的 9 轴传感器集成电路。它结合了 陀螺仪、加速度计和磁力计。 内置了 DMP&#xff08;Digital Motion Processor&#xff09;即负责执…

机器学习(李宏毅)——BERT

一、前言 本文章作为学习2023年《李宏毅机器学习课程》的笔记&#xff0c;感谢台湾大学李宏毅教授的课程&#xff0c;respect&#xff01;&#xff01;&#xff01; 读这篇文章必须先了解self-attention、Transformer&#xff0c;可参阅我其他文章。 二、大纲 BERT简介self-…

NO.12十六届蓝桥杯备战|关系操作符|操作符连用|浮点数比较|练习2道(C++)

关系操作符 关系操作符介绍 ⽤于⽐较的表达式&#xff0c;称为“关系表达式”&#xff08;relational expression&#xff09;&#xff0c;⾥⾯使⽤的运算符就称为“关 系运算符”&#xff08;relational operator&#xff09;&#xff0c;主要有下⾯6个。 运算符描述>⼤…

JVM组成

JVM是什么&#xff1f; JVM&#xff08;Java Virtual Machine&#xff09;&#xff1a;Java程序的运行环境(java二进制字节码的运行环境) 好处&#xff1a; 1.一次编写&#xff0c;到处运行 Java代码是如何做到一次编写&#xff0c;到处运行&#xff1f; 计算机的最底层是计…

不小心删除服务[null]后,git bash出现错误

不小心删除服务[null]后&#xff0c;git bash出现错误&#xff0c;如何解决&#xff1f; 错误描述&#xff1a;打开 git bash、msys2都会出现错误「bash: /dev/null: No such device or address」 问题定位&#xff1a; 1.使用搜索引擎搜索「bash: /dev/null: No such device o…

130,[1] 攻防世界 very_easy_sql

进入靶场 典型SQL注入页面 先查看源码 访问 试试http://127.0.0.1/ 还尝试了其他都是nonono 回归第一个登录页面 提交的内容不在url处显示&#xff0c;反而第二个url页面会在url处显示 明白第一个页面是通过post方式提交&#xff0c;反正没得到什么信息&#xff0c;去抓…

Android10 音频参数导出合并

A10 设备录音时底噪过大&#xff0c;让音频同事校准了下&#xff0c;然后把校准好的参数需要导出来&#xff0c;集成到项目中&#xff0c;然后出包&#xff0c;导出方式在此记录 设备安装debug系统版本调试好后&#xff0c; adb root adb remount adb shell 进入设备目录 导…

django中间件,中间件给下面传值

1、新建middleware.py文件 # myapp/middleware.py import time from django.http import HttpRequest import json from django.http import JsonResponse import urllib.parse from django.core.cache import cache from comm.Db import Db class RequestTimeMiddleware:def …

24电子信息类研究生复试面试问题汇总 电子信息类专业知识问题最全!电子信息复试全流程攻略 电子信息考研复试真题汇总

你是不是在为电子信息考研复试焦虑&#xff1f;害怕被老师问到刁钻问题、担心专业面答不上来&#xff1f;别慌&#xff01;作为复试面试92分逆袭上岸的学姐&#xff0c;今天手把手教你拆解电子信息类复试通关密码&#xff01;看完这篇&#xff0c;让你面试现场直接开大&#xf…

LVDS接口总结--(1)LVDS硬件电路接口

1.LVDS差分信号电路原理 LVDS指的是低压差分信号&#xff0c;是一种电平标准。 差分信号在串行通信中有着非常广泛的应用&#xff0c;典型应用有PCIE中的gen1&#xff0c;gen2&#xff0c;gen3&#xff0c;gen4&#xff0c;gen5&#xff0c;SATA接口&#xff0c;USB接口等。 …

【STM32】HAL库Host MSC读写外部U盘及FatFS文件系统的USB Disk模式

【STM32】HAL库Host MSC读写外部U盘及FatFS文件系统的USB Disk模式 在先前 分别介绍了FatFS文件系统和USB虚拟U盘MSC配置 前者通过MCU读写Flash建立文件系统 后者通过MSC连接电脑使其能够被操作 这两者可以合起来 就能够实现同时在MCU、USB中操作Flash的文件系统 【STM32】通过…

第四期书生大模型实战营-第5关-L2G5000

1 Web 版茴香豆 助教说这趴先跳过&#xff0c;那我就跳过 2 茴香豆本地标准版搭建 2.1 环境搭建 2.2 安装茴香豆 2.3 知识库创建 2.4 测试知识助手 2.4.1 命令行运行 2.4.2 Gradio UI 界面测试 确认一下是否正常 完美。 至于选做&#xff0c;我这么懒&#xff0c;怎么可能…

Elastic Cloud Serverless 现已在 Microsoft Azure 上提供技术预览版

作者&#xff1a;来自 Elastic Yuvi Gupta Elastic Cloud Serverless 提供了启动和扩展安全性、可观察性和搜索解决方案的最快方法 — 无需管理基础设施。 今天&#xff0c;我们很高兴地宣布 Microsoft Azure 上的 Elastic Cloud Serverless 技术预览版现已在美国东部地区推出。…

go语言简单快速的按顺序遍历kv结构(map)

文章目录 需求描述用map实现按照map的key排序用二维切片实现用结构体实现 需求描述 在go语言中&#xff0c;如果需要对map遍历&#xff0c;每次输出的顺序是不固定的&#xff0c;可以考虑存储为二维切片或结构体。 假设现在需要在页面的下拉菜单中展示一些基础的选项&#xff…

TDengine 产品由哪些组件构成

目 录 背景产品生态taosdtaosctaosAdaptertaosKeepertaosExplorertaosXtaosX Agent应用程序或第三方工具 背景 了解一个产品&#xff0c;最好从了解产品包括哪些内容开始&#xff0c;我这里整理了一份儿 TDegnine 产品包括有哪些组件&#xff0c;每个组件作用是什么的说明&a…

2.buuctf [NPUCTF2020]ReadlezPHP(类与对象、类的属性、序列化、代码复用与封装)

进入题目页面如下 哎呦&#xff0c;有趣哈 ctrlu查看源码&#xff0c;下拉看到 点进去看看 看到源码 开始审代码 <?php // #error_reporting(0); 这行代码被注释掉了&#xff0c;原本的作用是关闭所有PHP错误报告 // 定义一个名为 HelloPhp 的类 class HelloPhp {// 声明…

Spring MVC 拦截器(Interceptor)与过滤器(Filter)的区别?

1、两者概述 拦截器&#xff08;Interceptor&#xff09;&#xff1a; 只会拦截那些被 Controller 或 RestController 标注的类中的方法处理的请求&#xff0c;也就是那些由 Spring MVC 调度的请求。过滤器&#xff08;Filter&#xff09;&#xff1a; 会拦截所有类型的 HTTP …

多机器人系统的大语言模型:综述

25年2月来自 Drexel 大学的论文“Large Language Models for Multi-Robot Systems: A Survey”。 大语言模型 (LLM) 的快速发展为多机器人系统 (MRS) 开辟新的可能性&#xff0c;从而增强通信、任务规划和人机交互。与传统的单机器人和多智体系统不同&#xff0c;MRS 带来独特…