JAVA字符是以unicode处理,但是通过getbytes()方法,看到的是英文是一个byte而中文是三个byte
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA字符是以unicode处理,但是通过getbytes()方法,看到的是英文是一个byte而中文是三个byte相关的知识,希望对你有一定的参考价值。
可以看出JAVA并不是使用固定长度的字节来编码的,目前我要处理一些固定2个字节16位的字节码,这些字节码在C++中可以用wchar*的方式,在java中如何能正确的转换为JAVA的编码格式,通过utf-8,utf-16,utf-32和其他的中文编码格式,都不能正确的转换,但是我通过手动删除每个字符的第二个字节码,可以转换为正确的JAVA格式,因为一些英文字等没有用到高位字节码,但是如果是用到多字节的字符就会出问题。请问是否有做过该字节码的兄弟请教一下如何转换???感激不尽,高分送上。分数还可追加。
举例:47 0 114 0 101 0 115 0 47 0 103 0 97 0 109 0 101 0 47 0 50 0 48 0 48 0 52 0 47 0 0 0
这是从流中读取的字节码了,通过JAVA转码转换为不正常字符串
手动删除高位:47 114 101 115 47 103 97 109 101 47 50 48 48 52 47
转换正确,这是在只用到一个字节的情况下
表示的字符串应该是“/res/game/2004/”
在Java/C#中,将字符串转换为字节数组时,为了与其他语言兼容,一般应该将一个中文字符转换为2个字节。常见的地方:使用.NET发布Web Service,客户端使用Java访问Web Service,这里就要注意解码和编码的问题了,应该使用同一种字符集编码,否则读取会出现所谓的“中文乱码”。
再来一组测试:
public class Test30
public static void main(String[] args) throws Exception
String source = "i我";
byte[] arr;
int i;
//按Java平台默认的字符集解码
arr = source.getBytes();
System.out.printf("%15s", "default : ");
for(i=0; i<arr.length; i++)
System.out.printf("%X " , arr[i]);
System.out.println();
//按GBK(中文平台的默认字符集)字符集解码
arr = source.getBytes("GBK");
System.out.printf("%15s", "GBK : ");
for(i=0; i<arr.length; i++)
System.out.printf("%X " , arr[i]);
System.out.println();
//按utf-8字符集解码
arr = source.getBytes("utf-8");
System.out.printf("%15s", "utf-8 : ");
for(i=0; i<arr.length; i++)
System.out.printf("%X " , arr[i]);
System.out.println();
//按utf-16字符集解码
arr = source.getBytes("utf-16");
System.out.printf("%15s", "utf-16 : ");
for(i=0; i<arr.length; i++)
System.out.printf("%X " , arr[i]);
System.out.println();
//按ISO-8859-1(ASCII字符集的扩展,0~255)字符集解码
arr = source.getBytes("ISO-8859-1");
System.out.printf("%15s", "ISO-8859-1 : ");
for(i=0; i<arr.length; i++)
System.out.printf("%X " , arr[i]);
System.out.println();
测试结果:
default : 69 CE D2
GBK : 69 CE D2
utf-8 : 69 E6 88 91
utf-16 : FE FF 0 69 62 11
ISO-8859-1 : 69 3F
分析:原来GBK(还有gb2312)字符集的解码结果和Java平台的解码结果完全一致,这不是偶然,因为我的测试平台是Windowx中文平台,GBK是Java中文平台的默认字符集,一个汉字解码成为2个字节,1个字符转换为1个字节。
解决方案:如果多种语言之间需要进行编码、解码,对汉字应该按双字节处理,目前绝大多数语言都支持这种解码方案,针对Java语言,采用默认的字符集(或显示使用GBK或gb2312字符集)就可以了。
扩展:C#的默认字符集不是GBK,即使所处环境是中文平台。 参考技术A 全局通过XML格式传输,包括JS也是传XML对象。追问
跟传输没关系,读取的是本地字节流文件
追答你在得出字节流前拿到的字符串是不是就可以处理了?为什么非要等到转成字节流以后再做事。
我说用XML的意思就是从源头规避掉这些
字节流文件就是字节流,里面还有其他东西的,比如dword,word,wchar等多个类型需要分别转换,这是本是在C++中处理的文件
追答你如果框上原来就是这样 这个条件。。那就帮不上忙了。。。
JAVA里用类似DOM4J,你说的几种类型都能封装成XML对象。前提要去做这些事。。。
你说的都是xml处理的东西,跟这没一点关系,不过还是谢谢你
追答代码是相同的,你有之前的系统在,传输的参数里有这些类型
我说的意思是想从你字节流文件获取的阶段就去做这些事,从源头开始就规避掉这些问题,而不是传到要用了,才去解决。。。
除非您拿到的参数就已经是这样了(比如在数据库里存的就是这种),如果是通过什么算法或方法得到的字节流文件,那问题的根源还是在那
再问一下,如是是单字节与双字节混合,这样去高位是不是会出错?
java输入与输出
注:本文为作者学习总结,如有错误请见谅与及批评指出
1.输入输出流
计算机存储文件在物理上都是以二进制的形式存储,根据逻辑上的不同一般分为以下两种:
文本文件:每个字符对应一个ASCII(Unicode)码,用二进制形式写入磁盘,即文本与二进制之间是以Unicode(ASCII)等常见编码方式翻译。文本编辑器能够打开文本文件。
二进制文件:磁盘同样以二进制保存,但是翻译不再是Unicode(ASCII)等常见编码方式,不同程序自己定义。文本编辑器打开的是乱码文件。
文本文件用字符流(基于字符char)进行读写,二进制文件用字节流(基于字节byte)进行读写。图1为常见的字节流各个类,图2为常见的字符流各个类,图3为输入输出流中常用的一些接口。
图1 常见字节流层次结构
图2 常见字符流层次结构
图3 输入输出流常见接口
2.文本文件读写
Reader(抽象类)是字符输入流的父类,Writer(抽象类)是字符输出流的父类。字符流是以字符(char)为单位读写数据的,一次处理一个unicode,且其底层仍然是基本的字节流。通俗的说,写入时采用某种编码方式把字符转换成二进制存入磁盘中,读取时按照同样的编码方式把二进制读取出来并且转换成字符。因此,字符流只能操作文本文件。
2.0 字符转换流原理
InputStreamReader:可以设置字符集,按照此编码方式将字节转换为字符并且读取。构造函数:InputStreamReader(InputStream in,String charsetName)和InputStreamReader(InputStream in)--系统默认字符集
OutputStreamWriter:可以设置字符集,按照此编码方式将字符转换为字节并且写出。构造函数:OutputStreamWriter(OutputStream out,String charsetName)和OutputStreamWriter(OutputStream out)--系统默认字符集
2.1 文本输出(PrintWriter)
常见构造器:
PrintWriter(File file) PrintWriter(String filename) PrintWriter(File file,String encoding) PrintWriter(String filename,String encoding) PrintWriter(Writer writer) PrintWriter(Writer writer,boolean autoFlush) PrintWriter(OutputStream out) PrintWriter(OutputStream out,boolean autoFlush)
常见方法:
void print(Object obj) //打印obj的toString后的字符串 void print(String s) void println(String s) void print(char[] s) void print(char c) void print(int i) void print(long l) void print(float f) void print(double d) void print(boolean b) //以文本格式打印 void print(String format,Object... args) //按指定格式打印字符串
例子:
PrintWriter out=new PrintWriter("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat","UTF-8"); PrintWriter out=new PrintWriter(new OutputStreamWriter(new FileOutputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat"),"UTF-8"),true);
2.2 文本读入
(1)Scanner类(Scanner(InputStream in,String charsetName))
try(Scanner in=new Scanner(new FileInputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat"),"UTF-8"))
{ while(in.hasNextLine()){ System.out.println(in.nextLine()); } }
(2)短小文本读入一个字符串中
String content=new String(Files.readAllBytes(Paths.get("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat")),"UTF-8");
(3)短小文本一行一行地读
List<String> lines=Files.readAllLines(Paths.get("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat"),StandardCharsets.UTF_8); for(String s:lines){ System.out.println(s); }
(4)大文件将行惰性处理成一个Stream<String>对象(JDK1.8)
try(Stream<String> lines=Files.lines(Paths.get("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat"),StandardCharsets.UTF_8)){ ... }
(5)BufferedReader类
FileInputStream fin=new FileInputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat"); InputStreamReader isr=new InputStreamReader(fin,StandardCharsets.UTF_8); try(BufferedReader in=new BufferedReader(isr);){ String line; while((line=in.readLine())!=null){ System.out.println(line); } }
3.二进制文件读写
3.0 DataInput和DataOutput接口
DataInput接口:用于读取二进制格式的数字(组)、字符、boolean和字符串。
常用方法:writeByte、writeInt、writeShort、writeLong、writeFloat、writeDouble、writeChar、writeBoolean、writeChars、writeUTF(只在写出用于java虚拟机的字符串)
DataOutput接口:用于以二进制格式写数字(组)、字符、boolean和字符串。
常用方法:readByte、readInt、readShort、readLong、readFloat、readDouble、readChar、readBoolean、readUTF、skipBytes(int n)
3.1 DataInputStream和DataOutputStream实现读写
try(DataOutputStream out=new DataOutputStream(new FileOutputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat"))){ out.writeInt(222); out.writeDouble(222.22); out.writeUTF("郭无"); } //////////////////////////////////////////////////////////////////////// try(DataInputStream in=new DataInputStream(new FileInputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat"))){ System.out.println(in.readInt()+","+in.readDouble()+","+in.readUTF()); }
3.2 RandomAccessFile实现读写
RandomAccessFile同时实现了DataInput和DataOutput接口,可以使用构造器第二个参数r/rw指定打开方式。有一个表示下一个将被读入或者写出的字节所处位置的文件指针。
常用构造器:
RandomAccessFile(File file,String mode) RandomAccessFile(String filename,String mode) //mode:r rw
额外常用方法:
seek(Long long):把文件指针设置到任意字节位置(0到文件字节长度) getFilePointer:返回文件指针当前位置 length()文件字节总数
skipBytes(int n):跳过n个字节
例子:
try(RandomAccessFile raf=new RandomAccessFile("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat","rw")){ raf.writeInt(123); raf.writeDouble(123.56); raf.writeUTF("郭文景"); } ///////////////////////////////////////////////////////////////////////////////// try(RandomAccessFile raf=new RandomAccessFile("C:\\\\Users\\\\Administrator\\\\Desktop\\\\raf.dat","rw")){ System.out.println(raf.readInt()+","+raf.readDouble()+","+raf.readUTF()); }
3.3 ZIP文档
java操作zip文档主要涉及以下四个类:ZipInputStream、ZipOutStream、ZipEntry、ZipFile
(1)写入zip文件
FileOutputStream fOutputStream = new FileOutputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\gwj1.zip"); ZipOutputStream zoutput = new ZipOutputStream(fOutputStream); String line="gwj"; for(int i=0;i<3;i++){ byte[] bytes=(line+i).getBytes(); ZipEntry zEntry = new ZipEntry("no"+i+".txt"); zoutput.putNextEntry(zEntry); zoutput.write(bytes); zoutput.closeEntry(); } zoutput.close();
(2)读取zip文件(ZipFile和ZipInputStream都行)
ZipFile zipfile=new ZipFile("C:\\\\Users\\\\Administrator\\\\Desktop\\\\gwj1.zip"); ZipEntry entry; Enumeration e = zipfile.entries(); while(e.hasMoreElements()){ entry = (ZipEntry) e.nextElement(); System.out.println("-------"+entry.getName()+"-------"); InputStreamReader isr=new InputStreamReader(zipfile.getInputStream(entry),StandardCharsets.UTF_8); try(BufferedReader in=new BufferedReader(isr);){ String line; while((line=in.readLine())!=null){ System.out.println(line); } } }
3.4 对象系列化
(1)对象系列化使用
Employee harry = new Employee("Harry Hacker", 50000, 1989, 10, 1); Manager carl = new Manager("Carl Cracker", 80000, 1987, 12, 15); carl.setSecretary(harry); Manager tony = new Manager("Tony Tester", 40000, 1990, 3, 15); tony.setSecretary(harry); Employee[] staff = new Employee[3]; staff[0] = carl; staff[1] = harry; staff[2] = tony; String name="郭文景"; // save all employee records to the file employee.dat try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\employee.dat"))) { out.writeObject(staff); out.writeUTF(name); } try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("C:\\\\Users\\\\Administrator\\\\Desktop\\\\employee.dat"))) { Employee[] newStaff = (Employee[]) in.readObject(); newStaff[1].raiseSalary(10); for (Employee e : newStaff) System.out.println(e); System.out.println(in.readUTF()); }
注:Employee需要实现Serializable接口。Employee implements Serializable
(2)对象系列化原理
- 对象系列化的文件格式
以上是关于JAVA字符是以unicode处理,但是通过getbytes()方法,看到的是英文是一个byte而中文是三个byte的主要内容,如果未能解决你的问题,请参考以下文章