Java-输入输出流的简单看法与总结
Java-输入输出流的简单看法与总结
为什么Java中关于输入输出流(IO流)的对象为什么这么多,实在难以记忆,这可能是绝大多数人在学习关于Java此内容的问题,下面就来总结一下这个知识点,让这个困难得到解决。
一、理解Java的IO模型和框架
实际上对于Java输入输出流的所有概念在下图中就已经完整地体现了:
还有不得不提一下Java的IO框架:
弄明白上面两张图,你就可以说已经理解了Java的IO模型。
首先,需要理解IO流的各个类是用来做什么的。比方说:InputStreamReader 类可以用来做什么,有什么用途?可能这个问题难道你了,因为这个类既包括字节流,也囊括了字符流,到底是哪一个流?
有一个规律:
- 末尾的单词决定其是哪一类IO流,所以在此例中,这为字符流;
- 开始的单词决定的输入的流类型,或者目的地流类型;
- Reader是基于字符的输入操作流,InputStream是基于字节的输入操作流
- Writer是基于字符的输出操作流,OutputStream是基于字节的输出操作流
- 输出/输出流的分类意味着这个类具有输出/读取的功能方法,而不以为这流本身会主动执行这些方法
有些既可以是源,也可以是目的地,比如说File,因为我们既可以从文件中读取内容,也可以向文件中写入内容,所以File既可以与InputStream组合,也可以和OutputStream组合;
有些则只能是目的地,或源,比如说InputStream只能和Reader组合,而没有OutputStreamReader的组合。
综上所述,InputStreamReader类使用来读取字节流数据,得到字符数据来供我对字符流数据进行操作的类,所以这也要求了InputStreamReader类中的大多数方法是基于字符的操作。
注意事项:不要错认为IO流操作过程中只有输出流会对数据进行转换,比如说字节流转为硬盘文件存储起来,输入流同样有转换数据的功能。
除了用于缓冲作用的流,输入流可以一下方式理解:
输出流可以这么理解:
对于缓冲IO流的理解:其也是个流对象,不过被称为装饰类流,这主要是通过其对输入/出流对象装饰后,我们不再直接调用输入/出流的读写方法,而是调用它缓冲IO流的读写方法。但是这个理解还是不够到位。所有流对象也是位于内存中的,但是缓冲IO流对象还是一个实管理内存的工具,所以可以凭借此类来和内存直接打交道,优化内存管理,而直接使用输入输出流则没有此功能。
二、活学活用
注意事项:下面的例子没有进行异常处理以及流的关闭操作,实际上不够科学,但是这里不是重点,省略了。
- 将一个字符串转为文档储存起来:
面对这样一个例子,我们应当怎么做呢?
我们是否需要一个输出流对象以及一个输出流对象呢?
其实是不需要的,因为输入流的作用是读取数据至内存(或者特殊的内存块:缓冲IO流),既然String对象以及位于内存中了,不需要输入流对象,只需要输出流对象即可。输出流的前缀很容易判断:因为我们生成一个文件,所以此前缀为File,输出流的后缀不妨先设置为OutputStream
,我们打算对其进行字节流的操作,所以调用了一下的方法:
byte[] bytes = str.getBytes();
,因为要求输出流的构造参数需要为为字节类型的数据。
注意事项:根据需要确定是否需要输入流以及输出流。
/**
* @author Fisherman
*/
public class MyTry {
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("Mystr.txt");
byte[] bytes = str.getBytes();
FileOutputStream fileOutputStream = new FileOutputStream("Mystr.txt");
fileOutputStream.write(bytes);
fileOutputStream.close();
}
}
问题实际上就是确定2个前缀以及两个后缀,输出流的前缀很容易判断:因为我们生成一个文件,所以此前缀为File。输入流的后缀和输出流的前缀恰好是流的两端,一定要一致,这里先选择OutputStream
,
当然我们也可以采用字符流的操作来进行,如下代码块:
/**
* @author Fisherman
*/
public class MyTry {
public static void main(String[] args) throws IOException {
String str="hello world i am fisherman!!!!!1233";
char[] chars =str.toCharArray();
FileWriter fileWriter = new FileWriter("Mystr.txt");
fileWriter.write(chars);
fileWriter.close();
}
}
注意事项:这里不要遗漏掉fileWriter的close方法,否则会造成文件写出失败。
- 将一个文件复制到另一个文件
对于文件的相关操作,推荐使用字节流,并且可以采用缓冲IO流进行包装:
无缓冲IO流的文件复制代码块:
这里是两个文件的输入和输出,以及都是使用字节流,所以显然IO流对象采用的是:FileInputStream以及FileOutputStream。
/**
* @author Fisherman
*/
public class CopyFIle {
public static void main(String[] args) throws IOException {
File inFile = new File("1.txt");
File outFile = new File("2.txt");
FileInputStream fins = new FileInputStream(inFile);
FileOutputStream fouts = new FileOutputStream(outFile);
int c ;
while (((c = fins.read()) != -1)) {
fouts.write(c);
}
fins.close();
fouts.close();
}
}
由上面的代码我们可见其效率是比较低的,因为我们每次调用方法:fins.read()
只能读取一个字节,然而频繁地访问硬盘上的资源是一个效率比较低的做法,所以需要使用缓冲IO流来对其进行装饰。
使用缓冲IO流进行装饰的代码块:
import java.io.*;
/**
* @author Fisherman
*/
public class CopyFIle_Buffered {
public static void main(String[] args) throws IOException {
File inFile = new File("1.txt");
File outFile = new File("2.txt");
FileInputStream fins = new FileInputStream(inFile);
FileOutputStream fouts = new FileOutputStream(outFile);
BufferedInputStream bif = new BufferedInputStream(fins);
BufferedOutputStream bof = new BufferedOutputStream(fouts);
byte[] bytes = new byte[1024];//每次读取的最大数据量为1kb
int length;
while ((length = bif.read(bytes,0,1024))!=-1){
bof.write(bytes,0,length);
}
bif.close();
bof.close();
}
}
三、总结
Java的IO流操作实际上理解起来很容易,就简单确定输入、输出流的前缀以及后缀,前缀决定的是输入、输出类型,后缀决定read/write方法的参数类型。缓冲IO流我们大可将其视作一块具有能够优化数据所占内存空间大小的“智能”的内存。输出输出流的选择完全可以依靠本文所提到的两张图来完成选择。
上一篇: I/O流
下一篇: Android 文件选择器详解及实例代码
推荐阅读