详解JAVA 字节流和字符流
1、InputStream和Reader
InputStream和Reader是所有输入流的抽象基类,本身并不能创建实例来执行输入,但它们将成为所有输入流的模板,所以它们的方法是所有输入流都可使用的方法。
在InputStream里包含如下三个方法。
- intread():从输入流中读取单个字节,返回所读取的字节数据(字节数据可直接转换为int类型)。
- intread(byte[]b):从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数。
- intread(byte[]b,intoff,intlen):从输入流中最多读取len个字节的数据,并将其存储在数组b中,放入数组b中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字节数。
在Reader里包含如下三个方法。
- intread():从输入流中读取单个字符,返回所读取的字符数据(字符数据可直接转换为int类型)。
- intread(char[]cbuf):从输入流中最多读取cbuf.length个字符的数据,并将其存储在字符数组cbuf中,返回实际读取的字符数。
- intread(char[]chuf,intoff,intlen):从输入流中最多读取len个字符的数据,并将其存储在字符数组cbuf中,放入数组cbuf中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数。
对比InputStream和Reader所提供的方法,就不难发现这两个基类的功能基本是一样的。
正如前面提到的,InputStream和Reader都是抽象类,本身不能创建实例,但它们分别有一个用于读取文件的输入流:FileInputStream和FileReader,它们都是节点流一一会直接和指定文件关联。
下面程序示范了使用FileInputStream来读取自身的效果。
publicclassFileInputStreamTest{ publicstaticvoidmain(String[]args)throwsIOException{ //创建字节输入流 FileInputStreamfis=newFileInputStream("F:\\eclipse-workspace\\demo\\src\\com\\jwen\\demo15_3\\FileInputStreamTest.java"); //创建一个长度为1024的“竹筒” byte[]bbuf=newbyte[1024]; //用于保存实际读取的字节数 inthasRead=0; //使用循环来重复“取水”过程 while((hasRead=fis.read(bbuf))>0){ //取出“竹筒”中水滴(字节),将字节数组转换成字符串输入! System.out.print(newString(bbuf,0,hasRead)); } //关闭文件输入流,放在finally块里更安全 fis.close(); } }
上面程序中的粗体字代码是使用FileInputStream循环“取水”的过程,运行上面程序,将会输出上面程序的源代码。
注意:上面程序创建了一个长度为1024的字节数组来读取该文件,实际上该Java源文件的长度还不到1024字节,也就是说,程序只需要执行一次read()方法即可读取全部内容。但如果创建较小长度的字节数组,程序运行时在输出中文注释时就可能出现乱码一一这是因为本文件保存时采用的是GBK编码方式,在这种方式下,每个中文字符占2字节,如果read()方法读取时只读到了半个中文字符,这将导致乱码。
上面程序最后使用了fis.close()来关闭该文件输入流,与JDBC编程一样,程序里打开的文件IO资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件资源。Java7改写了所有的IO资源类,它们都实现了AutoCloseable接口,因此都可通过自动关闭资源的try语句来关闭这些IO流。下面程序使用FileReader来读取文件本身。
publicclassFileReaderTest{ publicstaticvoidmain(String[]args){ try( //创建字符输入流 FileReaderfr=newFileReader("F:\\eclipse-workspace\\demo\\src\\com\\jwen\\demo15_3\\FileReaderTest.java")){ //创建一个长度为32的“竹筒” char[]cbuf=newchar[32]; //用于保存实际读取的字符数 inthasRead=0; //使用循环来重复“取水”过程 while((hasRead=fr.read(cbuf))>0){ //取出“竹筒”中水滴(字符),将字符数组转换成字符串输入! System.out.print(newString(cbuf,0,hasRead)); } }catch(IOExceptionex){ ex.printStackTrace(); } } }
上面的FileReaderTest.java程序与前面的FileInputStreamTest.java并没有太大的不同,程序只是将字符数组的长度改为32,这意味着程序需要多次调用read()方法才可以完全读取输入流的全部数据。程序最后使用了自动关闭资源的try语句来关闭文件输入流,这样可以保证输入流一定会被关闭。
除此之外,InputStream和Reader还支持如下几个方法来移动记录指针。
- voidmark(intreadAheadLimit):在记录指针当前位置记录一个标记(mark).
- booleanmarkSupported():判断此输入流是否支持mark()操作,即是否支持记录标记。
- voidreset():将此流的记录指针重新定位到上一次记录标记(mark)的位置。
- longskip(longn):记录指针向前移动个字节/字符。
2、OutputStream和Writer
OutputStream和Writer也非常相似,两个流都提供了如下三个方法。
- voidwrite(intc):将指定的字节/字符输出到输出流中,其中c既可以代表字节,也可以代表字符。
- voidwrite(byte[]/char[]buf):将字节数组/字符数组中的数据输出到指定输出流中。
- voidwrite(byte[]/char[]buf,intoff,intlen):将字节数组/字符数组中从off位置开始,长度为len的字节/字符输出到输出流中。
因为字符流直接以字符作为操作单位,所以Writer可以用字符串来代替字符数组,即以String对象作为参数。Writer里还包含如下两个方法。
- voidwrite(Stringstr):将字符串里包含的字符输出到指定输出流中。
- voidwrite(Stringstr,intoff,intlen):将字符串里从off位置开始,长度为len的字符输出到指定输出流中。
下面程序使用FileInputStream来执行输入,并使用FileOutputStream来执行输出,用以实现复制FileOutputStreamTest.java文件的功能。
publicclassFileOutputStreamTest{ publicstaticvoidmain(String[]args){ try( //创建字节输入流 FileInputStreamfis=newFileInputStream("FileOutputStreamTest.java"); //创建字节输出流 FileOutputStreamfos=newFileOutputStream("newFile.txt")){ byte[]bbuf=newbyte[32]; inthasRead=0; //循环从输入流中取出数据 while((hasRead=fis.read(bbuf))>0){ //每读取一次,即写入文件输出流,读了多少,就写多少。 fos.write(bbuf,0,hasRead); } }catch(IOExceptionioe){ ioe.printStackTrace(); } } }
运行上面程序,将看到系统当前路径下多了一个文件:newFile.txt,该文件的内容和FileOutputStreamTest.java文件的内容完全相同。
注意:使用Java的IO流执行输出时,不要忘记关闭输出流,关闭输出流除可以保证流的物理资源被回收之外,可能还可以将输出流缓冲区中的数据flush到物理节点里(因为在执行close()方法之前,自动执行输出流的flush()方法)。Java的很多输出流默认都提供了缓冲功能,其实没有必要刻意去记忆哪些流有缓冲功能、哪些流没有,只要正常关闭所有的输出流即可保证程序正常。
如果希望直接输出字符串内容,则使用Writer会有更好的效果,如下程序所示。
publicclassFileWriterTest{ publicstaticvoidmain(String[]args){ try(FileWriterfw=newFileWriter("poem.txt")){ fw.write("锦瑟-李商隐\r\n"); fw.write("锦瑟无端五十弦,一弦一柱思华年。\r\n"); fw.write("庄生晓梦迷蝴蝶,望帝春心托杜鹃。\r\n"); fw.write("沧海月明珠有泪,蓝田日暖玉生烟。\r\n"); fw.write("此情可待成追忆,只是当时已惘然。\r\n"); }catch(IOExceptionioe){ ioe.printStackTrace(); } } }
运行上面程序,将会在当前目录下输出一个poem.txt文件,文件内容就是程序中输出的内容。
注意:上面程序在输出字符串内容时,字符串内容的最后是\r\n,这是Windows平台的换行符,通过这种方式就可以让输出内容换行;如果是UNIX/Linux/BSD等平台,则使用\n就作为换行符。
以上就是详解JAVA字节流和字符流的详细内容,更多关于JAVA字节流和字符流的资料请关注毛票票其它相关文章!