读取数据库Blob类型的文本数据
开发一个查询功能时,遇到了一个ORM的问题:数据库字段是 Blob 类型,里面实际存储的是文本数据,Java 后端代码中用字符串 String 类型去接收这个字段的数据时,报错,提示没有对应的setter方法,类型不匹配;换成 byte[] 字节数组类型去接收这个字段的数据,依然报错,同样是找不到setter方法,类型不匹配;最后只好将Java中对应的变量类型改为 java.sql.Blob 类型去接收对应的数据,不报错了,但如何取获取其中的文本数据呢?
使用的代码如下:
private String getTextFromBlob(Blob blob) {
int i = 1;
byte btArr[] = new byte[0];
try {
while (i < blob.length()) {
byte[] bytes = blob.getBytes(i, 1024);
btArr = ArrayUtils.addAll(btArr, bytes);
i += 1024;
}
return new String(btArr, "GB2312");
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
代码逻辑并不复杂,但其实这地方有一个坑,需要注意一下。
最开始的时候写的代码并不是这样,我在 while 循环里每次拿 1024 个字节的数据,然后使用 new String(bytes,"GB2312") 得到字符串,再用 StringBuilder 把每次循环得到的字符串拼接起来,最后 stringBuilder.toString() 返回完整的字符串内容。
写完之后,测试,没问题。但紧接着,我想到了一个问题:我每次拿1024个字节,会不会正好把组成一个汉字的两个字节拆分开呢?
答案是肯定的。虽然 GB2312 编码字符集固定使用 2 个字节来存储汉字,但是 GB2312字符集在存储 ASCII 字符的时候,用的是 1 个字节来存储。也就是说,对于英文字母、数字、英文标点,GB2312 用一个字节存储;对于中文,则使用两个字节存储。这样的话就没法保证每次拿1024个字节不会把某个汉字的两个字节拆分成两段。
因为数据库中的文字都比较短,没有超过一百个字的,程序每次拿1024个字节就把所有的内容都拿完了,所以在测试中返回的文本都是正常的。改了一下代码,把 1024 改成 10,每次拿10个字节,果然出现了乱码问题,文本中的部分中文出现了乱码,而其他部分的中文是正常的。
最后改成了上面的代码,每次依然拿固定长度的字节,然后把结果都放到一个 byte[] 字节数组里,等拿完所有的字节之后,使用 new String(bytes,"GB2312") 得到字符串,这样就避免了上面的问题。实际测试之后(每次拿10个字节),返回的文本正常,没有乱码。
当然这个代码并不完美,代码里使用 apache collections 包里的 ArrayUtils.addAll(byte[] b,byte[] c) 方法来把两个字节数据拼到一块,其内部的实现方法就是创建一个大数组,然后把两个数据的内容依次放进去,这样的话每次都要开辟一个新的内存空间,效率并不高,如果数据量大的话,会有很大的性能开销。
一个比较好的解决方案就是:自己定义一个大数组,每次循环把取到的内容放到这个大数组对应的位置上,避免每次都要 new 一个数组出来,性能更好。缺点就是代码逻辑会复杂一些。
总结:
在对字节流进行读取、拆分的时候,需要注意会不会把表示一个字符的几个字节给误拆分了,这样最后得到的内容会有部分乱码。像常见的GB2312、UTF-8、UTF-16等都是变长的方式进行字节存储,不能进行拆分;而像 UCS-2 这样的字符集,固定使用两个字节存储,按偶数进行拆分就没问题。
读取数据库Blob类型的文本数据的更多相关文章
- python 数据库 blob类型 转字符串
例如: 从数据库里读出了blob类型,如 z = b'61736467' 在py里转化成字符串:bytes.fromhex(z).decode('utf8')
- mysql数据库中导入txt文本数据的方法
安装好MySQL和Navicat 8 for MySQL 通过Navicat 8 for MySQL创建数据库test. 2 在数据库test上创建测试数据表student(主键ID,姓名,年龄,学 ...
- jsp页面file标签上传图片以及blob类型数据库存取。
我的jsp页面表单如下: <form name="form1" action="/YiQu/AddUserServlet?jurisdiction=1" ...
- python读取数据库并把数据写入本地文件
一,介绍 上周用jmeter做性能测试时,接口B传入的参数需要依赖接口A生成的借贷申请ID,接口A运行完需要把生成的借贷申请ID导出来到一个文件,作为参数传给接口B,刚开始的时候,手动去数据库倒, 倒 ...
- pandas.read_sql_query()读取数据库数据用chunksize的坑
最近一项工作需要读取数据库中1500万条数据,考虑到数据量太大,不方便直接一次性读取,不然会内存爆炸.想到用pandas.read_sql_query()里有一个chunksize可以分批返回chun ...
- 插入与读取Blob类型数据
BlobTest package com.aff.PreparedStatement; import java.io.File; import java.io.FileInputStream; imp ...
- 读取和写入blob类型数据
读写oracle blob类型 http://zyw090111.iteye.com/blog/607869 http://blog.csdn.net/jeryjeryjery/article/de ...
- 在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除。
在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除. 作者:邵盛松 2009-09-05 前言 1关于的BLOB(Binary)数据的存储和读取功能主要参考了MSDN上的一篇& ...
- 使用PreparedStatement向数据表中插入、修改、删除、获取Blob类型的数据
使用PreparedStatement向数据表中插入.修改.删除.获取Blob类型的数据 2014-09-07 20:17 Blob介绍 BLOB类型的字段用于存储二进制数据 MySQL中,BLOB是 ...
随机推荐
- MySQL 中常见的时间类型有三种 DATE, DATETIME 和 TIMESTAMP
MySQL 中常见的时间类型有三种 DATE, DATETIME 和 TIMESTAMP,其中 DATE 类型用于表示日期,但是不会包含时间,格式为 YYYY-MM-DD,而 DATETIME 和 T ...
- BP网络简单实现
目录 BP算法的简单实现 Linear 全连接层 ReLu MSELoss 交叉熵损失函数 BP算法的简单实现 """ BPnet 简易实现 约定输入数据维度为(N, i ...
- [c++]对vector<T>容器求交集,并集,去重
#include "iostream" #include "vector" #include "algorithm" //sort函数.交并 ...
- Java程序设计基础作业目录(作业笔记)
持续更新中............. Java程序设计基础笔记 • [目录] 我的大学笔记>>> 第1章 初识Java>>> 1.1.4 学生成绩等级流程图练习 1 ...
- Flask_CSRF保护(十一)
flask使用 flask-wtf 模块提供的 CSRFProtect对象开启CSRF防护,方法如下: 后端设置 from flask import Flask from flask_wtf.csrf ...
- Django_MVT(二)
一.MVT简介 M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理. V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答. T全拼为Template,与 ...
- python中多模块导入的注意点
导入模块常见的方式有 import xxx ,from xxx import yyy 或者 from xxx import yyy as a(为导入包(方法)取别名主要用于防止包名与模块中的变量重 ...
- springboot 配置 swagger2
1.pom.xml 添加依赖 <!--swagger2 依赖--> <dependency> <groupId>io.springfox</groupId&g ...
- 创客系列教程——认识LED灯
认识LED灯 一.初识LED灯 LED灯是一种能够将电能转化为可见光的固态的半导体器件,它可以直接把电转化为光.LED灯逐步融入到生活中的方方面面:室内外的照明.电子指示牌.酷炫的舞台灯光.车辆的 ...
- ADD software version display
ADD software version display ADD software version display1. Problem Description2. Analysis3. Solutio ...