读取本文部分数据变为byte数组,如何防止字符被拆开?

Jobernowl 2011-11-17 03:45:55
如题。具体情形是:我要读取一个大文本,于是每次读取一小部分(假设每次读取58kb),读取出来的形式是byte数组,然后再把byte数组转化为String。现在遇上的问题是一些特殊编码如unicode最开始读取到的58kb数据不是乱码,但是往后都是乱码了。经过查找资料得知,原因是unicode一个字符要占几个字节吧,由于我分块读取所以把分界点的字符拆开了,比如只读取了半个字符。应该这就是问题所在了吧。现在我考虑的办法是分析每块读取的byte数组最后长度为10的一部分如果没有半个字符就读完,如果有半个字符就归到下一块。只是我不知该如何区分,求助。或者你们觉得我的想法有错或者有更好的想法也可以提出来。编码类型现在考虑到的有UNICODE、UTF-16BE、UTF-16LE。值得注意的是现在我已经能判断这几种编码类型了,所以问题仅仅有以上所说的
...全文
691 49 打赏 收藏 转发到动态 举报
写回复
用AI写文章
49 条回复
切换为时间正序
请发表友善的回复…
发表回复
绿领巾童鞋 2011-12-05
  • 打赏
  • 举报
回复
...统一一下字符类型,省事
杜尚奎 2011-12-05
  • 打赏
  • 举报
回复
String(char[],offset,size)
jacklondon 2011-12-05
  • 打赏
  • 举报
回复
FileInputStream stream = new FileInputStream("filepath");
String charsetName = "utf-8";
InputStreamReader reader = InputStreamReader(stream , String charsetName);
BufferedReader in = new BufferedReader(reader);
while((String line = in.readLine())!=null){
...
}
in.close();
stream.close();
富兰克陈 2011-12-05
  • 打赏
  • 举报
回复
用字符流,str.toCharArray().length<str.getBytes().length,说明存在占两个字节的中文或其它字符,那你就需要一个个排查,再分开它们了了
lfp001 2011-11-23
  • 打赏
  • 举报
回复
11楼的代码不能实现你的需求吗?

建议你停下来去看看JDK源码,你会发现读取不同字符集的文件是怎么实现的。

你似乎很执着,非得读到byte[]检测“半个字符”之类。先前我在7L说了,按你的思路,要自己编写代码从底层实现,例如你读入58K到byte[],得从byte[]起始处检测,其实JDK现成的方法也是这么干的,你这么绕来绕去的,何不直接用它给你提供的现成的方法呢?

涉及这些比较底层的东西,停下来去看看JDK相应的源码比较好。如果你不能确保写出比它更好的实现代码,还是用它给你提供的现成的方法比较好一点。
Jobernowl 2011-11-23
  • 打赏
  • 举报
回复
详情请看 这个是我做的 那个东西留着很多bug没解决 现在只剩下这个大bug没解决了 不解决都不好意思更新了http://www.anzhi.com/soft_84133.html
Jobernowl 2011-11-23
  • 打赏
  • 举报
回复
[Quote=引用 39 楼 lfp001 的回复:]
11楼的代码不能实现你的需求吗?

建议你停下来去看看JDK源码,你会发现读取不同字符集的文件是怎么实现的。

你似乎很执着,非得读到byte[]检测“半个字符”之类。先前我在7L说了,按你的思路,要自己编写代码从底层实现,例如你读入58K到byte[],得从byte[]起始处检测,其实JDK现成的方法也是这么干的,你这么绕来绕去的,何不直接用它给你提供的现成的方法呢?

涉及这些比较……
[/Quote]

首先 我可能必须要读取为byte了 因为我提供了一个功能 允许用户随时更改编码格式 我不是把string。getbyte的 而是使用当前缓存的byte数组来允许用户任意构造任意编码的text 这样能确保准确与快速 其次我用到了MappedByteBuffer来很方便很快速地任意读取某一块内容的 输入流要求有getChannel()这个方法才能获得MappedByteBuffer的实例。
junerkele 2011-11-23
  • 打赏
  • 举报
回复
大哥竟然对编码如此了解,佩服之至啊
[Quote=引用 36 楼 sasuke38 的回复:]

引用 32 楼 magong 的回复:
第二页乱码问题,不知道你有没有确保data的起始是正确的,包括首字符不残缺,也包括FEFF前缀。


feff前缀是啥意思 还有就是我写错了 没想得到会遇上没匹配到换行符的情况 应该加个判断什么的

引用 35 楼 CherryMs 的回复:
楼主这语气让人有点……


--signature--------------------
http://www.lunwenwa.com/


哎 当时我太着急了 因为我几乎每次都遇上别人问我干啥的 为……
[/Quote]
冰红茶盖 2011-11-22
  • 打赏
  • 举报
回复
坐看楼主和大大交流。虽然很多一下子看不懂...
jingluo 2011-11-22
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 magong 的回复:]

如果只是你顶楼提到的那几种编码,它们有个特点就是总是偶数字节编码的(不论中英文),
所以只要你的切块是偶数字节大小,不可能有字符断在切块之间。
[/Quote]

UNICODE、UTF-16BE、UTF-16LE 都是2byte一个字符
magong 2011-11-22
  • 打赏
  • 举报
回复
第二页乱码问题,不知道你有没有确保data的起始是正确的,包括首字符不残缺,也包括FEFF前缀。
magong 2011-11-22
  • 打赏
  • 举报
回复
你程序我看了,有一个问题就是
如果没匹配上最后应该返回0而不是全部长度。
Jobernowl 2011-11-22
  • 打赏
  • 举报
回复
[Quote=引用 37 楼 magong 的回复:]
引用 36 楼 sasuke38 的回复:

feff前缀是啥意思


UTF-16编码的前缀啊。你程序中不是体现到你知道这一点的嘛。
[/Quote]
没有 关于这方面的我一无所知
magong 2011-11-22
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 sasuke38 的回复:]

feff前缀是啥意思

[/Quote]
UTF-16编码的前缀啊。你程序中不是体现到你知道这一点的嘛。
Jobernowl 2011-11-22
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 magong 的回复:]
第二页乱码问题,不知道你有没有确保data的起始是正确的,包括首字符不残缺,也包括FEFF前缀。
[/Quote]

feff前缀是啥意思 还有就是我写错了 没想得到会遇上没匹配到换行符的情况 应该加个判断什么的

[Quote=引用 35 楼 CherryMs 的回复:]
楼主这语气让人有点……
[/Quote]

哎 当时我太着急了 因为我几乎每次都遇上别人问我干啥的 为什么要那样做,我就急了 。况且世界上那么多人怎么能都问呢 而且无奇不有是不是?很多情况是我们想不到的 因为不是当事人啊
CherryMs 2011-11-22
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 sasuke38 的回复:]
我就是用nio 内存映射 我读取的是1Gb的文本 请大家不要管其他事了 这样子做都是别人的特殊要求你们自己当然不能理解了 因为你们不是本人 请帮一下忙
[/Quote]
楼主这语气让人有点……
Jobernowl 2011-11-21
  • 打赏
  • 举报
回复
因为我发现如果\n前面没有内容的话会跟有内容的情形不一样 所以我就自己加了内容进去 然后再把\n的字节截取出来
Jobernowl 2011-11-21
  • 打赏
  • 举报
回复
我测试的文件内容是中英混合的,不是单纯的英文或者中文
Jobernowl 2011-11-21
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 magong 的回复:]
引用 24 楼 magong 的回复:

不错啊。记得测试下每种charset下不同的换行符字节序列啊,免得破坏换行符。
还有考虑不同OS上的换行符不同的问题。

不好意思,仔细想了下,发现认换行符还是不行的,如以下UTF-16编码序列:
0x53, 0, 0x0A, (byte)0xA0
是两个合法Unicode字符“匀ઠ”
但是其中0, 0x0A子串就是换行符。
尽管这种字符……
[/Quote]

呵呵 你多虑了。首先换行符是唯一的,即使亿分之一的概率出现和换行符字节相同的字符那也是没关系的。因为换行符不是必须的。1.首先残缺字符肯定是在结尾;2.残缺字符的字节数组中不可能包含换行符。
所以我的方案是完美的。
按照约定先奉上我的代码

public int newLength(byte[] data,String charset){
String lastStr=" \n";
String nullStr=" ";
byte[] array=null;
byte[] nullByte=null;
try {
array=lastStr.getBytes(charset);
nullByte=nullStr.getBytes(charset);

} catch (UnsupportedEncodingException e) {
}
if(null!=array){
boolean flag=true;
int len1=data.length;
int len2=array.length;
byte[] temp=new byte[len2-nullByte.length];
System.arraycopy(array, nullByte.length, temp, 0, temp.length);
System.out.println("Array"+Arrays.toString(temp));
len2=temp.length;
int j=len2-1;
for(int i=len1-1;i>-1;i--){
flag=true;
if(j>-1&&data[i]==temp[j]){
j--;
}
else{
flag=false;
j=len2-1;
}
if(j==-1&&flag){
array=null;
nullByte=null;
return i+len2;
}
}
}
array=null;
nullByte=null;
return data.length;
}

写得很罗嗦。我试了一下,结果第二页中英文不会出现乱码了(比之前好多了),但是中文出现乱码,翻回第一页正常。想不明白为什么,求各位大大赐教。难道说我的方案哪里还有漏洞么?还是代码写错了?
magong 2011-11-21
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 sasuke38 的回复:]
首先换行符是唯一的,即使亿分之一的概率出现和换行符字节相同的字符那也是没关系的。因为换行符不是必须的。

1.首先残缺字符肯定是在结尾;2.残缺字符的字节数组中不可能包含换行符。

我试了一下,结果第二页中英文不会出现乱码了(比之前好多了),但是中文出现乱码,翻回第一页正常。
[/Quote]
换行符可以不是必须的,但是错误识别出来的“换行符”前后被破坏的其他字符是否是必须的呢。
如果你是任意切块,随机进入任意一块的话,残缺字符可能也出现在块的头部。
OK,26楼所举例子确实是极端情况,不太会出现。怕的就是某日它真的出现了。就不和你讨论这个了,反正你也知道了。

至于你的程序,
你的nullStr和lastStr为什么都要包含一个空格呢?
加载更多回复(25)
IO流: Input Output 输入输出流 自己去扩展: 1. 对象序列化和反序列化生成一个 2. 流的种类: io包下 扩展nio包下 1. IO分类: 输入流 输出流 字节流 InputStream(抽象类) OutputStream(抽象类) 字符流 Reader (抽象类) Writer(抽象类) 2.字节流:(重点) * 使用场景: * 1.字节流处理除了文本、文字相关所有的流问题,如,png/jpg/avi/map4/mp3/exe * 2.字符流只处理文本、文字相关(编码乱码问题) * * 1.输入流 abstract class InputStream:这个抽象类是表示输入字节流的所有类的超类。 * | * FileInputStream 子类:文件字节输入流 * 1. 构造方法 * FileInputStream(String name) name:表示(绝对路径、相对路径)文件名 * FileInputStream(File file) * * 2. 普通方法: //1. int read(byte[] b) 从输入流读取一些字节数,并将它们存储到缓冲区 b 。 最常用 * //2. int read() 从输入流读取数据的下一个字节。 //3. int read(byte[] b, int off, int len) 从输入流读取最多 len字节的数据到一个字节数组。 * 2.输出流 abstract class OutputStream:这个抽象类是表示输出字节流的所有类的超类。 * | * FileOutputStream 子类:文件字节输出流 * 1. 构造方法 FileOutputStream(String name) name:表示(绝对路径、相对路径)文件名 FileOutputStream(String name, boolean append) append:表示是否在该文件末尾追加数据,如果为true,表示追加,false,表示从头开始覆盖 * FileOutputStream(File file) FileOutputStream(File file, boolean append) * * 2. 普通方法: //1. void write(byte[] b, int off, int len) 将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。 最常用 * //2. void write(byte[] b)将 b.length个字节从指定的字节数组写入此文件输出流。 //3. void write(int b) 将指定的字节写入此文件输出流。 3. 注意事项: 1. 必须要关闭IO流,节约资源开销 2. 关闭IO流原则,先开后关 3. IO流工具类的抽取,将所有的关流(字节流和字符流)方法抽取出来,优化代码 4. 字符流:(重点) * 使用场景:使用于处理文本相关的文件 * * Reader 抽象类: * |子类 * InputStreamReader(转换流) * |子类 * FileReader:适用于读取字符相关的文件 * 1. 构造方法: * 1.FileReader(File file) 2.FileReader(String fileName) fileName:文件名(相对路径/绝对路径) * * 2. 读取方法: * 3. int read(char[] c)读取字符到char数组中 最常用 * 2. int read()读取一个字符 * 3. int read(char[] c,int start,int length)读取制定长度的字符到char数组中 * * Writer 抽象类: * |子类 * OutputStreamWriter(转换流) * |子类 * FileWriter:适用于写出字符相关的文件 * 1. 构造方法: * 1.FileWriter(File file) 默认是false 2.FileWriter(File file, boolean append) append:表示是在文件末尾追加还是从头覆盖,如果true追加,false覆盖,默认是false 3.FileWriter(String fileName) 默认是false 4.FileWriter(String fileName, boolean append) fileName:文件名(相对路径/绝对路径) * 2. 写出方法: * 1. public Writer append(CharSequence csq,int start,int end) * 2. public Writer append(char c) * 3. public Writer append(CharSequence csq) * 4. public void write(char[] c) * 5. public void write(String str) * 6. public void write(String str,int start,int end) 5. 乱码问题:(掌握) GBK: 中文2个字节 英文、数字:1字节 UTF-8: 中文3~6个字节 英文、数字:1字节 编码:将字符串转换为字节 * 1. byte[] getBytes() 根据默认字符集将当前字符串转换为字节数组 * 2. byte[] getBytes(String charsetName) UTF-8/GBK * 按照指定的字符集将将当前字符串转换为字节数组 * * 解码:将字节转换为字符 * 1.String(byte[] bytes, int offset, int length) * 根据默认字符集将字节数组中从指定下标开始到指定长度结束的数据转换为字符串 * * 2.String(byte[] bytes, int offset, int length, String charsetName) * 根据指定字符集将字节数组中从指定下标开始到指定长度结束的数据转换为字符串 * charsetName:字符集名 例如 : "GBK"、"UTF-8" 、"ISO-8859-1" * * 不常用 * 3.String(byte[] bytes) 根据默认字符集将字节数组转换为字符串 * 4.String(byte[] bytes, String charsetName) * 根据默认字符集将字节数组转换为字符串 * * 这里会有乱码问题: * 产生的原因: * 1、因为字符集不统一,即编码和解码new String(b,0,read,"gbk")字符集不一致 * 2、因为字节流读取汉字的时候,字节数组长度不够,将一个汉字拆开了 * 解决: * 1. 用字符流用统一的字符集(最常用) * * 浏览器 : UTF-8 * 前台: * HTML :UTF-8 * CSS :UTF-8 * JS、JSP :UTF-8 * * 后台: * java :UTF-8 * * 数据库: * mysql、oracle、DB2 :UTF-8 * * 开发工具:UTF-8 * 2. 文本文件用统一的字符集 且用字符读取和写出文本相关文件(最常用) * 3. 用一个大的字节数组(一般不用) 6. 转换流:(重点) 目前唯一一个可以设置字符集的流 (简单的理解为包装流,就是将字节流包装以下,方便操作文本相关的文件) * 使用场景: * 别人给提供了字节流,而需要处理文本文件,这时候,就需要用转换流转换一下,更方便处理文本文件 * * 作用:就是一字符流的方式读取或写出文本相关的数据 * * InputStreamReader:将字节输入流包装一下,让其更适合读取本文件 * 构造方法: * 1.InputStreamReader(InputStream in) 创建一个使用默认字符集的InputStreamReader。 * 2.InputStreamReader(InputStream in, String charsetName) 创建一个使用指定字符集的InputStreamReader。 * 普通方法: * public int read(char[] cbuf) * int read(char[] cbuf, int offset, int length) * OutputStreamWriter:将字节输出流包装一下,让其更适合写出文本文件 * 构造方法: * 1. OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter。 * 2. OutputStreamWriter(OutputStream out, String charsetName) 创建一个使用指定字符集的OutputStreamWriter。 普通方法: void write(char[] cbuf, int off, int len) append(CharSequence csq,int start,int end) 只有转换流可以设置字符集 7. jdk7关流的新方式: 用新结构可以自动关流 前提:该流必须是实现了一个接口 AutoCloseable 语法: try( //只能写创建流的操作,不能写其他业务操作 ){ //可能有异常的代码 }catch(异常类型1 e){ }...不需要finally关流了 8. 缓冲流:(重点)包装流 * 1.概念: 提高读取和写出效率的流 * 2.作用: 提高效率 3.使用场景:以后一律都要使用,以提高效率 建议以后都是用字节或者字符数组的方式复制文件,这样效率最高 * 4. * BufferedInputStream * 字节输入缓冲流构造方法: 1.BufferedInputStream(InputStream

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧