Java中正确使用RandomAccessFile向文件中写入中文

Java中正确使用RandomAccessFile向文件中写入中文

最近有一个客户询问使用Java中的RandomAccessFile不能向文件中正确写入中文,出来的都是乱码。经过分析和验证后,发现的问题的原因和解决办法。下面将主要的回复内容贴出来和大家分享: -------------------------------------------------------------------------------         先将您昨天上午描述的问题总结如下:         使用RandomAccessFile向数据库写入中文的时候,         *使用write(String.getBytes()), 能够正常写入         *使用writeBytes(String), writeChars(String), writeUTF(String)均产生乱码。                 如果我对您的问题理解正确的话,经过分析,我认为如果您是使用RandomAccessFile来 访问数据库的话,为了正确写入中文,您最好使用write(String.getBytes())的方式。这主要有如下两方面的原因: 1、当java运行时,实际上存在两种字符编码方式。nativecode编码和unicode编码。     * 文件被操作系统保存时,都是以nativecode的编码方式保存的。这也是我们有时候在浏览器或电子邮件客户端软件中看到乱码后,改变浏览器或电子邮件客户端软件的编码设置(例如:GB2312,GB18030或者是BIG5)就可以正确的显示。         * 在JAVA程序内部,字符串都是以UNICODE的方式来表示的。     Java的内核是unicode的,其class文件也是这样的。另外在java代码中,string中的char是用unicode编码方式来表示的,string的bytes是用相应的nativecode编码方式来表示的。     由于RandomAccessFile是同native file来打交道,所以必然存在一个nativecode和unicode的转化过程。 2、RandomAccessFile的文件写入方式。 在RandomAccessFile的Javadoc中,对于各种文件写入方式有不同的定义。     * public void write(byte[] b):Writes b.length bytes from the specified byte array to this file, starting at the current file pointer.         * public final void writeBytes(String s) throws IOException     Writes the string to the file as a sequence of bytes. Each character in the string is written out, in sequence, by discarding its high eight bits. The write starts at the current position of the file pointer.(请注意每个字符的高8位都会被抛弃掉。)             * public final void writeChar(int v) throws IOException     Writes a char to the file as a two-byte value, high byte first. The write starts at the current position of the file pointer.(采用的是Big-endian的存储方式,注意由于x86架构的限制,Windows默认采用Little-endian)         * public final void writeChars(String s) throws IOException     Writes a string to the file as a sequence of characters. Each character is written to the data output stream as if by the writeChar method. The write starts at the current position of the file pointer.(注意writeChars采用的是writeChar的写入方式。)         * public final void writeUTF(String str) throws IOException     Writes a string to the file using modified UTF-8 encoding in a machine-independent manner.     First, two bytes are written to the file, starting at the current file pointer, as if by the writeShort method giving the number of bytes to follow. This value is the number of bytes actually written out, not the length of the string. Following the length, each character of the string is output, in sequence, using the modified UTF-8 encoding for each character. (注意writeUTF会首先写入两个字节,表示其后实际写入的字节数,然后才是对应字符串的UTF-8编码。)     下面是我编写的一段测试代码,供您参考。 -------------------------------------------------------------------------------- /* * RandomAFTest.java * * Created on 2005年5月8日, 下午3:38 * */ import java.io.*; /** * * @author Paul */ public class RandomAFTest {         //按照指定的charset,将字符串转换为bytes,并打印出来     public static void printBytes(String str, String charsetName) {         try {             byte strBytes[] = str.getBytes(charsetName);             String strBytesContent = "";             for (int i = 0; i < strBytes.length; i++) {                 strBytesContent = strBytesContent.concat(Integer.                         toHexString(strBytes ) + ",");             }             System.out.println("The Bytes of String " + str +                     " within charset " + charsetName + " are: " +                     strBytesContent);         } catch (UnsupportedEncodingException e) {             //Not handle;         }     }         //将字符串的chars打印出来     public static void printChars(String str) {         int strlen = str.length();         char strChars[] = new char[strlen];         str.getChars(0, strlen, strChars, 0);         String strCharsContent = "";         for (int i = 0; i < strlen; i++) {             strCharsContent = strCharsContent.concat(Integer.                     toHexString(strChars) + ",");         }         System.out.println("The chars of String " + str + " are: " +         strCharsContent);     }         public static void main(String args[]) {         try {             RandomAccessFile rfWrite =                     new RandomAccessFile("c://testWrite.dat", "rw");             RandomAccessFile rfWriteBytes =                     new RandomAccessFile("c://testWriteBytes.dat", "rw");             RandomAccessFile rfWriteChars =                     new RandomAccessFile("c://testWriteChars.dat", "rw");             RandomAccessFile rfWriteUTF =                     new RandomAccessFile("c://testWriteUTF.dat", "rw");                          String chStr = "中";             //打印字符串在GB2312下的bytes             printBytes(chStr, "GB2312");             //打印字符串在UTF-8下的bytes             printBytes(chStr, "UTF-8");             //打印字符串的UNICODE的chars             printChars(chStr);             try {                 rfWrite.write(chStr.getBytes());                 rfWrite.close();                 System.out.println("Done write!");                 rfWriteBytes.writeBytes(chStr);                 rfWriteBytes.close();                 System.out.println("Done writeBytes!");                 rfWriteChars.writeChars(chStr);                 rfWriteChars.close();                 System.out.println("Done writeChars!");                 rfWriteUTF.writeUTF(chStr);                 rfWriteUTF.close();                 System.out.println("Done writeUTF!");             } catch (IOException e) {                 // Do not handle the IOException             }         } catch (FileNotFoundException e) {             //Do not handle         }              } } --------------------------------------------------------------------------- 以下是该程序的部分运行结果: The Bytes of String 中 within charset GB2312 are: ffffffd6,ffffffd0, The Bytes of String 中 within charset UTF-8 are: ffffffe4,ffffffb8,ffffffad, The chars of String 中 are: 4e2d, 我们可以看到"中"的     * GB2312编码为D6 D0     * UTF-8编码为 E4 B8 AD     * UNICODE编码为 4E 2D 那么实际写入的文件是什么样的呢,下面给出各个文件内容的16进制描述: 文件testWrite.dat: D6 D0 文件testWriteBytes.dat: 2D 文件testWriteChars.dat: 4E 2D 文件testWriteUTF.dat: 00 03 E4 B8 AD 结合我们上述的1和2,我们不难看出: 1、String.getBytes()将会按照当前系统默认的encoding方式获得字符串的Bytes,RandomAccessFile.write(byte[])将这个byte数组正确写入。由于写入的实际就是Windows平台的nativecode编码,所以文件还能够被正确的阅读。 2、RandomAccessFile.writeBytes(String)将字符串的各个字符(当然是用unicode编码的)的高8位去掉,写入文件。 3、RandomAccessFile.writeChars(String)将字符串的各个字符按照unicode的编码,以Big-endian的方式写入文件。Windows平台上默认文件的编码方式为Little-endian,所以用写字板打开看到的是乱码,但是如果我们用浏览器打开这个文件(testWriteChars.dat)并指定编码方式为Unicode Big-endian,就能看到正常的“中”字了。 4、RandomAccessFile.writeUTF(String)首先写入00 03表示其后将写入3个实际的字节,然后写入“中”的UTF-8编码:E4 B8 AD 通过上面的分析,我建议如果使用RandomAccessFile来写入中文的话,最好用RandomAccessFile.write(String.getBytes())的方式,如果为了保险起见,还可以进一步指定运行平台的默认nativecode编码方式,例如使用:RandomAccessFile.write(String.getBytes("gb2312"))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值