Java中IO的四大抽象类
InputStream/OutputStream和Reader/writer类是所有IO流类的抽 象父类,我们有必要简单了解一下这个四个抽象类的作用。然后, 通过它们具体的子类熟悉相关的用法。
InputStream
此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽 象类,它不可以实例化。 数据的读取需要由它的子类来实现。根据 节点的不同,它派生了不同的节点流子类 。 继承自InputSteam的流都是用于向程序中输入数据,且数据的单位 为字节(8 bit)。
常用方法:
OutputStream
此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节 并将这些字节发送到某个目的地。
常用方法:
Reader
Reader用于读取的字符流抽象类,数据单位为字符。
Writer
Writer用于输出的字符流抽象类,数据单位为字符。
常用流详解
文件字节流
FileInputStream 通过字节的方式读取文件,适合读取所有类型的文 件(图像、视频、文本文件等)。
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型 的文件(图像、视频、文本文件等)。
FileInputStream文件输入字节流
public class TestFileInputStream { public static void main(String[] args) { //使用try-with-resource方式关闭资源。 //在try中打开资源,不需要在代码中添加finally块关闭资源。 try(FileInputStream fis = new FileInputStream("d:/a.txt");){ StringBuilder sb = new StringBuilder(); int temp=0; while((temp = fis.read()) != -1) { sb.append((char) temp); } System.out.println(sb); }catch(Exception e){ e.printStackTrace(); } }
FileOutputStream文件输出字节流
public class TestFileOutputStream { public static void main(String[] args) { String str = "Old Lu"; // true表示内容会追加到文件末尾;false表示重写整个文件内容。 try(FileOutputStream fos = new FileOutputStream("d:/a.txt",true)){ //将整个字节数组写入到文件中。 fos.write(str.getBytes()); //将数据从内存中写入到磁盘中。 fos.flush(); }catch (IOException e){ e.printStackTrace(); } } }
通过字节缓冲区提高读写效率
通过创建一个指定长度的字节数组作为缓冲区,以此来提高IO流的 读写效率。该方式适用于读取较大文件时的缓冲区定义。注意:缓 冲区的长度一定是2的整数幂。一般情况下1024长度较为合适。
public class TestFileByteBuffer{ public static void main(String[] args) { long time1 = System.currentTimeMillis(); copyFile("d:/1.jpg", "d:/2.jpg"); long time2 = System.currentTimeMillis(); System.out.println(time2 - time1); } /** * * @param src 源文件 * @param desc 目标文件 */ public static void copyFile(String src,String desc){ //“后开的先关闭!”按照他们被创建顺序的逆序来关闭 try(FileInputStream fis = new FileInputStream(src); FileOutputStream fos = new FileOutputStream(desc)){ //创建一个缓冲区,提高读写效率 byte[] buffer = new byte[1024]; int temp = 0; while ((temp = fis.read(buffer)) != -1){ //将缓存数组中的数据写入文件中,注意:写入的是读取的真实长度; fos.write(buffer,0,temp); } //将数据从内存中写入到磁盘中。 fos.flush(); } catch (IOException e) { e.printStackTrace(); } } }
注意 在使用字节缓冲区时,我们需要注意:
1、为了减少对硬盘的读写次数,提高效率,通常设置缓存数组。相应地,读取时使用的方法 为:read(byte[] b);写入时的方法为:write(byte[ ] b, int off, int length)
2、程序中如果遇到多个流,每个流都要单独关闭,防止其中一个流出现异常后导致其他流无法 关闭的情况。
缓冲字节流
Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流 (节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的 流包装起来一样,因此缓冲流是一种处理流(包装流)。 BufferedInputStream和BufferedOutputStream这两个流是缓冲 字节流,通过内部缓存数组来提高操作流的效率。
使用缓冲流实现文件的高效率复制
下面我们通过两种方式(普通文件字节流与缓冲文件字节流)实现 一个文件的复制,来体会一下缓冲流的好处。
public class TestFileBufferStream { public static void main(String[] args) { long time1 = System.currentTimeMillis(); copyFile("d:/1.jpg","d:/2.jpg"); long time2 = System.currentTimeMillis(); System.out.println(time2 - time1); } public static void copyFile(String source,String destination){ //实例化节点流 try(FileInputStream fis = new FileInputStream(source); FileOutputStream fos = new FileOutputStream(destination); //实例化处理流 BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos)){ int temp = 0; while ((temp = bis.read()) !=-1){ bos.write(temp); } bos.flush(); }catch(IOException e){ e.printStackTrace(); } } }
注意
1、在关闭流时,应该先关闭最外层的包装流,即“后开的先关闭”。
2、缓存区的大小默认是8192字节,也可以使用其它的构造方法自己指定大小。
文件字符流
前面介绍的文件字节流可以处理所有的文件,如果我们处理的是文 本文件,也可以使用文件字符流,它以字符为单位进行操作。
文件字符输入流
public class TestFileReader { public static void main(String[] args) { //创建文件字符输入流对象 try(FileReader fr = new FileReader("d:/a.txt")){ StringBuilder sb = new StringBuilder(); //读取文件 int temp = 0; while((temp = fr.read()) != -1){ sb.append((char)temp); } System.out.println(sb); }catch (IOException e){ e.printStackTrace(); } } }
文件字符输出流
public class TestFileWriter { public static void main(String[] args) { //创建文件字符输出流对象 try(FileWriter fw = new FileWriter("d:/aa.txt")){ fw.write("您好尚\r\n"); fw.write("您好Old Lu\r\n"); fw.flush(); }catch (IOException e){ e.printStackTrace(); } } }
缓冲字符流
BufferedReader/BufferedWriter增加了缓存机制,大大提高了读 写文本文件的效率。
字符输入缓冲流
BufferedReader是针对字符输入流的缓冲流对象,提供了更方便的 按行读取的方法:readLine(); 在使用字符流读取文本文件时,我们 可以使用该方法以行为单位进行读取。
public class TestBufferedReader { public static void main(String[] args) { //创建文件字符输入流对象 try(FileReader fr = new FileReader("d:/aa.txt"); //创建字符缓冲处理流。缓冲区默认大小为8192个字符。 BufferedReader br = new BufferedReader(fr)){ //操作流 String temp = ""; //readLine():读取一行文本。 while((temp = br.readLine()) != null){ System.out.println(temp); } }catch(IOException e){ e.printStackTrace(); } } }
字符输出缓冲流
BufferedWriter是针对字符输出流的缓冲流对象,在字符输出缓冲 流中可以使用newLine();方法实现换行处理。
public class TestBufferedWriter { public static void main(String[] args) { //创建文件字符输出流对象 try(FileWriter fw = new FileWriter("d:/sxt.txt"); //创建字符输出缓冲流对象 BufferedWriter bw = new BufferedWriter(fw)){ //操作缓冲流 bw.write("您好尚像素"); bw.write("您好Oldlu"); //换行 bw.newLine(); bw.write("何以解忧"); bw.newLine(); bw.write("唯有学堂"); bw.flush(); }catch (IOException e){ e.printStackTrace(); } } }
注意
readLine()方法是BufferedReader的方法,可以对文本文件进行更加方便的读取操作。 newLine()方法BufferedWriter的方法,可以使用newLine()方法换行。
为文件中的内容添加行号
public class TestLineNumber { public static void main(String[] args) { //创建字符输入缓冲流与文件字符输入流 try(BufferedReader br = new BufferedReader(new FileReader("d:/sxt.txt")); //创建字符输出缓冲流与文件字符输出流 BufferedWriter bw = new BufferedWriter(new FileWriter("d:/sxt2.txt"))){ String temp =""; //定义序号变量 int i = 1; while((temp = br.readLine()) != null){ //将读取到的内容添加序号,并输出到指定文件中。 bw.write(i+","+temp); //换行处理 bw.newLine(); //序号变量累加 i++; } //刷新 bw.flush(); }catch(IOException e){ e.printStackTrace(); } } }