黑马程序员--自学笔记--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() ; } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统