开发一个查询功能时,遇到了一个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类型的文本数据的更多相关文章

  1. python 数据库 blob类型 转字符串

    例如: 从数据库里读出了blob类型,如 z = b'61736467' 在py里转化成字符串:bytes.fromhex(z).decode('utf8')

  2. mysql数据库中导入txt文本数据的方法

     安装好MySQL和Navicat 8 for MySQL 通过Navicat 8 for MySQL创建数据库test. 2 在数据库test上创建测试数据表student(主键ID,姓名,年龄,学 ...

  3. jsp页面file标签上传图片以及blob类型数据库存取。

    我的jsp页面表单如下: <form name="form1" action="/YiQu/AddUserServlet?jurisdiction=1" ...

  4. python读取数据库并把数据写入本地文件

    一,介绍 上周用jmeter做性能测试时,接口B传入的参数需要依赖接口A生成的借贷申请ID,接口A运行完需要把生成的借贷申请ID导出来到一个文件,作为参数传给接口B,刚开始的时候,手动去数据库倒, 倒 ...

  5. pandas.read_sql_query()读取数据库数据用chunksize的坑

    最近一项工作需要读取数据库中1500万条数据,考虑到数据量太大,不方便直接一次性读取,不然会内存爆炸.想到用pandas.read_sql_query()里有一个chunksize可以分批返回chun ...

  6. 插入与读取Blob类型数据

    BlobTest package com.aff.PreparedStatement; import java.io.File; import java.io.FileInputStream; imp ...

  7. 读取和写入blob类型数据

    读写oracle  blob类型 http://zyw090111.iteye.com/blog/607869 http://blog.csdn.net/jeryjeryjery/article/de ...

  8. 在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除。

    在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除. 作者:邵盛松 2009-09-05 前言 1关于的BLOB(Binary)数据的存储和读取功能主要参考了MSDN上的一篇& ...

  9. 使用PreparedStatement向数据表中插入、修改、删除、获取Blob类型的数据

    使用PreparedStatement向数据表中插入.修改.删除.获取Blob类型的数据 2014-09-07 20:17 Blob介绍 BLOB类型的字段用于存储二进制数据 MySQL中,BLOB是 ...

随机推荐

  1. C++函数参数的传递顺序

    C++编译器默认使用的是 __cdecl 模式,参数是通过栈传递的,因此是从右到左的传参顺序. int f(int a, int b, int c) { return 0; } int main(){ ...

  2. [转]opencv2早期调用函数

    1.cvLoadImage:将图像文件加载至内存: 2.cvNamedWindow:在屏幕上创建一个窗口: 3.cvShowImage:在一个已创建好的窗口中显示图像: 4.cvWaitKey:使程序 ...

  3. [opencv]白平衡算法中的灰度世界法,改善图像发红发蓝发绿的现象

    #include<iostream> #include <opencv2/opencv.hpp> #include <math.h> using namespace ...

  4. [opencv]keypoint数据结构分析

    KeyPoint这数据结构中有如下数据成员: angle:角度,表示特征点的方向,通过Lowe大神的论文可以知道,为了保证方向不变形,SIFT算法通过对特征点周围邻域进行梯度运算,求得该点方向.-1为 ...

  5. <数据结构>图的最小生成树

    目录 最小生成树问题 Prim算法:点贪心 基本思想:类Dijstra 伪代码 代码实现 复杂度分析:O(VlogV + E) kruskal算法:边贪心 基本思想: 充分利用MST性质 伪代码 代码 ...

  6. Java中关于super关键字的作用

    在子类继承父类中,一般有一行super的语句,需要记住三种使用方法: 1.super.变量/对象名: 使用这种方法可以直接访问父类中的变量或对象,进行修改赋值等操作 2.super.方法名(): 直接 ...

  7. CSS 基础 背景相关属性操作

    1.background-color:red : //设置背景颜色为红色,rgb(0,0,0)和transparent 均为透明颜色 2.background-image(可缩bgi写用tab键) 语 ...

  8. tomcat启动卡在了 At least one JAR was scanned for TLDs yet contained no TLDs 的根本原因与解决办法

    1.前言 有时候服务器开启时启动不了,卡在了 org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned fo ...

  9. Python操作数据库实战

    pymysql # -*- coding: utf-8 -*- """ @Datetime: 2018/12/26 @Author: Zhang Yafei " ...

  10. 利用js模拟用户的cookie信息保存

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6814761849708347907/ 默认已完成爬虫文档<爬虫学习文档顺序> 并简单搭建完展示页面和管 ...