IO流
IO,Input Out的缩写,也就是输入输出,对数据的输入输出。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流。IO通常有两种分类。
- 按流的方向分为输入流和输出流
- 按流的数据单位分为字节流和字符流
字节流与字符流
两者区别在于数据单位不一样。顾名思义,字节是计算机存储容量的一种计量单位,字符是字形和符号(占2个字节)。下面来看看他们的类。
字符流
- Reader 输入字符流
- Writer 输出字符流
字节流
- InputStream 输入字节流
- OutputStream 输出字节流
在java.io包下可以找到这是四个抽象类,官方提供了很多它们的子类。只要Reader、Writer结尾的类就是字符流,Stream结尾就是字节流。很容易区别。而且大多需要一对使用,比如ByteArrayInputStream和ByteArrayOutputStream。
这两者怎么选择呢?字符流通常用于编辑文本,而字节流的作用就大了,可以把任意文件化作为字节来传输。最好使用字节流,因为它支持所有文件,甚至可以代替字符流。jdk也提供了两者互转的类,InputStreamReader和OutputStreamWriter。
InputStream类内有read抽象方法,继承它子类都要实现read方法。它会向传进byte数组输入数据,返回数据长度,如果是-1就是没有数据。相同的,OutputStream类内有write方法,向传进byte数组的数据输出到它里面。可以指定长度。两个方法都是只进不退,也就是说下一段输出输入都跟上一段没有关系,重新来过。这两个方法一打开,要记得最后close关闭掉,不要造成资源泄漏。字符流也差不多如此。
终于来个例子。
String str = "字节流演示";
InputStream is = new ByteArrayInputStream(str.getBytes());
OutputStream os = new ByteArrayOutputStream();
byte[] buf = new byte[1024];// 缓存
try {
int len = -1;
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
System.out.println(os.toString());
} catch (IOException e) {
} finally {
if (is != null) {
try {
is.close();//关闭流
} catch (IOException e) {
}
}
if (os != null) {
try {
os.close();//关闭流
} catch (IOException e) {
}
}
}
String str = "字符流演示";
StringReader sr = new StringReader(str);
StringWriter sw = new StringWriter();
char[] ch = new char[1024];//缓存区
try {
int len = 1;
while ((len = sr.read(ch)) != -1) {
sw.write(ch, 0, len);
}
System.out.println(sw.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (sr != null) {
sr.close();
}
if (sw != null) {
sr.close();
}
}
缓存区
这是很重要的一点。因为有可能传输的数据会很大,CPU资源利用率会飙高,对硬盘的伤害也大。通常做法是把申请一块内存区,数据一点点的传输。字节流本身是不带缓存区,缓存区的做法跟上面代码一样。字符流会多出一个flush方法,用于清空缓存区。但是每个衍生的子类都有自己的特性,如上面StringReader要自己写个中间缓存区。
四个抽象类衍生出的子类,都具有不同的特性。但不外乎就两个方法read和write。IO流并不难,一个输入一个输出最后记得关就好了。