io流(一)
什么是流:
Java的io流是实现输入输出的基础,利用流可以方便的实现输入输出操作,在java中把不同的输入输出源抽象成流(键盘、文件、网络)。
流的分类:
1. 按照流的流向分类,可以将流分为输入流和输出流。
- 输入流:只能从中读取数据,而不能向其写入数据。
- 输出流:只能向其写入数据,而不能从中读取数据。
输入输出的方向,以运行的程序为主体。流向程序的流是输入流,从程序流出的流是输出流。
2. 字节流和字符流
字节流和字符流的用发几乎完全一样,区别在于字节流和字符流操作的数据单元不同。字节流操作的数据单元是8位的字节,而字符流操作的单元是16位的字符。
字节流主要由IntputStream和OutputStream作为基类,字符流主要是由Reader和Writer作为基类。
3. 字节流和处理流
- 节点流:程序直接连接到实际的数据源,和实际的输入输出节点相连。节点流也被称为低级流。
- 处理流:对一个已经存在的流进行连或包装的流。用封装后的流进行数据读写。处理流也被称为高级流。
实际上,java使用处理流来包装节点流是一种典型的装饰器设计模式,通过使用处理流来包装不同的节点流,既可以消除不同节点的差异,也提供了方便的方法来完成输入输出功能。
节点流和字符流
InputStream和Reader:
InputStream和Reader是所有输入流的抽象基类,本身不能创建实例来执行,但他们将成为所有输入流的模版,他们的方法是所有输入流都可以使用的方法。
InputStream里面包含如下三个方法:
- int read() :从输入流中读取单个字节,返回读取的字节数据(字节数据直接转换成int);
- int read(byte[] b) :从输入流中读取b.length个字节的数据,并将其储存在字节数组b中,返回实际读取的字节数。
- int read(byte[] b,int off, int len) :从输入流中最多读取len个字节的数据,并将其储存到数组b中。放入数组b中时,不是从数组起点开始,而是从off位置开始,返回读取的字节数。
Reader中提供的方法:
- int read() :从输入流中读取单个字符,返回读取的字符数据(字符数据直接转换为int)
- int read(char[] cbuf) :从输入流中读取cbuf.length个字符数据,并将其储存到字符数组cbuf中,返回实际读取的字符数。
- int read(char[] b,int off, int len) :从输入流中最多读取len个字符的数据,并将其储存到数组b中。放入数组b中时,不是从数组起点开始,而是从off位置开始,返回读取的字符数。
InputStream和Read都是抽象类,本身不能创建实例,但他们分别有一个用于读取文件的输入流:FileInputStreamhe,FileWriter。
public abstract class ReaderTest {
public static void main(String args [])throws IOException{
//创建一个文件流对象,和指定文件名的文件相关联。
//要保证文件是已经存在的,如果不存在会发生FileNotFoundException。
FileReader fr = new FileReader("g:\\test.txt");
//定义的缓冲去,当buf装满后才将其输出
char[] buf = new char[1024];
//保存读取的个数,当等于-1时说明文件已经读到末尾了。
int hasread = 0 ;
while((hasread=fr.read(buf))!=-1){
//输出字符串,从0开始上面读取hasread长度的字符串。
System.out.println(new String(buf,0,hasread));
}
}
}
OutputStream和Writer:
OutputStream和Writer非常相似,这两个流同样提供了如下三个常用的方法
- int writer(int c) :将指定的字节/字符输出到流中,其中c既可以代表字节,也可以代表字符;
- int writer(byte[] b) :将字节数组/字符数组输出到指定的流中。
- int writer(byte[] b,int off, int len) :将字节数组/字符数组中从off开始,长度为len的字节/字符输出到指定的输出流程。
Writer中提供的方法:
- int read(String str ) :将str字符串包含的字符输出到指定的输出流中。
- int read(String str,int off, int len) :将str字符串从off位置开始,长度为len的字符输出到指定的输出流中。
如下是使用Writer创建一个输出流,向指定的地方输出字符串
public class FileWriterTest {
<span style="white-space:pre"> </span>public static void main(String [] args) throws IOException{
<span style="white-space:pre"> </span>//创建FileWriter对象。对象在被初始化的时候就要确定操作的文件。
<span style="white-space:pre"> </span>//文件会被创创建在指定的文件下,如果文件存在,将会被覆盖。
<span style="white-space:pre"> </span>//该步骤的目的是为了明确数据要存放的目的地
<span style="white-space:pre"> </span>//使用下面的构造方法,当文件存在的时候不会覆盖原来的文件,而在后面追加。
<span style="white-space:pre"> </span>//FileWriter writer = new FileWriter("g:\\test.txt",true);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>FileWriter writer = new FileWriter("g:\\test.txt");
<span style="white-space:pre"> </span>//调用write方法将字符串写入流中
<span style="white-space:pre"> </span>writer.write("abcd");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//刷新流对象中的缓冲数据。
<span style="white-space:pre"> </span>//将缓冲的数据刷到目的地中。
<span style="white-space:pre"> </span>writer.flush();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//关闭流资源,在关闭之前会调用flush()方法,将缓冲中的数据输出
<span style="white-space:pre"> </span>//和flush()区别,flush刷新后流可以继续使用,close后流会关闭
<span style="white-space:pre"> </span>writer.close();
<span style="white-space:pre"> </span>}
}
异常处理
凡是涉及到流操作,很多的方法都会抛出异常。下面是io异常的处理方式:
public class IoExceptionTest {
public static void main(String[] args) {
//将流对象创建在try的外面,因为别的地方还要使用。
FileReader fr = null;
try{
fr = new FileReader("123.txt");
int s = fr.read();
}catch(IOException e){
System.out.println(e.toString());
}finally{
//当上面发生异常是,fr对象可能还没有创建出来,直接关闭会抛出空指针异常。
if(fr!=null){
try{
fr.close();
}catch(IOException e){
System.out.println(e.toString());
}
}
}
}
}
文件复制的实现:
实现文件的复制需要创建两个流,一个将文件的数据读出来,一个将读出来的数据输出到指定的地方。
为了提高文件的复制速度,可以使用一个缓冲数组。一次将数组读满后在将数组里面的数据一起写到硬盘。
public class CopyTest {
public static void main(String[] args) {
FileReader fr = null ;
FileWriter fw = null ;
try{
//创建输入流,从文件中读数据
fr = new FileReader("g:\\test.txt");
//创建输出流
fw = new FileWriter("g:\\testCopy.txt");
char[] cbuf = new char[1024];
int hasread = 0 ;
//当没读到文件的末尾,一直读
while((hasread=fr.read(cbuf))!=-1){
//当缓冲数组读满后或是读到文件的末尾
//输出流将数据输出到指定的位置。
fw.write(cbuf, 0, hasread);
}
}catch(IOException e ){
System.out.println(e.toString());
}finally{
if(fr !=null){
try {
fr.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(fw !=null){
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}