1.输入流和输出流
a: 数据从内存到硬盘,通常称为输出流。划分输入/输出流是从程序运行所在内存来考虑的,所以是输出流,而不是输入流。
b: 数据从服务器通过网络流向客户端,在这种情况下,server的内存负责将数据输出到网络,因此server端的程序使用输出流;client端的内存负责从网络里读取数据,因此client端的程序应该使用输入流。
注:
Java的输入流主要由InputStream和Reader作为基类,而输出流则主要由OutputStream和Writer作为基类。
2.字节流和字符流
字节流和字符流用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同:字节流操作的最小数据单元是8位的字节,而字符流操作的最小数据单元是16位字符。
字节流主要由InputStream和OutputStream作为基类;
字符流主要由Reader和Writer作为基类。
3.节点流和处理流
按流的角色分,可以分为节点流和处理流。
从一个特定的IO设备(如磁盘、网络)读/写数据的流,称为节点流,节点流通常被称为低级流。
处理流则用于对一个已存在的流进行连接和封装,通过封装后流来实现数据读/写功能。处理流也被称为高级流.
注: java使用处理流来包装节点流是一种典型的装饰设计模式,通过使用处理流包装不同的节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输/输出功能。
3.1 InputStream 和Reader
InputStream和Reader都是抽象类,本身不能创建实例,但是它们分别有一个用于读取文件的输入流:FileInputStream 和 FileReader,他们都是节点流----会直接和指定文件关联。
//创建字节输入流
FileInputStream fis = newFileInputStream("D:\\WorkSpace\\FileInputStreamTest.java");
//创建一个长度为1024的“竹筒”
byte[] bbuf = new byte[1024];
//用于保存实际读取的字节数
int hasRead = 0;
try {
//使用循环来重复“取水”过程
while ((hasRead = fis.read(bbuf))> 0) {
System.out.println(newString(bbuf, 0, hasRead));
}
} finally {
fis.close();
}
注:fis.close()关闭该文件输入流,与JDBC编程一样,程序里打开的文件IO资源不属于内存里的资源,垃圾回收无法回收该资源,所以应该显示关闭文件IO资源。与JDBC类似的是,我们一样应该把关闭文件资源放在finally块里,这样才更安全.
3.2 OutputStream 和 Writer
将某个文件的数据复制到指定的文件中。
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
//创建字节输入流
fis= new FileInputStream("C:\\Documents and Settings\\wh1207029\\Desktop\\修改的java类\\phone.txt");
//创建字节输出流
fos= new FileOutputStream("C:\\Documents andSettings\\wh1207029\\Desktop\\newFile.txt");
byte[] bbuf = new byte[32];
int hasRead = 0;
//循环从输入流中取出数据
while((hasRead =fis.read(bbuf))>0)
{
fos.write(bbuf, 0,hasRead);
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if(fis !=null){fis.close();}
if(fos !=null){fos.close();}
}
4.处理流的用法
由于PrintStream类的输出功能非常强大,通常如果我们输出文本内容,都应该将输出流包装成PrintStream后进行输出。
PrintStream ps = null;
try {
//创建一个节点输出流:FileOutputStream
FileOutputStream fos = newFileOutputStream("test.txt");
//以PrintStream来包装FileOutputStream输出流
ps = new PrintStream(fos);
//使用PrintStream 执行输出
ps.println("普通字符串");
//直接使用PrintStream输出对象
ps.println(new PrintStreamTest());
} catch (IOException e) {
e.printStackTrace();
}finally{
if(ps!=null){ps.close();}
}
注:当我们使用处理流来包装底层节点流之后,关闭输入/输出流资源时,只要关闭最上层的处理流即可。关闭最上层的才处理流时,系统会自动关闭被该处理流包装的节点流。
5.RandomAccessFile类
RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,它提供了众多的方法来访问文件内容。支持“任意访问”方式,程序可以直接跳转到文件的任意地方来读写数据。
RandomAccessFile包含了如下两个方法来操作文件记录指针:
Long getFIlePointer():返回文件记录指针的当前位置.
Void seek(long pos):将文件记录指针定位到pos位置。
注:RandomAccessFile既可以读文件,也可以写,包含了完全类似于InputStream的三个read()方法,也包含了OutputStream的三个write方法。除此之外,RandomAccessFile类的构造函数还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式。
RandomAccessFile依然不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某位置后开始输出,则新输出的内容覆盖文件中原有的内容。如果需要向指定位置插入内容,程序需要先把插入点后面内容读入缓冲区,等把需要插入的数据写入文件后,再将缓冲区的内容追加到文件后面。