背景:公司生产线上出现异常,报的错是记录日志时数据库长度超出,导致异常,经查询发现是由于在计算byte长度时出了问题。

问题代码:

                    operatorLog.setOperAfterData(updateString.substring(0,updateString.getBytes("gbk").length > 1024?1024-(updateString.getBytes("gbk").length - updateString.length()):updateString.length()));

只有一行,这么长一行代码,压根没法看,分解成如下代码:

                    int defaultLen = updateString.length();
int gbkLen = updateString.getBytes("gbk").length;
operatorLog.setOperAfterData(updateString.substring(0,
defaultLen > 1024 ? 1024 - (gbkLen - defaultLen) : defaultLen));

笔者目地是想让保存的日志长度限制为1024个字节-byte(不管中文还是英文);当文本中出现中文,一个字符占用两个bytes,但是英文只占用一个byte,首先得计算出文字中包含的中文字符个数,知道差别后不难得出中文长度为:gbkLen - defaultLen,假设字符长度为1025,里面中文有5个,此时gbkLength = 1030, defaultLen = 1025,此时得出的子字符串为1024 - 5 = 1019个字符,其实此时能保证这1019能够存储在1024字节的数据库字段中,因为这1019字符长度肯定不会超过1024;这是作者想要的目地

发生问题场景:

当字符里全是中文的时候会出现什么问题,比如1025个汉字,那得到的字符将是1024 - 1025 = -1,那在取子串的时候updateString.substring(0, -1);,这个时候就发生了我们在生产上跑的异常,数组越界,不可能取索引为-1的元素的值

当时想的解决办法:

当时就有点被绕进去了,最后写出来的代码竟然和原作者差不多一样,只是在最前面加了先取原串的1024个字符,这样确实是当汉字长度小于1024时,问题都好解决,但是实际情况往往不是这样的

问题依然出现:

目标是为了取得1024个字节,但是取得的值完全不对,此时假设字符串长度为513,全为汉字,做为字符串存至数据库时会超出长度1024,此时字节长度为1026

简单解决:

最后由于我们只是简单的记录日志,不做过多处理,决定只取512长度,超过512就不取了

真正解决:

在网上搜索后找到真正的解决办法:

使用循环对字条串的每个字符进行是否为中文判断或都判断将字符一个个读出来,取到规定长度:

String.valueOf(c).getBytes("GBK").length > 1

参考:

http://jingyan.baidu.com/article/1709ad80d383d44634c4f0dc.html

http://www.cnblogs.com/myphoebe/archive/2011/12/20/2294171.html

引伸:

Q: oracle在对字符进行存储时到底使用的是哪种方式,bytes?char?

A: 在定义时,oracle默认是以byte定义的,就是说如果定义成varchar(20), 理论上来说只能存储10个汉字,但对不同编码方式来说,又不一样,一个汉字在oracle中可能会占3个byte,这个是由oracle本身决定,有方法可以解决此问题,在定义表格时这样字义

create table ABC_TABLE (A_FIELD varchar2(20 char)) 

就表示字段A_FIELD会以字符存储,而不是以字节,当然对数据库也可以进行配置,参考以下:

http://doingwell.iteye.com/blog/972938

http://blog.csdn.net/yh555/article/details/6890000

String之-如何取得精确byte长度字符串的更多相关文章

  1. C#中字节数组byte[]和字符串string类型的相互转换

    C#中字节数组byte[]和字符串string类型的相互转换: string转byte[]: byte[] byteArray = System.Text.Encoding.Default.GetBy ...

  2. leetCode题解之寻找string中最后一个word的长度

    1.题目描述 返回一个 string中最后一个单词的长度.单词定义为没有空格的连续的字符,比如 ‘a’,'akkk'. 2.问题分析 从后向前扫描,如果string是以空格‘  ’结尾的,就不用计数, ...

  3. asp.net AES加密跟PHP的一致,将加密的2进制byte[]转换为16进制byte[] 的字符串获得

    <?php class AESUtil { public static function encrypt($input, $key) { $size = mcrypt_get_block_siz ...

  4. Application.StartupPath获取执行文件路径substring()取特定长度字符串取得根目录

    Application.StartupPath获取执行文件路径substring()取特定长度字符串取得根目录 2012-07-20 10:48 257人阅读 评论(0) 收藏 举报 path usi ...

  5. Java String类相关知识梳理(含字符串常量池(String Pool)知识)

    目录 1. String类是什么 1.1 定义 1.2 类结构 1.3 所在的包 2. String类的底层数据结构 3. 关于 intern() 方法(重点) 3.1 作用 3.2 字符串常量池(S ...

  6. String 对象是不动态改变长度的

    在java里 String 对象是不动态改变长度的,只有先转化成StringBuffer,插入处理后在转回. 如 StringBuffer str = new StringBuffer("T ...

  7. byte[] 与字符串转换

    //取值之后进行 StringBuffer buffer=new StringBuffer(); for (int i = 0; i < enBytes.length; i++) { if(i! ...

  8. C语言 realloc为什么要有返回值,realloc返回值具体解释/(解决随意长度字符串输入问题)。

    在C语言操作中会用到大量的内存操作,当中非经常常使用的一个是realloc(). 由字面意思能够知道,该函数的作用是用于又一次分配内存. 使用方式例如以下: NewPtr=(数据类型*)realloc ...

  9. C#利用 string.Join 泛型集合快速转换拼接字符串

    C#利用 string.Join 泛型集合快速转换拼接字符串 List<int> superior_list = new List<int>(); superior_list. ...

随机推荐

  1. 应用HTK搭建语音拨号系统4: 识别器评估

    选自:http://maotong.blog.hexun.com/6261890_d.html 苏统华 哈尔滨工业大学人工智能研究室 2006年10月30日 声明:版权所有,转载请注明作者和来源 该系 ...

  2. Iterator中hasNext(), next() 和ResultSet结果集的next方法的区别

    接口 Iterator专门的迭代输出接口,将元素一个个进行判断,用hasNext() 判断是否有值,用next()方法把元素取出.hasNext() 如果仍有元素可以迭代,则返回 true.next( ...

  3. An exception occurred during a WebClient request

    System.Net.WebException was caught HResult=-2146233079 Message=An exception occurred during a WebCli ...

  4. C# 接口基础

     接口只包含方法.属性.事件或索引器的签名. 实现接口的类或结构必须实现接口定义中指定的接口成员 接口中可以包含字段吗? 第一次被问到这个问题的时候被问愣住了,只能回答:印象当中没见过在接口中定义变量 ...

  5. 套接字Socket

    TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的.UDP( ...

  6. Struts2学习笔记《一》

    (一)struts2中JSP页面数据与Action对应的三种方式 1.属性驱动,及页面中带有name属性的值传递过来action中,struts2会将值直接映射到getter.setter接收器中 此 ...

  7. js apply 和 call

    http://www.cnblogs.com/KeenLeung/archive/2012/11/19/2778229.html

  8. 堆栈指针 ---delete 使用

    对拥有堆中一个有效对象的地址的指针进行删除操作的结果,是将这个堆内存的状态从“使用中” 变为“可用”(此时的可用就是指可以调用内存)释放了,可以再次覆盖此处;;     对指针内存进行删除操作后,指针 ...

  9. 安装VisualSvn Server时遇到的问题

    安装标准版VisualSvnserver,端口443,启用https//,安装过程中报服务启动失败,后用命令行 msiexec /i VisualSVN-Server-2.7.3.msi NO_STA ...

  10. ABAP 仓库理货单导出

    *&---------------------------------------------------------------------* *& Report   *& ...