记一次从Sql Server中图片二进制流还原回图片的开发过程
背景:最近在客户现场做项目上线时,需要数据迁移工作。客户之前用的一个BS桌面应用,其中关于图片的存储全部以二进制流的方式写入到Sql Server数据库表中的某个字段中,如下图所示,由于新开发应用采用文件服务器存储图片、文档等,所以就需要将表中的二进制数据还原成图片保存到文件服务器中。棘手的是原BS应用并没有提供图片下载功能以及存储前图片的MIME类型或者文件后缀,这就要求在读取图片二进制流时需要根据内容判断属于哪种类型的图片文件;
思路:首先观察一下上述图片,发现Sql Server Management工具在展示二进制流字段时会以十六进制的形式展示,并且大致可以归纳出相同图片类型的前四个字节(每两个十六进制算作一个字节)字节是一样的,那么我们在读取二进制流的时候先取出前四个字节转换成对应的十六进制,然后再找到这个十六进制字符串和图片类型的关系,那样就可以判断出这个二进制流是哪个图片类型(JPG,PNG,GIT,BMP等)了。
通过查阅 通过二进制头识别文件类型 这篇文章,找到图片相关的十六进制头大致有这么个对应关系,该篇博客详细描述了其它类型的文件和二进制头的对应关系,如有需要可查阅。由于这次的需求只处理图片,所以只关注图片相关的对应关系!
JPEG (jpg),文件头:FFD8FF
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638
Windows Bitmap (bmp),文件头:424D
好了,思路讲解清楚,直接上代码。以下代码为了达成快速实现,借助Springboot+JDBC的方式,即从jdbcTemplate中获取JDBC对象执行操作,有需要的小伙伴只需要查看while里面的内容即可
@RunWith(SpringRunner.class)
@SpringBootTest
public class ErmsDatahandleApplicationTests {@Autowiredprotected JdbcTemplate jdbcTemplate;@Testpublic void contextLoads() throws SQLException, IOException {String sql = "select [ArticleNo],[图片] from WearPartsInfo where [图片] is not null";PreparedStatement statement = jdbcTemplate.getDataSource().getConnection().prepareStatement(sql);ResultSet resultSet = statement.executeQuery();while (resultSet.next()) {// 读取图片二进制流InputStream is = resultSet.getBinaryStream("图片");/*1、从流中读取四个字节数据来判断图片后缀2、解决由于从流中读取四个字节后流当前指针位置会移动,导致图片二进制流数据丢失的问题*/is.mark(4);byte[] bytes = new byte[4];is.read(bytes);// 通过分析字节数据内容获取图片后缀String imageSuffix = FileUtils.getImageSuffix(bytes);if(imageSuffix == null){continue;}is.reset();try {// 将图片二进制流还原成图片后写入本地硬盘ImageIO.write(ImageIO.read(is), imageSuffix, new File("F:\\img\\" + resultSet.getString("ArticleNo") + "." + imageSuffix));} catch (Exception ex) {// 防止出现未知类型的文件格式,导致还原失败System.out.printf("图片写入磁盘异常:%s", resultSet.getString("ArticleNo"));}}}}
以下代码为工具类,主要提供根据字节数据解析文件后缀的过程,下述代码只罗列了几种,如有其它需要可根据实际情况追加即可;
public class FileUtils {/*** 根据字节数据推测文件后缀名* 1、首先将字节数组内容转换为十六进制字符串* 2、拿十六进制字符串和对应头进行简单匹配* JPEG (jpg),文件头:FFD8FF* PNG (png),文件头:89504E47* GIF (gif),文件头:47494638* Windows Bitmap (bmp),文件头:424D** @param bytes* @return*/public static String getImageSuffix(byte[] bytes) {// 将二进制转换成16进制字符串String hexStr = parseByte2HexStr(bytes);if (hexStr == null || hexStr.length() == 0) {return null;}// 进行内容匹配String imageSuffix = "jpg";if (hexStr.startsWith("89504E47")) {imageSuffix = "png";} else if (hexStr.startsWith("47494638")) {imageSuffix = "gif";} else if (hexStr.startsWith("424D")) {imageSuffix = "bmp";}return imageSuffix;}/*** 将二进制转换成16进制字符串** @param bytes* @return*/public static String parseByte2HexStr(byte[] bytes) {StringBuffer sb = new StringBuffer();for (int i = 0; i < bytes.length; i++) {String hex = Integer.toHexString(bytes[i] & 0xFF);if (hex.length() == 1) {hex = '0' + hex;}sb.append(hex.toUpperCase());}return sb.toString();}}
以上,完了!
记一次从Sql Server中图片二进制流还原回图片的开发过程相关推荐
- SQL Server中的文件流
This article will discuss SQL Server FILESTREAM including installation, configuration, enabling and ...
- SQL Server中的零碎数据库还原
This article explores the piecemeal database restore SQL Server feature and its benefits to minimize ...
- C#2.0 从sql server 中读取二进制图片
1/**//// <summary> 2 /// 显示示带图片的记录 3 /// </summary> 4 /// <p ...
- SQL Server中的Replicate函数。循环字符次数,可用于多层分类
描述 REPLICATE :以指定的次数重复字符表达式. 语法 REPLICATE ( character_expression , integer_expression ) 参数 character ...
- SQL Server中的尾日志备份和还原
A tail-log backup is a special type of transaction log backup. In this type of backup, the log recor ...
- SQL Server中的数据库文件组和零碎还原
So far, we discussed many de-facto details about SQL Server database backup and restore. In this 15t ...
- 在AWS RDS SQL Server中恢复数据
This article explores the process to recover data in AWS RDS SQL Server and its recent enhancements. ...
- sql安装弹出sqlcmd_讨论使用SQLCMD和SQL Server代理进行备份和还原自动化
sql安装弹出sqlcmd Database administrators are often requested to refresh a database, mostly to create a ...
- oracle 图片 显示不出,Sql Server 中image类型迁移到Oracle 中Blob类型出现图片显示不出来,why????请博客们帮忙 | 学步园...
我现在在一项目中碰到这么一个问题 Sql Server 中image类型迁移到Oracle Blob类型出现图片显示不出来,我在Sql Server 中看了一条image数据 如下: 1.Sql Se ...
最新文章
- 新上任项目经理遇到的难题
- 合作伙伴常见技术问题集锦
- 【JetPack】kotlin-android-extensions 插件 ( 视图绑定简单用法 )
- Android内存溢出分析
- Android2.2 r1 API 中文文档系列(10) —— CheckBox
- 三星“打法”:先模仿对手 再吃掉对手
- python在另一个函数中使用其他函数的变量_在另一个函数中访问函数的变量,如function() . var in python...
- 高大上!手把手教你在京东云擎上部署个人应用!
- android之数组排序
- Power BI中的AI语义分析应用:《辛普森一家》
- 【代码优化】私有构造器使用及对象创建优化
- 如何在线修改图片大小?图片在线改大小方法推荐给你
- bootStrap 搜索框
- 关于徐晓东,传统武术,以及太极拳
- wsl2 局域网访问_超轻巧局域网传输神器,用手机看电脑上的小电影
- 最小熵原理(四):“物以类聚”之从图书馆到词向量
- Vue 2.x折腾记 - (17) 基于Ant Design Vue 封装一个配置式的表单组件
- CSS3 3D transform
- Linux命令zip和unzip
- SP公司新人培训教案
热门文章
- HTML 中CSS 图像详解
- Zjoi2011 看电影
- 利用virt-manager,xmanager, xshell启动界面来管理虚拟机
- Javascript预解析、作用域、作用域链
- Some regret....
- [导入]如何动态生成table(javascript)
- Python_列表生成式
- 动手学深度学习(PyTorch实现)(四)--梯度消失与梯度爆炸
- 7-18 QQ帐户的申请与登陆 (10 分)
- 苹果x为什么是android,技术角度分析:这就是苹果手机和安卓手机为什么有差距的主要原因...