1、首先说一下出现的过程,代码如下,定义文件输入流和输出流,读取testFile1文件,并将读取到的数据,输出到控制台和本地D盘中testFile2文件中。
2、在控制它结果输出的是一串数字。但是文件中的确实正常的结果,难道os.write(b);不是按照int存储的,而是做了什么操作。
3、接着看FileOutputStream源码,发现其调用的是FileOutputStream的public void write(int b),然后此方法又调用了FileOutputStream类中的本地方法private native void write(int b, boolean append);注释没什么可看的,到这里并不能看出什么端倪。
4、但是我打开了OutputStream抽象类,FileOutputStream实现了此抽象类,并且public void write(int b)是重写了OutputStream的方法:public abstract void write(int b) 。看OutputStream类中的这个方法的注释:给输出流写特别的字节,write方法一般的约定是给输出流写一个字节。而写的这个字节是整形变量b的低8位字节,高24位字节会被忽略掉。最后一句很重要,子类必须提供一个此方法的实现。看到这里很是欣慰,终于找到原因了,因为在底层的native方法中,write会自动把高的24位去掉,(因为高24位本来就是无效的,全是0)这样文件中的数据是没有问题的。再回到上文的输出数字的问题,我是不是可以在read()的时候自己处理一下,也把高24位过滤掉,这样是不是就会正常显示了?
5、所以重新写一段程序,把拿到int数据,转成byte或者char试一下。
6、结果是转成char可以正确输出(因为对于英文字符来说,通过ascall码表可以知道,是用十进制的0-127表示的,所以直接转成char就可以得到正确的字符了),byte则是对应的十进制数,我们把int转成byte的意思也就是取int中这个字符的有效位。
7、如果文件中是一个中文"夏",还用这种读取一个字节的方法,会出现什么情况。发现输出了三个不认识的码,首先ecplise中设置的默认编码格式是utf-8, 在utf-8中,汉字是占用了三个字节,使用read方法正好接收了三个字节的数据,很显然计算机是把汉字“夏”,拆成三个字节进行传输的。对于拆开的三个字节,计算机很难认识,如果把这三个字节拼在一起是不是就是“夏”字了。
8、定义一个字节数组,长度是三,每次读取时,将其存储到字节数组中,然后把此字节数组通过new String(byte[])转换成字符,发现真的是“夏”字。上面还有一个比较有意思的是,这三组数据两两加在一起都是256(143+113)。143(int型)的元码是0000(24个0)10001111,-113(byte型)的元码是11110001,并且-113的补码就是143对应的低八位。这个现象说明了一个问题,本来以为int转成byte应该就是直接存其低八位,其实是存的其低八位的补码(第八位是符号位)。这是不是也说明其实所有的字符都是存储的补码呀?,,,
9、FileOutputStream中还有一个read(byte[] b);每次读取多个字节。我们也可以弋讥孜求使用此方法,循环的读取字节流中的数据。所以对于字节流的操作我们要注意,字符的编码,如果是英文则一个字节就可以将其转换成正确的字符,如果是汉字,则需要连续的三个字节的数据,才能解析成一个准确的汉字(utf-8)。如果文件流中全是中文的字符,则可以用一个3的倍数的字节数组b去循环的接收,然后使用newString转换成汉字字符。如果全是英文的字符,则可以随便定义字节数组大小,然后转成字符。如果文件流中既包含中文字符也包含英文字符,字节数组的大小真不好确定,此时建议使用字符流按行读取文件。