Java 输入输出流


203 第 7 章 IO/输入输出 ..................................................................................................... 203 7.1 File 类 .................................................................................................................. 204 7.2 RandomAccessFile 类 .......................................................................................... 206 7.3 节点流 .................................................................................................................. 208 7.3.1 理解流的概念 ........................................................................................... 208 7.3.2 InputStream 与 OutputStream ................................................................... 209 指点迷津:1.如何选择输入与输出 2.为什么要调用 close 方法 多学两招:IO 中的缓冲区 7.3.3 FileInputStream 与 FileOutputStream ...................................................... 212 7.3.4 Reader 与 Writer ....................................................................................... 213 独家见解:隐含的缓冲区 7.3.5 PipedInputStream 与 PipedOutputStream ................................................. 214 独家见解:管道流类的作用 7.3.6 ByteArrayInputStream 与 ByteArrayOutputStream ................................. 217 7.3.7 IO 程序代码的复用 .................................................................................. 218 7.4 过滤流与包装类 .................................................................................................. 220 7.4.1 理解包装类的概念与作用 ....................................................................... 220 7.4.2 BufferedInputStream 与 BufferedOuputStream ....................................... 221 脚下留心:使用 mark 时应考虑的问题 7.4.3 DataInputStream 与 DataOutputStream ................................................... 222 7.4.4 PrintStream ................................................................................................ 224 指点迷津:何谓格式化输出 7.4.5 ObjectInputStream 与 ObjectOutputStream .............................................. 225 指点迷津:文件中的数据可读但不见得可用 7.4.6 字节流与字符流的转换 ........................................................................... 228 7.4.7 IO 包中的类层次关系图 .......................................................................... 230 7.5 IO 中的高级应用................................................................................................. 231 7.5.1 字符集的编码问题 ................................................................................... 231 指点迷津:如何处理字符乱码问题 7.5.2 Decorator 设计模式 ................................................................................. 242 7.5.3 Java 虚拟机读写其他进程的数据 ........................................................... 243 多学两招:提高程序的运行效率 204 第 7 章 IO/输入输出 大多数应用程序都需要与外部设备进行数据交换,最常见的外部设备包含磁盘和网络, IO 就是指应用程序对这些设备的数据输入与输出,在程序中,键盘被当作输入文件,显示 器被当作输出文件使用。Java 语言定义了许多类专门负责各种方式的输入输出,这些类都 被放在 java.io 包中。 7.1 File 类 File 类是 IO 包中唯一代表磁盘文件本身的对象,File 类定义了一些与平台无关的方法 来操纵文件,通过调用 File 类提供的各种方法,我们能够创建、删除文件,重命名文件, 判断文件的读写权限及是否存在,设置和查询文件的最近修改时间。 在 Java 中,目录也被当作 File 使用,只是多了一些目录特有的功能——可以用 list 方法列出目录中的文件名。在 Unix 下的路径分隔符为(/),在 Dos 下的路径分隔符为(\), Java 可以正确处理 Unix 和 Dos 的路径分隔符,即使我们在 Windows 环境下使用(/)作为 路径分隔符,Java 仍然能够正确处理。 我们用下面的一个简单应用来演示一下 File 类用法,判断某个文件是否存在,存在则 删除,不存在则创建,读者可以在 Windows 的资源管理器下观察到这个变化。 程序清单:FileTest.java import java.io.*; public class FileTest { public static void main(String[] args) { File f=new File("c:\\1.txt"); if(f.exists()) f.delete(); else try { f.createNewFile(); } catch(Exception e) { System.out.println(e.getMessage()); } System.out.println("File name:"+f.getName()); System.out.println("File path:"+f.getPath()); System.out.println("Abs path:"+f.getAbsolutePath()); System.out.println("Parent:"+f.getParent()); System.out.println(f.exists()?"exists":"does not exist"); System.out.println(f.canWrite()?"is writeable":" 205 is not writeable"); System.out.println(f.canRead()?"is readable":"is not readable"); System.out.println(f.isDirectory()?"is ":"is not"+" a directory"); System.out.println(f.isFile()?"is normal file":"might be a named pipe"); System.out.println(f.isAbsolute()?"is absolute":" is not absolute"); System.out.println("File last modified:"+f.lastModified()); System.out.println("File size:"+f.length()+" Bytes"); } } 当运行这个程序时会因为文件 1.txt 的存在和不存在而出现两种结果: 结果 1: File name:1.txt File path:c:\1.txt Abs path:c:\1.txt Parent:c:\ exists is writeable is readable is not a directory is normal file is absolute File last modified:1051755103126 File size:0 Bytes 结果 2: File name:1.txt File path:c:\1.txt Abs path:c:\1.txt Parent:c:\ does not exist is not writeable is not readable is not a directory might be a named pipe is absolute File last modified:0 File size:0 Bytes 注:delete 方法删除由 File 对象的路径所表示的磁盘文件。它只能删除普通文件,而不能删除目 录,即使是空目录也不行。 关于 File 类的其它方法,是没法死记硬背的,读者在需要时自己查看 JDK 文档,应该 能够明白怎么使用。初步接触了 File 类,我们发现 File 类不能访问文件的内容,即不能够 从文件中读取数据或往文件里写数据,它只能对文件本身的属性进行操作。 206 7.2 RandomAccessFile 类 RandomAccessFile 类可以说是 Java 语言中功能最为丰富的文件访问类,它提供了众多 的文件访问方法。RandomAccessFile 类支持“随机访问”方式,我们可以跳转到文件的任 意位置处读写数据。在你访问一个文件的时候,不想把文件从头读到尾,并希望像访问一个数 据库一样的访问一个文本文件,使用 RandomAccessFile 类就是你的最佳选择。 RandomAccessFile 对象类有个位置指示器,指向当前读写处的位置,当读写 n 个字节 后,文件指示器将指向这 n 个字节后的下一个字节处。刚打开文件时,文件指示器指向文件 的开头处,我们可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。 RandomAccessFile 在等长记录格式文件的随机(相对顺序而言)读取时有很大的优势,但 该类仅限于操作文件,不能访问其他的 IO 设备,如网络,内存映象等。 有关 RandomAccessFile 类中的成员方法及使用说明,请参阅 JDK 文档。下面是一个使 用 RandomAccessFile 的例子,往文件中写入三名员工的信息,然后按照第二名员工,第一 名员工,第三名员工的先后顺序读出。RandomAccessFile 可以以只读或读写方式打开文件, 具体使用哪种方式取决于我们创建 RandomAccessFile 类对象的构造方式: new RandomAccessFile(f,"rw"); //读写方式 new RandomAccessFile(f,"r"); //只读方式 注:当我们的程序需要以读写的方式打开一个文件时,如果这个文件不存在,程序会为 你创建它。 我们还需要设计一个类来封装员工信息。一个员工信息就是文件中的一条记录,我们必 须保证每条记录在文件中的大小相同,也就是每个员工的姓名字段在文件中的长度是一样 的,我们才能够准确定位每条记录在文件中的具体位置。假设 name 中有八个字符,少于八 个则补空格(这里我们用"\u0000"),多于八个则去掉后面多余的部分。由于年龄是整型数, 不管这个数有多大,只要它不超过整型数的范围,在内存中都是占 4 个字节大小。 程序清单:RandomFileTest.java import java.io.*; public class RandomFileTest { public static void main(String [] args) throws Exception { Employee e1 = new Employee("zhangsan",23); Employee e2 = new Employee("Lisi",24); Employee e3 = new Employee("Wangwu",25); RandomAccessFile ra=new RandomAccessFile("c:\\1.txt","rw"); ra.write(e1.name.getBytes()); ra.writeInt(e1.age); ra.write(e2.name.getBytes()); ra.writeInt(e2.age); ra.write(e3.name.getBytes()); ra.writeInt(e3.age); ra.close(); RandomAccessFile raf=new RandomAccessFile("c:\\1.txt","r"); int len=8; 207 raf.skipBytes(12); //跳过第一个员工的信息,其中姓名 8 字节,年龄 4 字节 System.out.println("第二个员工信息:"); String str=""; for(int i=0;iLEN) { name = name.substring(0,8); } else { while(name.length()>6))),(byte)(0x80|(0x3f&c))。  假如字符 c 的范围在\u0800 和 uffff 之间,对应的 UTF 码占三个字节,内容为: (byte)(0xe0|(0x0f&(c>>12))),(byte)(0x80|(0x3f &(c>>6))),(byte)(0x80|(0x3f& c )) 在与 DataOutputStream 类对应的输入流 DataInputStream 类中只提供了一个 readUTF 方法返回字符串,也就是 DataInputStream 类中没有直接读取到 DataOutputStream 类的 writeBytes 和 writeChars 方法写入的字符串,这又是为什么呢?我们要在一个连续的字节 流读取一个字符串(只是流中的一段内容),如果没有特殊的标记作为一个字符串的结尾, 而且和我们事先也不知道这个字符串的长度,我们是没法知道读取到什么位置才是这个字符 串的结束。在DataOutputStream类中只有writeUTF方法向目标设备中写入了字符串的长度, 所以,我们也只能准确地读回这个方法写入的字符串。 我们下面的程序使用了多个流对象来进行文件的读写,这多个流对象形成了一个链,我 们称之为流栈,如图 7.3 所示: 223 图 7.3 import java.io.*; public class DataStreamTest { public static void main(String[] args) { try { FileOutputStream fos = new FileOutputStream("hello.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); DataOutputStream dos = new DataOutputStream(bos); dos.writeUTF("ab 中国"); dos.writeBytes("ab 中国"); dos.writeChars("ab 中国"); dos.close(); FileInputStream fis = new FileInputStream("hello.txt"); BufferedInputStream bis = new BufferedInputStream(fis); DataInputStream dis = new DataInputStream(bis); System.out.println(dis.readUTF()); /*byte [] buf=new byte[1024]; int len = dis.read(buf); System.out.println(new String(buf,0,len));*/ fis.close(); } catch(Exception e) { System.out.println(e.getMessage()); } } } 如果正在使用一个流栈,程序关闭最上面的一个流也就自动关闭了栈中的所有底层流, 所以程序中只调用了 DataInputStream 与 DataOutputStream 这两个流对象的 close 方法。 我们用记事本程序打开 hello.txt 文件,显示内容如下 224 图 7.4 我们能看出其中的大概,就如同作者直接在上面的图中进行标注的那样,writeChars 写入的 a 字符都占用两个字节。尽管我们在记事本程序中看不出 writeUTF 写入的字符串是 “ab 中国”,但程序通过 readUTF 读回后显示在屏幕上的仍是“ab 中国”,这个过程就好比 一个写入函数把字符串加密后写入文件,我们用记事本程序是看不出其实际写入的内容的, 但对应的读取函数却能正确返回先前写入的字符串,因为读取函数内部知道如何解密。 writeChars 和 writeBytes 方法写入的字符串,我们要想读取回来,就没这么幸运了,读者 可以借鉴作者在程序中注释掉的那段代码,运行后没有把我们写入的字符串打印出来,你就 能够明白我们要将 writeChars 和 writeBytes 方法写入的字符串正确读取回来,实在太很难 了,所以,io 包中专门提供了各种 Reader 和 Writer 类来操作字符串。 如果读者想仔细研究上面几个write方法写入的字符串在hello.txt文件中到底以何种 形式存在的,可以使用 UltraEdit 打开 hello.txt 文件,显示的内容如下: 图 7.5 通过 UltraEdit,我们看到了每个字节所对应的具体数值,所以,有经验的人士经常用 UltraEdit 来查看和研究二进制文件的内容信息。 7.4.4 PrintStream PrintStream 类提供了一系列的 print 和 println 方法,可以实现将基本数据类型的格 225 式化成字符串输出。在前面,我们在程序中大量用到“System.out.println”语句中的 System.out 就是 PrintStream 类的一个实例对象,读者已经多次使用到这个类了。 PrintStream 有 3 个构造函数: PrintStream(OutputStream out) PrintStream(OutputStream out,boolean auotflush) PrintStream(OutputStream out,boolean auotflush,String encoding) 其中 autoflush 控制在 Java 中遇到换行符(\n)时是否自动清空缓冲区,encoding 是指 定编码方式,关于编码方式,我们在本章后面部分有详细的讨论。 println 方法与 print 方法的区别是:前者会在打印完的内容后再多打印一个换行符 (\n),所以 println()等于 print("\n")。 Java 的 PrintStream 对象具有多个重载的 print 和 println 方法,它们可输出各种类 型(包括 Object)的数据。对于基本数据类型的数据,print 和 println 方法会先将它们转 换成字符串的形式后再输出,而不是输出原始的字节内容,如:整数 123 的打印结果是字符 ‘1’、‘2’、‘3’所组合成的一个字符串,而不是整数 123 在内存中的原始字节数据。对于 一个非基本数据类型的对象,print 和 println 方法会先调用对象的 toString 方法,然后 再输出 toString 方法返回的字符串。 IO 包中提供了一个与 PrintStream 对应的 PrintWriter 类,PrintWriter 即使遇到换行 符(\n)也不会自动清空缓冲区,只在设置了 autoflush 模式下使用了 println 方法后才自动 清空缓冲区。PrintWriter 相对 PrintStream 最有利的一个地方就是 println 方法的行为, 在 Windows 的文本换行是"\r\n",而 Linux 下的文本换行是"\n",如果我们希望程序能够生 成平台相关的文本换行,而不是在各种平台下都用"\n"作为文本换行,我们就应该使用 PrintWriter 的 println 方法时,PrintWriter 的 println 方法能根据不同的操作系统而生 成相应的换行符。 指点迷津: 格式化输出是指将一个数据用其字符串格式输出,如我们使用 print 方法把 97 这个整 数打印到一个文件中,该方法将把‘9’和‘7’这两个字符的 ASCII 码写入到文件中, 也就 是文件中会被写入两个字节,这两个字节中的数字分别为 57(十六进制的 0x39)和 55(十 六进制的 0x37),在记事本程序中显示为‘9’和‘7’这两个字符。如果我们使用 write 方 法把 97 这个整数写到一个文件中,只有一个字节会写入到这个文件中,字节中的数字就是 97,正好是字符‘a’的 ASCII 码,所以在记事本程序中显示为一个字符‘a’。 7.4.5 ObjectInputStream 与 ObjectOutputStream 这两个类是用于存储和读取对象的输入输出流类,不难想象,我们只要把对象中的所有 成员变量都存储起来,就等于保存了这个对象,我们只要读取到一个对象中原来保存的所有 成员变量的取值,就等于读取到了一个对象。ObjectInputStream 与 ObjectOutputStream 226 类,可以帮我们完成保存和读取对象成员变量取值的过程,但要读写或存储的对象必须实现 了 Serializable 接口,Serializable 接口中没有定义任何方法,仅仅被用作一种标记,以 被编译器作特殊处理。ObjectInputStream 与 ObjectOutputStream 类不会保存和读取对象 中的transient和static类型的成员变量,使用 ObjectInputStream与ObjectOutputStream 类保存和读取对象的机制叫序列化,如下面定义了一个可以被序列化的 MyClass 类: public class MyClass implements Serializable { public transient Thread t; private String customerID; private int total; } 在 MyClass 类的实例对象被序列化时,成员变量 t 不会被保存和读取。 序列化的好处在于:它可以将任何实现了 Serializable 接口的对象转换为连续的字节 数据,这些数据以后仍可被还原为原来的对象状态,即使这些数据通过网络传输也没问题。 序列化能处理不同操作系统上的差异,我们可以在 Windows 上产生某个对象,将它序列化存 储,然后通过网络传到 Linux 机器上,该对象仍然可以被正确重建出来,在这期间,我们完 全不用担心不同机器上的不同的数据表示方式。 下面我们就创建一个学生对象,并把它输出到一个文件(mytext.txt)中,然后再把该 对象读出来,将其还原后打印出来: 程序清单:Serializatioan.java import java.io.*; public class serialization { public static void main(String args[]) throws IOException,ClassNotFoundException { Student stu=new Student(19,"dintdding",50,"huaxue"); FileOutputStream fos=new FileOutputStream("mytext.txt"); ObjectOutputStream os=new ObjectOutputStream(fos); try { os.writeObject(stu); os.close(); }catch(IOException e) { System.out.println(e.getMessage()); } stu=null; FileInputStream fi=new FileInputStream("mytext.txt"); ObjectInputStream si=new ObjectInputStream(fi); try { stu=(Student)si.readObject(); 227 si.close(); }catch(IOException e) { System.out.println(e.getMessage()); } System.out.println("ID is:"+stu.id); System.out.println("name is:"+stu.name); System.out.println("age is:"+stu.age); System.out.println("department is:"+stu.department); } } class Student implements Serializable { int id; String name; int age; String department; public Student(int id,String name,int age,String department) { this.id=id; this.name=name; this.age=age; this.department=department; } } 运行结果: ID is:19 name is:dintdding age is:50 department is:huaxue 从运行结果上看,我们刚刚读出来并还原的内容和我们原来创建时是一样的。我们到底 写了些什么内容到mytext.txt文件中呢?我们用记事本程序打开mytext.txt文件时所看到 的内容如图 7.6 所示: 图 7.6 我们不用了解其中的详细细节,只要能够通过相应的方式正确地读取回来就足够了。 228 指点迷津: 一个学员曾经问过我,他们公司买了一套美国人的地理信息系统,这个系统将采集到的 地理数据存放在一个文件中,他有没有办法读取到这个文件中的内容?看来,他还没有完全 明白这些 IO 类能帮助我们做些什么。我告诉他,用我们的前面讲的 FileInputStream 类就 能够读取到这个文件中的所有字节的数据,只是我们不明白这些数据代表的是什么意思罢 了,也就是说我们不知道美国人存储数据的格式,读到了这些数据也是白读!只有开发那个 系统的美国人自己知道这些数据的意义,他们才能正确地使用文件中保存的数据。就象 ObjectOutputStream 保存的数据一样,是专门给 ObjectInputStream 来读取的,我们通过 别的方式读取到的数据毫无意义。 7.4.6 字节流与字符流的转换 前面我们讲过,Java 支持字节流和字符流,我们有时需要字节流和字符流之间的转换。 InputStreamReader 和 OutputStreamWriter 这两个类是字节流和字符流之间转换的类,InputStreamReader 可以将一个字节流中的 字节解码成字符,OuputStreamWriter 将写入的字符编码成字节后写入一个字节流。其中 InputStreamReader 有两个主要的构造函数: InputStreamReader(InputStream in) //用默认字符集创建一个 InputStreamReader 对象 InputStreamReader(InputStream in,String CharsetName) //接受以指定字符集名的字符串,并用 //该字符集创建对象 OutputStreamWriter 也有对应的两个主要的构造函数: OutputStreamWriter(OutputStream in) //用默认字符集创建一个 OutputStreamWriter 对象 OutputStreamWriter(OutputStream in,String CharsetName) //接受以指定字符集名的字符串, //并用该字符集创建 OutputStreamWriter 对象 为了达到最好的效率,避免频繁的字符与字节间的相互转换,我们最好不要直接使用这 两个类来进行读写,应尽量使用 BufferedWriter 类包装 OutputStreamWriter 类,用 BufferedReader 类包装 InputStreamReader。例如: BufferedWriter out=new BufferedWriter(newOutputStreamWriter(System.out)); BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); 我们接着从一个更实际的应用中来熟悉 InputStreamReader 的作用,怎样用一种简单的 方式一下就读取到键盘上输入的一整行字符?只要用下面的两行程序代码就可以解决这个 问题: BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); String strLine = in.readLine(); 229 我们不可能什么时候都提前掌握了正好可以解决我们问题的各个小知识点,作者在第一 次碰到这种需求时,就不知道可以用这种方式,但作者在以前从没有接触的情况下,也写出 了上面的代码。首先,要读取一行,我马上想到在 chm 格式的 JDK 文档中去查类似 readLine 这样的英文单词的拼写组合,查询的界面如图 7.7 所示: 图 7.7 我们找到了 BufferedReader 这个类,查看 BufferedReader 类的构造方法,如图 7.8 所示: 图 7.8 可见,构建 BufferedReader 对象时,必须传递一个 Reader 类型的对象作为参数,而键 盘对应的 System.in 是一个 InputStream 类型的对象,解决问题的关键是,我们还需要找到 将 InputStream 类型的流对象包装成 Reader 类型的包装类。作者眼尖(其实是作者读文档 的一个习惯,也可以说是作者查文档的一点小经验吧),就在 BufferedReader 的帮助界面中, 我看了如下的一段信息: See Also: FileReader, InputStreamReader 在这里,我看到了 InputStreamReader 这个关键的类,阅读其帮助后,最终写出了上面 230 的程序代码,轻松解决了我从未碰到过的问题。在查阅文档时,经常顺便看看 See Also 部 分也是很重要的,在那里往往都有解决相关问题的超链接。如果在 See Also 部分也没有提 及 InpustStreamReader,那我们只能去查 IO 包的帮助,浏览其中列出的每个类,也能发现 InpustStreamReader 这个类就是我们所要找的类的。 BufferedReader类可以读取一行文本,对应的BufferedWriter类也提供了一个newLine 方法来向字符流中写入不同操作系统下的换行符,如果我们要向字符流中写入与平台相关的 文本换行,就可以考虑使用 BufferedWriter 这个包装类了。 我们在前面用到的 FileWriter 和 FileReader 实际上都是包装类,FileReader 是 InputStreamReader 的子类,FileWriter 是 OutputStreamWriter 的子类。 7.4.7 IO 包中的类层次关系图 1. 字节输入流类: 图 7.9 2. 字节输出流类: 图 7.10 3. 字符输入流类: 231 图 7.11 4. 字符输出流类: 图 7.12 7.5 IO 中的高级应用 7.5.1 字符集的编码问题 计算机里只有数字,我们在计算机软件里的一切都是用数字来表示,屏幕上显示的一个 个字符也不例外,最初的计算机的使用是在美国,当时所用到的字符也就是我们现在键盘上 的一些符号和少数几个特殊的符号,每一个字符都用一个数字来表示,一个字节所能表示的 数字范围内足以容纳所有的这些字符,实际上表示这些字符的数字的字节最高位(bit) 都为 0,也就是说这些数字都在 0 到 127 之间,如字符 a 对应数字 97,字符 b 对应数字 98 等, 这种字符与数字对应的编码固定下来后,这套编码规则被称为 ASCII(美国标准信息交换 码)。 232 随着计算机逐渐在其他国家的应用和普及,许多国家都把本地的字符集引入了计算机, 大大扩展了计算机中字符的范围。一个字节所能表示的数字范围是不能容纳所有的中文汉字 的,中国大陆将每一个中文字符都用两个字节的数字来表示,原有的 ASCII 字符的编码保持 不变,仍用一个字节表示,为了将一个中文字符与两个 ASCII 码字符相区别,中文字符的每 个字节的最高位(bit) 都为 1,中国大陆为每一个中文字符都指定了一个对应的数字,并作 为标准的编码固定下来,这套编码规则称为 gbk(国标码),后来又在 gbk 的基础上对更多 的中文字符(包括繁体)进行了编码,新的编码系统就是 gb2312,可见 gbk 是 gb2312 的子 集。使用中文的国家和地区很多,同样的一个字符,如“中国”的“中”字,在中国大陆的 编码是十六进制的 D6D0,而在中国台湾的编码是十六进制的 A4A4,台湾地区对中文字符集的 编码规则称为 big5(大五码)。 在一个国家的本地化系统中出现的一个字符,通过电子邮件传送到另外一个国家的本地 化系统中,看到的就不是那个原始字符了,而是另外那个国家的一个字符或乱码,因为计算 机里面并没有真正的字符,字符都是以数字的形式存在的,我们通过邮件传送一个字符,实 际上传送的是这个字符对应的编码数字,同一个数字在不同的国家和地区代表的很可能是不 同的符号,如十六进制的 D6D0 在中国大陆的本地化系统中显示为“中”这个符号,但在伊 拉克的本地化系统就不知对应的是一个什么样的伊拉克字符了,反正人们看到的不是“中” 这个符号。随着世界各国的交往越来越密切,全球一体化的趋势越来越明显,人们不可能完 全忘记母语,都去使用英文在不同的国家和地区间交换越来越多的电子文档,特别是人们开 发的应用软件都希望能走出国门、走向世界,可见,使用各个国家和地区的本地化字符编码, 已经给我们的生活和工作带来了很多的不方便,严重制约了国家和地区间在计算机使用和技 术方面的交流。 为了解决各个国家和地区使用本地化字符编码带来的不利影响,人们将全世界所有的符 号进行了统一编码,称之为 unicode 编码,所有字符不再区分国家和地区,都是人类共有的 符号,如“中国”的“中”这个符号,在全世界的任何角落始终对应的都是一个十六进制的 数字 4e2d,如果所有的计算机系统都使用这种编码方式,在中国大陆的本地化系统中显示 的“中”这个符号,发送到伊拉克的本地化系统中,显示的仍然是“中”这个符号,至于那 个伊拉克能不能认识这个符号,就不是我们计算机所要解决的问题了。Unicode 编码的字符 都占用两个字节的大小,也就是说全世界所有的字符个数不会超过 2 的 16 次方(65536),我 想一定是 unicode 编码中没有包括诸如中国的藏文和满文这些少数民族的文字。 长期养成的保守习惯不可能一下子就改变过来,特别是不可能完全推翻那些已经存在的 运行良好的系统,新开发的软件要做到瞻前顾后,既能够在存在的系统上运行,又便于以后 的战略扩张和适应新的形式。unicode 一统天下的局面暂时还难以形成,在相当长的一段时 期内,人们看到的都是本地化字符编码与 unicode 编码共存的景象。既然本地化字符编码与 unicode 编码共存,那就少不了涉及两者之间的转化问题,在 Java 中的字符使用的都是 unicode 编码,Java 技术在通过 Unicode 保证跨平台特性的前提下也支持了全扩展的本地平 台字符集,而我们显示输出和键盘输入都是采用的本地编码。 作者在上面的讲解中,写出了“中国”的“中”字在 gbk,big5,unicode 编码中分别对 应的数字,读者是否对此感到奇怪过,是作者记忆力超群吗?非也!作者就是通过下面的实 验而得到的这几个数字并借此帮助读者完全理解字符编码的问题。 步骤 1,在 UtralEdit 中,输入“中国”,再按下工具栏上的“H”样的按钮,用十六进 制方式查看“中国”这两个字符在本地系统编码中所对应的字节数字,如图 7.13 所示: 233 图 7.13 步骤 2,编写并运行下面的程序代码 public class CharCode { public static void main(String [] args) throws Exception { String strChina = "中国"; for(int i=0;i
还剩43页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 6 人已下载

下载pdf

pdf贡献者

lpaisgm

贡献于2012-08-15

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf