背景:公司生产线上出现异常,报的错是记录日志时数据库长度超出,导致异常,经查询发现是由于在计算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. chkconfig用法 LINUX

    chkconfig用法 有时候为了方便管理,我们常常喜欢在Linux中将之安装为服务,然后就可以使用服务来管理. 但是当我们运行安装服务的命令时候,假设服务名为myservice #chkconfig ...

  2. openstack 常用命令

    转自: docs.openstack.org $ nova boot --image ubuntu-cloudimage --flavor 1 --user-data mydata.file

  3. 【Other】Ubuntu 14.04 pptp 客户端连接配置

    sudo apt-get install pptp-linux binutils modprobe ppp_mppe sudo pptpsetup --create testvpn --server ...

  4. FreeRTOS--删除任务

    FreeRTOS学习笔记——任务删除 vTaskDelete() API - liyan728的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/liyan728/a ...

  5. 【leetcode】Multiply Strings

    Multiply Strings Given two numbers represented as strings, return multiplication of the numbers as a ...

  6. 关于 strcpy 段错误

    int main(){ char * s = "hello,world" ; char *t = "happy"; strcpy(s,t) ; // error ...

  7. 允许FTP用户登录并禁止Shell登录的方法

    最近安装了vsftpd做FTP服务,发现系统用户的登录shell设置为/sbin/nologin,就无法使用FTP服务.网上资料说,vsftpd会为每个FTP登录用户去在/etc/shells中检查对 ...

  8. 常用js学习

    http://www.cnblogs.com/qiantuwuliang/tag/js/

  9. [Android进阶]学习AccessibilityService实现微信抢红包插件

    在你的手机更多设置或者高级设置中,我们会发现有个无障碍的功能,很多人不知道这个功能具体是干嘛的,其实这个功能是为了增强用户界面以帮助残障人士,或者可能暂时无法与设备充分交互的人们 它的具体实现是通过A ...

  10. Struts2防止表单重复提交

    1.说明 系统拦截器的应用. 表单重复提交:当使用请求转化进行跳转的时候,存在着表单重复提交的问题. 2.在表单中加入s:token 如果页面加入了struts2的标签,页面的请求必须进入struts ...