纯文本-FileInputStream的编码与解码方式
前言:以下分析只针对纯文本
1.FileInputStream默认的编码方式就是文件的编码方式
即:源文件是什么编码方式,则利用FileInputStream默认读取的字节数组,就是什么编码方式。
例:纯文本采用“GBK”编码,文本内容如下(注意:文本是纯汉字):
你好世界我是潘小白
利用“GBK”字符集解码如下:
package cn.edu.uestc.IO; import java.io.*; public class TestFileInputStream03 {
public static void main(String[] args){
//流
File file = new File("abc3.txt");
//源
InputStream is = null;
try {
is = new FileInputStream(file);
//操作
byte[] bytes = new byte[4];//这里数组容量必须采用2的倍数,具体原因后面后谈
int len = -1;
while ((len = is.read(bytes))!=-1){
String str = new String(bytes,0,len,"GBK");//利用GBK字符集,对FileInputStream读取的字节数组进行解码
System.out.print(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//释放资源
try {
if (null!=is){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} }
}
/*output:
你好世界我是潘小白
*/
分析:通过代码可知,我采用FileInputStream对格式为“GBK”的纯汉字文本读取,得到的字节数组,可以用"GBK"字符集对其完美解码;反推可知,FileInputStream默认读取的字节数组,其编码格式和原文件编码格式相同。接下来,用"UTF-8"对其进行解码试一试。。。
利用“UTF-8”字符集解码如下:
package cn.edu.uestc.IO; import java.io.*; public class TestFileInputStream03 {
public static void main(String[] args){
//流
File file = new File("abc3.txt");
//源
InputStream is = null;
try {
is = new FileInputStream(file);
//操作
byte[] bytes = new byte[4];//这里数组容量采用3的倍数,区别于上面GBK解码时2的倍数,具体原因后面谈
int len = -1;
while ((len = is.read(bytes))!=-1){
String str = new String(bytes,0,len,"UTF-8");//利用UTF-8字符集对字节数组进行解码
System.out.print(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//释放资源
try {
if (null!=is){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} }
}
/*output:
�������������С��//输出无法解码
*/
分析:利用UTF-8无法解码,再次说明,FileInputStream默认读取的字节数组的编码格式,就是原文件的编码格式。
同理读者可以将纯文本(纯汉字文本)设置成UTF-8的编码格式,再分别采用“GBK”和“UTF-8”方式解码试一试,特别注意数组容量的选择,即:“纯汉字文本,GBK解码时,字节数组容量是2的倍数”、““纯汉字文本,UTF-8解码时,字节数组容量是3的倍数”,原因下面分析。
————————简单的分割————————
2.采用“GBK”对纯汉字文本解码时,字节数组容量是2的倍数;“UTF-8”对纯汉字文本解码时,字节数组容量是3的倍数。
原因是:“GBK”编码时,一个汉字是2个字节,“UTF-8”对常规汉字编码时,一个汉字是3个字节(UTF-8方式下,生僻汉字也可能会占4个字节,这种方式此处不谈)。
所以,你要对字节数组解码时,你首先必须成组的取字节(“GBK”模式下2的倍数一组,“UTF-8”模式下3的倍数一组),否则会将一个汉字的字节拆开,这样肯定会乱码,其对应着我上一篇文章提到的“字节数不全或者丢失情况,产生的乱码”。
此处,我们用代码做一下简单示范,原文本采用“GBK”编码,字节数组容量采用3,不是2的倍数:
package cn.edu.uestc.IO; import java.io.*; public class TestFileInputStream03 {
public static void main(String[] args){
//流
File file = new File("abc3.txt");
//源
InputStream is = null;
try {
is = new FileInputStream(file);
//操作
byte[] bytes = new byte[3];//不是2的倍数
int len = -1;
while ((len = is.read(bytes))!=-1){
String str = new String(bytes,0,len,"GBK");//却用GBKJ解码
System.out.print(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//释放资源
try {
if (null!=is){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} }
}
/*output:
你�檬�界�沂�潘�“�//也就第一个字取全了,解码出来,但是后面字节数乱了,也就无法解码了
*/
结果看到,基本全部乱码。
同理,读者可以采用UTF-8的文本,而设置字节数组容量不是3的倍数,从而进行UTF-8解码,试试看;你会发现,即使编码-解码的字符集同步,但是字节数组中字节个数不对,同样乱码。
——————简单的分割线——————
上面问题2中,“编码-解码的字符集同步,字节数组中字节个数不匹配出现乱码”可以进一步延伸;
我们看到上面,都是纯汉字文本,没有任何英文字符(包括英文字母和英文标点),如果文本是,中英文混合怎么办,还能否采用上面的方式,对FileInputStream读取的字节进行解码呢??
答案是:不能,见下面分析。
3.中英文混合纯文本,用FileInputStream读取时,得到的字节数组无法采用上面 String str = new String(bytes,0,length,"CharacterSet")方式解码,应该采用字符转换流InputStreamReader。
(提示:这里不再考虑标点符号的事了,你可以将英文标点符号看出一个英文字母,中文下的标点看成一个普通汉字分析,因为同一种编码格式下,中文字母和中文标点占用字节数一样,英文字母和英文标点占用字节数一致)
原因:无论是"GBK"还是"UTF-8",英文占用1个字节,所以,当插入引文时,一定会改变字节个数混乱,无法保证“在GBK格式下,每个汉字的两个字节同时被字节数组读取”,也无法保证“在UTF-8格式下,每个汉字的三个字节同时被字节数组读取”,那么将导致后期解码时,出现乱码。
示例:文本格式是“GBK”,文本中插入了一个英文字母
你好p世界我是潘小白
代码如下:
package cn.edu.uestc.IO; import java.io.*; public class TestFileInputStream03 {
public static void main(String[] args){
//流
File file = new File("abc3.txt");
//源
InputStream is = null;
try {
is = new FileInputStream(file);
//操作
byte[] bytes = new byte[2];//字节数组容量采用2
int len = -1;
while ((len = is.read(bytes))!=-1){
String str = new String(bytes,0,len,"GBK");//GBK解码,实现编码-解码格式匹配
System.out.print(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//释放资源
try {
if (null!=is){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*output:
你好p�澜缥沂桥诵“�
*/
结果分析:输出结果从字母p以后,出现乱码;这里选取得字节数组的容量是2,所以前两个汉字被一一读取,并完美解码,但是读取字母p得时候,因为其只占用一个字节,所以汉字“世”被取一个字节,留下一个字节,未被取走,所以导致“世”字无法被正确解码,而且这也引发连锁效应,后面得字都将被错误得读取,从而乱码。
总之:这也是乱码得一种情况,即“字节数丢失或者不完整造成乱码”。
这里,可能有人会有疑问,“如果将字节数组容量设置非常大,一次将中英文混合文本全部读取,然后再解码,这样不出现文字多次读取,造成汉字字节截断得情况,不就行了吗?”
是的,这种情况可以实现正确解码,但是如果文本超级大,这种方式是不现实得,因为字节数组得容量过大,不现实,还是乖乖的用字符转换流InputStreamReader吧。
下面用一个超大字节数组,将文本一次读取,并完美解码得代码示例:
package cn.edu.uestc.IO; import java.io.*; public class TestFileInputStream03 {
public static void main(String[] args){
//流
File file = new File("abc3.txt");
//源
InputStream is = null;
try {
is = new FileInputStream(file);
//操作
byte[] bytes = new byte[20];//数组容量超级大,一次能将中英混合文本全部读取完
int len = -1;
while ((len = is.read(bytes))!=-1){
String str = new String(bytes,0,len,"GBK");
System.out.print(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//释放资源
try {
if (null!=is){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*output:
你好p世界我是潘小白//完美解码
*/
除了上面的情况,读者也可以试试,对于中英文结合的文档,采用UTF-8编码-解码;或者故意将英文字体排布规则,即GBK格式下,2个英文一起排列,放在中文文本中,或者GBK格式下,2个英文一起排列,放在中文文本中。对其进行编码和解码,并分析一下原因。
补充一点:UTF-8编码格式下,一些生僻汉字占4个字节,所以将字节数组容量设置成3的倍数时,面对有生僻字的纯汉字文本,解码时也会出现乱码情况。
——————分割线——————
总结:
上面讨论的三个问题,问题1就是属于编码-解码字符集匹配问题,只是进一步说明了FileInputStream读取的字节数组是哪种编码方式;
问题2和3,是讨论在编码-解码字符集匹配情况下,字节个数不完整或者丢失时,解码时出现乱码的情况,从而说明了用FileInputStream读取时,得到的字节数组无法采用上面 String str = new String(bytes,0,length,"CharacterSet")方式解码,应该采用字符转换流InputStreamReader。
纯文本-FileInputStream的编码与解码方式的更多相关文章
- base64编码、解码的C语言实现
转自:http://www.cnblogs.com/yejianfei/archive/2013/04/06/3002838.html base64是一种基于64个可打印字符来表示二进制数据的表示方法 ...
- C# Base64方式的编码与解码
编码与解码方法: ///编码 public static string EncodeBase64(string code_type, string code) { string encode = &q ...
- form表单提交数据编码方式和tomcat接受数据解码方式的思考
http://blog.sina.com.cn/s/blog_95c8f1ac010198j2.html *********************************************** ...
- 转 python3中SQLLIT编码与解码之Unicode与bytes
#########sample########## sqlite3.OperationalError: Could not decode to UTF-8 column 'logtype' with ...
- Java中的字节,字符与编码,解码
ASCII编码 ASCII码主要是为了表示英文字符而设计的,ASCII码一共规定了128个字符的编码(0x00-0x7F),只占用了一个字节的后面7位,最前面的1位统一规定为0. ISO-8859-1 ...
- java编码原理,java编码和解码问题
java的编码方式原理 java的JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关 . 在JAVA源文件-->JAVAC-->Class-->Java--& ...
- RapidJSON 代码剖析(三):Unicode 的编码与解码
根据 RFC-7159: 8.1 Character Encoding JSON text SHALL be encoded in UTF-8, UTF-16, or UTF-32. The defa ...
- BASE64编码和解码(VC源代码) 并 内存加载 CImage 图像
BASE64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本.完整的BASE64定义可见 RFC1421和 RFC2045.编码后的数据比原始数据略长,为原来的4/3.在电子 ...
- Android 中的编码与解码
前言:今天遇到一个问题,一个用户在登录的时候,出现登录失败.但是其他用户登录都是正常的,经过调试发现登录失败的用户的密码中有两个特殊字符: * .# . 特殊符号在提交表单的时候,出现了编码不一样的 ...
随机推荐
- windows 10 WSL 安装 Centos
1. 打开 WSL,没啥好说的 使用管理员权限打开 powershell,执行 Enable-WindowsOptionalFeature -Online -FeatureName Microsoft ...
- SQL 将一个字段内用逗号分隔的内容分成多条记录
转自:http://www.cnblogs.com/zfanlong1314/archive/2013/01/14/2859848.html --> 测试数据 if not object_id( ...
- mvc EF 从数据库更新实体,添加视图实体时添加不上的问题
视图对象没有一列为非null的,解决办法,在视图中,将某一列排除为null的可能,比如:isnull(te,1),即可.
- MapReduceV1作业生命周期图解以及与YARN基本对比
仿照<hadoop技术内幕:深入解析MapReduce架构设计与实现原理>中的原图,我用手绘制了一份类似的图-_- 4大部分:HDFS,Client,JobTracker,TaskTrac ...
- laravel的函数asset()、url()
1.asset():用于引入静态文件,如 css/JavaScript/images,文件必须存放在public文件目录下 src="{{ asset('home') }}/images/t ...
- Zookeeper 系列(二)安装配制
Zookeeper 系列(二)安装配制 一.Zookeeper 的搭建方式 Zookeeper 安装方式有三种,单机模式和集群模式以及伪集群模式. 单机模式 :Zookeeper 只运行在一台服务器上 ...
- 【附案例】UI交互设计不会做?设计大神带你开启动效灵感之路
随着网络技术的创新发展,如今UI交互设计应用越来越广泛,显然已经成为设计的主流及流行的必然趋势.UI界面交互设计中的动效包括移动,滑块,悬停效果,GIF动画等.UI界面交互设计为何越来越受到青睐?它有 ...
- cxf soap rest webservice spring
1. 导入 jar 包 2. 编写接口 3. 编写实现 4. 配置spring 配置文件 5. 配置web.xml servlet 6. 访问 package com.diancai.test; im ...
- 直压到亚马逊AWS平台,阿里云OSS平台或者腾讯云COS平台
GTX Compressor (直压上云技术预览版) Powered by GTXLab of Genetalks. 技术预览版本下载地址: https://github.com/Genetalks/ ...
- IIS 6 备忘
用IIS7久了, 回到IIS6 总被搞混,所以记录下,以备忘记. 以下是转载和整合了他人的资源,原出处不详. IIS Web 服务器的权限设置有两个地方,一个是 NTFS 文件系统本身的权限设置, ...