我们频繁地要在不同设备之间传输数据,Java提供一系列的对象对数据传输进行描述与操作,这些被称为流的对象位于java.io包中。
流的分类
按流向可分为:输入流和输出流;
按传输单位可分为:字节流和字符流。
流的选择
流对象的使用还是挺直观便捷的,只要将数据源或者目的传入流对象的构造方法便完成了数据源(或者目的)与流对象的关联,之后就可以通过操作流对象读取数据源和目的了。读取完数据之后调用一个close()方法就断开了流对象与数据源的关联。就单个的流对象而言,事情就是这么简单。但是简单的事情多了以后,就不是那么回事了。考虑我们是如何用简单的分支语句和循环语句编写出复杂的代码的。学习IO流的困难不在于流对象的使用,而在于如何在繁多的流对象中选择合适的一个或几个对象来解决我们遇到的情况。
如果我们事先明确,在数据出出入入、读读写写的过程中,是以内存为参考点的,那就可以避免被数据的流向弄昏头脑。输入意味着数据流入内存,输出则意味着数据从内存流出,读是将数据读入内存,写是将数据从内存写出去。
我绘制了2张图来帮助自己理顺流对象之间的关系:(箭头代表数据流向)
首先应该关注那些可以与存储介质直接关联的流对象(在黑框中),因为只要涉及IO的操作,就一定会用上一个或几个这些对象。最常用的其实只有7个:FileInputStream与FileOutputStream、System.in与System.out、FileReader与FileWriter、PrintWriter;
完成了与存储介质的关联之后,这时已经可以将数据输入或输出了,但通常我们会根据需要选择装饰流(红色虚框)对基本流进行功能增强。注意,装饰流也是可以被装饰的:
BufferedReader buff = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
一些细节
使用字符流记得flush();
需要用到非平台默认的码表时,使用转换流,如:new InputStreamReader(InputStream, "utf-8");
一定要在finall块中释放资源。
java.util.Properties
是HashTable的子类,集合与io结合,针对配置文件的读写。
文件的格式:key=value,均为字符串,以键值对的形式存存入Properties集合。
一些常用方法:
load(InputStream) // 加载配置文件到集合中
getProperty(key) // 获取值
setProperty(key) // 设置值
store(OutputStream,null) // 保存配置信息到指定文件
对象的序列化
class Person
implements Serializable { // 实现Serializable接口,标记此类对象可被序列化
private static final long
serialVersionUID = 110L; // 手动指定UID,若不指定由系统给出
transient String name; // 被transient修饰的成员不会被序列化
static int age; //
}
RandomAccessFile
1、针对文件的随机读取,只能关联文件
2、内部封装了字节读取流和字节写入流,既可读取,又可写入。
3、对象内部定义了一个大型的byte数组,通过定义指针来操作这个数组。
4、通过getFilePointer()方法获取指针的位置,通过seek()方法设置指针的位置。