您的位置:首页 > 职场人生

黑马程序员--自学笔记--IO流(其一)

2015-11-24 12:04 441 查看

IO流(其一)

-------- android培训java培训、期待与您交流!
---------


一.概述

    IO流是用来处理不同设备之间的数据传输(硬盘,内存等),java语言对数据的操作是需要通过流的方式来进行的,按照流向可以将IO流分为输入流和输出流,按照操作的数据分为字节流(InputStream,OutputStream)和字符流(Reader,Writer)。其中字符流是基于GBK编码表的的流,简单来说,字符流=字节流+编码表

    一般关于IO流的基本操作都需要处理或者抛出异常。

二.字符流

 
  如果要操作文字数据,优先考虑字符流;如果是要将数据从内存中写到硬盘上,要使用字符流中的输出流(Writer)。而硬盘数据的基本体现是文件(FileWriter)。

1.往文件中写入字符步骤:
① 创建一个可以往文件中写入字符的输出对象:
        FileWriter fw = new FileWriter("文件位置") ; 
        //该文件位置是用于存储数据的目的地。如果文件不存在,则自动创建;如果文件存在,则将会覆盖文件。
② 调用Writer对象中的writer(String )方法,写入数据:
        fw.writer("黑马程序员") ;  // 将数据写入到临时缓冲区中
        fw.flush() ;   // 刷新缓冲区,将缓存中的数据直接写入到目的地
③调用完流之后,需要关闭流对象

        fw.close() ;   
        //在调用close()时,会先自动调用flush()。且在关闭刘对象之后将不能对数据进行任何操作
注意:
    (1)当流对象被初始化时,有可能会有异常产生,说一般都先在处理异常之前先定义
    (2)在流对象关闭时,为了避免因为路径无效无法关闭流对象,应该在关闭之前先做个判断,防止出现空指针异常

2.从文件中读取字符步骤
① 创建读取流对象明确所要读取的文件:
        FileReader fr = new FileReader("已存在的文件路径") ;    //该文件必须存在
② 用Reader中的read()/read(char[])方法读取字符数据:
        int ch = fr.read() ;    //该方法会抛出异常,当读到文件末尾时,将返回-1
    或者:
        char[] buf =  new char[3] ;  
        int num = fr.read(buf) ;    //将读取到的字符串存储到数组之中进行缓存

通过以下一个文件复制的操作,来深入了解字符流对象:(注意:注释包含注意点以及知识点) 
package cn.itzixue.writerandreader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/*
* 范例:将一个D盘中的文本文件复制到E盘中
*
* 思路:
* 		由于已经确定了是文本文件,所以可以直接使用字符流进行文件操作
* 		首先需要创建一个流对象读取源的数据,然后在将数据写入到指定的目的地中
*/

public class CopyTextTest {

public static void main(String[] args) {

//创建一个FileReader流对象,读取一个已有的文本文件,此处为了处理异常,先将其定义为空,在try/catch中在实例化对象
FileReader fr = null ;
//创建一个FileWriter流对象,并指定目的名称,对数据进行存储
FileWriter fw = null ;

try {

//所指定的("D:/demo01.txt")文件必须是存在的,否则会抛出异常
fr = new FileReader("D:"+File.separator+"demo01.txt") ;

//所指定的("E:/demo01-copy.txt")文件可以存在也可以不存在。若不存在则进行创建;若存在,则对原文件进行覆盖。
/*
如果想在原有文件中进行续写,则可以利用FileWriter对象的构造方法
FileWriter(File file,boolean append),在传入文件名的同时,传入一个布尔值true,
这样就可以对文件进行续写。
*/
fw = new FileWriter("E:"+File.separator+"demo01-copy.txt") ;

//创建一个临时容器,用于缓存读取到的字符
char[] buf = new char[1024] ;

//定义一个变量记录读取到的字符数,(即是向数组中存入的字符个数)
int len = 0 ;

while((len=fr.read(buf))!=-1){

fw.write(buf, 0, len) ;
}

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

/*
此处将流对象的close()方法定义在finally中,
是为了避免流对象在运行过程中出现异常而导致流对象没有关闭,进而导致内存资源的浪费
(当流未关闭时,文件将无法删除)
*/
finally {

try {

//将流对象关闭时,会先自动调用flush()方法进行刷新。
fr.close() ;
fw.close() ;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
}

三.字符流缓冲区

   引入字符流缓冲区是为了提高流对象传输数据的效率。
1.BufferedReader
    初始化BufferedReader类的对象(关联流对象): 
        BufferedReader bufr = new ByfferedReader(new FileReader("已存在的文件路径")) ;
    通过其特有的readLine()方法,可以一次性读取一行字符。其中包含行内容的字符串,但并不包括任何行结束符,如果已到达流的末尾,则返回 null。底层调用的依然是read,只不过每次将读到的数据储存的一个底层数组(缓冲区)中,返回的是一个字符串。如果读到末尾就返回null(注意此处的null不是字符串似的"null",因为"null"!=null,而是一个实实在在的对象)。该方法使用了读取缓冲区的read()方法,将读取到的字符进行缓冲并判断换行标志。最后将标志之前的缓存数据变成字符串返回。(其中,bufr.read()是从缓冲区中取出字符数据,所以覆盖了父类中的方法)
    在关闭缓冲区的时候,流对象也同时被关闭了。
    (但需要行号时,可以使用继承自BufferedReader的LineNumberReader)
2.BufferedWriter
    初始化BufferedWriter类的对象(关联流对象): 
        BufferedWriter bufw = new BufferedWriter(new FileWriter("文件路径")) ;
    其特有的方法是newLine(),当字符缓冲读取流调用readLine()方法的时候,返回的并不包括行结束标志。因此,在write()写入读取到的一行数据时候,就必须调用newLine()方法进行换行。
3.装饰设计模式
    当需要对一组对象的功能进行增强时,可以使用装饰设计模式进行解决。虽然通过继承也可以实现对原有类功能的增强,但是因为继承会产生关系,所以对比装饰来说,没有那么灵活。而是用装饰设计模式进行功能增强,确是不需要产生关系的,所以较为灵活。但是有一点需要注意,装饰类和被装饰类都必须说属于同一个接口或父类。

    总而言之,BufferedReader和BuffereWriter两个类是在原有类基础上的功能增强。通过这两个类与流对象进行关联并对数据进行操作,在很大程度上提高数据操作的效率。

四.字节流

  当操作的数据不是单纯的文本数据时,我们就不能使用字符流了,而是应该使用字节流来进行数据的操作。
1.使用字节流进行数据的写操作
① 创建字节输出流对象:
        FileOutputStream fos = new FileOutputStream("目的位置") ;
② 写数据:
        fos.write("abc".getBytes()) ;    //字节流写的数据是字节数据,并且直接写到目的地中,所以不需要进行刷新
③ 关闭流对象:

        fos.close() ;     //关闭资源动作一定要完成

2.使用字节流进行文件的读操作
① 创建一个读取流对象,和指定文件进行关联:
        FileInputStream fis = new FileInputStream(" 已存在的文件位置") ;
② 使用read()/read(byte[])进行读数据:
        int ch = fis.read() ;    //一次读取一个字节。对于中文,字符流一次可读一个而字节流需要读两次
    或者:
        byte[] buf = new byte[1024] ;    //字节流的缓冲区使用的是字节数组(byte[])
        int len = 0 ;    //对读取到的数据进行长度的记录
        while((len=fis.read(buf))!=-1){ … 对读取到的数据进行操作 … }
③ 关闭流对象

        fis.close() ;

    通过字节流对象的available()方法,可以返回文件大小(字节数)。

通过以下一个复制MP3文件的操作,来深入了解字节流对象:(注意:注释包含注意点以及知识点)

package cn.itzixue.inputstreamandoutputstream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyMP3 {

public static void main(String[] args) throws IOException {

copy() ;

}

/*
* 由于MP3文件有其特有的编码方式,所以不能通过字符的编码方式进行读取与写入,
* 		所以不能使用字符流,而应该使用字节流对象。
* 为了提高其传输效率,可以使用字节流对应的缓冲区对象(BufferInputStream/BufferOutputStream)
*/
public static void copy() throws IOException {

//创建一个文件的字节流输入对象
FileInputStream fis = new FileInputStream("D:"+File.separator+"1.mp3") ;
//创建缓冲区对象将字节流对象传入
BufferedInputStream bufis = new BufferedInputStream(fis) ;

//创建一个文件的字节流输出对象
FileOutputStream fos = new FileOutputStream("E:"+File.separator+"1-copy.mp3") ;
//创建缓冲区对象将字节流对象传入
BufferedOutputStream bufos = new BufferedOutputStream(fos) ;

//创建一个临时容器,用于缓存读取到的字节
byte[] buf = new byte[1024] ;
//定义一个变量记录读取到的字节数
int len = 0 ;

while((len=bufis.read(buf))!=-1){

bufos.write(buf,0,len) ;

//此处不应该进行刷新,如果没读一次刷新一次的话,会使得效率变得很慢
//bufos.flush() ;
}

//使用完流对象一定要将其关闭
bufis.close() ;
bufos.close() ;

}

}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息