(7) - IO流 (图)
来源:互联网 发布:淘宝一千零一夜在哪 编辑:程序博客网 时间:2024/05/22 08:08
---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------
一、IO流概述
IO流即输入(Input)输出(Output)流,流是种形象的说法,计算机数据(字节或字符)的转移都是大量、持续的,像水流般。输入指将制定位置的数据读入内存中,输出指将内存数据写到指定的位置上。那么IO流是用来处理设备间的数据传输的。
在java中:
(1) 对数据的操作是通过流的方式。
(2) 用于操作流的对象都在IO包中。
(3) 流按操作数据分为两种:字节流与字符流
(4) 流按流向分为:输入流和输出流。
IO流操作的异常处理:
由于IO流存在各方面的不确定,需要异常处理机制的支持,在常规处理时都建议采用捕获方式,下面IO流知识点的例子,为了突出知识点,简化了异常的处理,采用抛出方式,以便能使代码清晰些,常规处理应采用下列格式:
/*IO异常的处理方式*/import java.io.*; class IoExceptionDemo{public static void main(String[] args){ //在外面建立引用对象,在try中构造初始化 //colse也要求处理IO异常,所以也的进行try、 //即3个方法都要try处理 //如构造时抛出异常,将中断,但会执行finally中的 //fw.close,因为构造失败fw=null,调用失败 //需在前进行健壮性的判断,if(fw != null) FileWriter fw = null; try { fw =new FileWriter("Demo.txt"); //write将内容写入流缓存中,并未写入文件中 fw.write("写入文本内容"); //加flush刷新后,流中内容写入文件中,但流并未关闭,可继续写 fw.flush(); } catch (IOException e) { System.out.println(e.toString()); } finally { try { //这步要有,安全判断 //因fw =new FileWriter("Demo.txt");可能会失败,比如在不存在的K盘下 if(fw != null) fw.close(); //先刷新,后关闭流,不能再写入数据了 } catch (IOException e) { System.out.println(e.toString()); } } System.out.println("文件创建成功!");}}
二、字符流
在进行数据操作时,操作数据以字符为单元,该类体系为Reader和Writer。
1、 Writer和Reader
Writer为写入字符流的抽象类,其子类后缀名基本是Writer。其子类必须要实现父类的抽象方法为write(char[], int,int)、flush() 和 close()。当我们向文件write数据时,数据仅存在缓冲中,需用flush刷新后数据才从缓冲写入文件中。Close之前会进行一次缓冲的刷新。其实jvm是在调用系统内部的读写方法,因为系统会不同,jvm如都用自已的方式写入数据是不合适的。
Reader为读入字符流的抽象类,其子类后缀名基本是Reader,必须要复写的方法有read(char[],int, int) 和 close()。
2、 BufferedWriter和BufferedReader
为了提高对数据的读写效率,IO中定义了缓冲区,可以说是一个过渡区,将陆续的数据先写入缓冲区积攒,而后一股脑写入目标设备。就像我们写word,写一段后保存,而不是写一个字保存一下。所以不建议采用,读一字符,写一字符的方式,因为这使磁头读写操作频繁,建议先读一次性入流中,再将流数据写入目的文件中。 最后关闭读写流
特点:
①缓冲区的技术原理其实就是封装了数组。
②它的出现是为了提高流的操作效率存在的,所以在创建时,构造函数必须传入一个流对象。
③调用close关闭缓冲区时,就会关闭缓冲区的流对象,所以关闭了缓冲区就不需要写流对象关闭了。
④BufferedWriter和BufferedReader的类构造采用了装饰设计模式,对流的操作类进行了功能的加强,至于装饰模式,将在以后介绍。
BufferedWriter:字符流输出的缓冲区,提供了一个跨平台的换行方法newLine(),解决在不同系统中换行符不统一的问题。在向目标输出前记得先flush()刷新。
BufferedReader:字符流输入的缓冲区,同样提供了一个readLine方法,从文件中读取一行数据,返回给String,当读到文件尾时返回空,其本质还是用read一个一个字符读取的,只不过积攒一行返回。该类有个LineNumberReader子类,比BufferedReader多出行号的追踪功能。方法有setlineNumber();设置行号getReadLineNumber();读出行号
3、 InputStreamReader和OutputStreamWriter
转换流:由于某些需求,需要在字符流和字节流间互相转换,java便将该操作封装成类,以供需求,如他们的子类FileWriter和FileReader,我们直接可以用其子类进行字符的操作,而不必去考虑复杂的字节。
InputStreamReader为字节流转换成字符流,这样便可利用字节流的BufferedReader缓冲区操作提高效率,要求在创建时向构造函数传入InputStream的字节流对象,也可以用构造函数的Charset参数指定编码格式。InputStreamReader构造函数中传入System.in流参数,便可接手键盘录入数据。
OutputStreamWriter字符流转换成字节流,同理,只不过参数输入改输出,如接收System.out打印在控制台。
4、 FileWriter与FileReader
他们分别属于InputStreamReader和OutputStreamWriter的子类,专门对字符数据的文件进行操作。可接收路径字串和File对象等。
FileWriter:用来写入字符文件的便捷类,有默认的字符编码和缓冲区。可进行对文本的写入和文本的追加,追加文本的构造函数只要将参数2用上,初始成true即可,写入前需刷新。创建对象时,该类会打开指定文件,若文件已打开则创建失败。
FileReader:用于读取字符文件的便捷类,同样具有默认编码和缓冲区。由read()读取单个字符,返回一个整数,读到文件尾返回-1。
IO流操作会抛出异常,需处理,以应对文件已打开或文件不存在等异常,异常处理稍后介绍。下面是1、2、3的一个综合例子:将键盘录入,写入文件中。
import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;import java.io.InputStreamReader; /* * 需求:将键盘录入写入文件中 * * 说明这里不重点体现异常处理,所以简单的抛出了 * 正规开发,建议用try进行捕获 * */public class CopyText{ //由于异常处理不是这里要体现的,所以采取抛出异常,正常编码建议捕捉 public static voidmain(String[] args) throws IOException { //标准的键盘录入方式,将输入转字符交给缓冲区。 BufferedReader bufr= new BufferedReader(new InputStreamReader(System.in)); //FileWriter读取字符文件,交给缓冲,会抛出异常,简单抛出了,平时建议捕捉 BufferedWriter bufw= new BufferedWriter(new FileWriter("Test.txt")); String strLine =null; while((strLine =(bufr.readLine()))!=null) { //输入over时,结束 if("over".equals(strLine)) break; //写入文本 bufw.write(strLine); bufw.newLine();//换行 bufw.flush();//刷新 } bufr.close(); bufw.close(); }}
5、 CharArrayReader和CharArrayWriter
提供在缓冲区和内存间的操作方式,用于操作字符数组,内部拥有可自动延长的内存空间,由于是操作内存,最后不需关闭。
CharArrayReader,需接收一个字符数组型的数据源,将内存的数据以数组的方式存入传入的数组源中,无需关闭。
CharArrayWriter,同理。
6、 PrintWriter
向文本输出流打印对象的格式化表示形式,为其他字符流类添加了输出功能,在构建时,将构造函数参数2置true,还可带自动刷新功能,利用println()能实现换行,等于代替了上述代码中的 bufw.write(strLine);bufw.newLine();bufw.flush();三句。
构造函数能接收的文件源可以是,File对象,字符串路径,字节输出流。
7、 PipedWriter和PipedReader
管道流,它具有将一个程序的输出当做另一个程序的输入的能力,这个涉及线程,也就是我们线程通信的另一种方式,利用管道流通信,它需要利用connect将两者连接,即:读.connect(写)。
import java.io.IOException;import java.io.PipedReader;import java.io.PipedWriter; /* * 字符管道流的测试*/class Read implements Runnable{private PipedReader pr;Read(PipedReader pr){ this.pr = pr;}public void run(){ try { //构建接收数组 char[] chs = new char[1024]; //读取连接的写入管道流,多句用循环 int len = pr.read(chs); System.out.println(newString(chs,0,len)); pr.close(); }catch(Exception e) { throw new RuntimeException("读取失败!"); }}}class Write implements Runnable{private PipedWriter pw;Write(PipedWriter pw){ this.pw = pw;}public void run(){ try { //直接写出 pw.write("这是管道流数据!"); //多句要pw.flush()刷新,这里再close前自动刷新了 pw.close(); }catch(Exception e) { throw new RuntimeException("写入失败!"); }}}public class PipedDemo{public static void main(String[] args) throws IOException{ PipedWriter pw = new PipedWriter(); PipedReader pr = new PipedReader(); //需连接,读的连接写的 pr.connect(pw); new Thread(new Read(pr)).start(); new Thread(new Write(pw)).start();}}
8、RandomAccessFile
该类不算是IO体系中子类,而是直接继承自Object。随机访问文件,自身具备读写方法。通过skipBytes(int x),seek(int x)来达到随机访问,即含有文件指针,可跳跃。
但是它是java.IO包中成员,因为它具备读和写功能,
它内部封装了一个数组,而且通过指针对数组的元素进行操作。可以通过getFilePointer获取指针位置。同时可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
其构造函数只能接收文件对象,而且可以指定模式,如’r’,只读。
局限性:通过构造函数可已看出,该类只能操作文件。而且操作文件要用模式。
三、字节流
在进行数据操作时,操作数据以字节为单元,该类体系为InputStream和OutputStream,字节流的输出是直接从内存写入,不需要转字符的过程,因此没有字符流刷新的过程。
1、InputStream和OutputStream
InputStream为写出字节流的抽象类,其子类后缀名基本是InputStream。提供read()方法。
OutputStream为读入字节流的抽象类,其子类后缀名基本为OutputStream。提供write()方法。
2、FileOutputStream和FileInputStream
分别为InputStream和OutputStream的子类,复写了read()方法,主要用于读取诸如图像数据之类的原始字节流。没有缓冲区,自己构建byte类型的数组。
FileOutputStream:以字节流的形式输出到文件中,复写了write方法,一次写入一个字节,若要已向文件结尾处追加字节,在创建时的构造函数中初始第二个参数为true。
FileInputStream:将字节流读入到内存中,复写了read方法,每次只能读一个字节,返回一个int型数据,当读到文件尾时返回-1。他有个特有的方法available(),返回文件剩余的字节数。如果文件较小,可以先读出大小,声明足够的byte数组,不用循环,但是文件不能过大,虚拟机不可能开辟很大的内存空间,比如视频文件,new一个数组不会成功,所以应视情况使用available()。
其格式类似与FileWriter与FileReader,在这里不写例子了,稍作改动即可,将字符读入改为字节流的byte,不用刷新等。
3、ByteArrayOutputStream与ByteArrayInputStream
与字符流的CharArrayReader和CharArrayWriter同理,只不过数据源为byte数组。
4、PipedOutputStream与PipedInputStream
与字符流的PipedReader和PipedWriter同理,只不过一切按字节流的操作方式。
5、ObjectInputStream与ObjectOutputStream
对象序列化流,用于对象的序列化(持久化),即能将对象存入硬盘中,保存对象和对象数据。由ObjectOutputStream将java对象的基本数据类型和图形写入OutputStream(流)中,使用ObjectOutputStream可读取重构该对象。被操作的对象所属类必须实现Serializable接口,该接口没有要复写的方法,我们叫这种类型的接口为标记接口。实现该接口,其实就是给每给要保存的类一个ID号,简称UID,若要保存对象的类不实现该接口使用对象序列化流,将会报NotserializableException异常。
默认对象序列化后,不能修改其类,因为序列化文件中记录的UID变化了,使用时或报错,为防止修改类时,保存文件变化UID而导致不可用,我们采用自定义UID,
如public static final long srrialVersionUID = 42L;
静态成员不会被序列化,他再方法区,而对象在堆中。若不想某成员序列化,加tansient修饰该成员。
这两个类必须成对使用,用ObjectOutputStream写,就用ObjectInputStream。
如下例:
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable; public class ObjectStreamDemo{ public static void main(String[] args) throws Exception { writeObject(); readObject(); } public static void writeObject() throwsException { //这里为简化代码,异常省略捕捉处理 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt")); //写入一个Person对象 oos.writeObject(new Person("张三")); oos.close(); } public static void readObject() throws Exception { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt")); //从文件中读取序列化的对象 Person p = (Person)ois.readObject(); System.out.println(p); ois.close(); }}//要序列化的对象类,必须向实现SerializableclassPerson implements Serializable{ //自定义一个标记号,防止修改二影响序列化的对象不可用。 public static final long serialVersionUID =42L; private String name=null; Person(String name) { this.name = name; } public String toString() { return "姓名:" + name; }}
6、SequenceInputStream
SequenceInputStream对多个流进行合并。从第一个流,读完,再接着读取第二流,依次下去。可以将多个流的操作数据写入到一个目标中。比如将三个文件的数据写入到一个文件中。构造函数中传入Enumeration对象,由Enumeration保存多个流对象。Enumeration时旧版本中Vector的类型。
先准备三个文件1.txt,2.txt,3.txt,将内容合并到4.txt中如下例子:
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.SequenceInputStream;import java.util.Enumeration;import java.util.Vector; public class SequenceInputStreamDemo{ //这里为代码简练省略捕捉处理异常 public static void main(String[] args)throws IOException { //由于SequenceInputStream的构造函数要传Enumeration类型,这里用Vector Vector<FileInputStream> vct = new Vector<FileInputStream>(); //准备合并的三个文件 vct.add(new FileInputStream("1.txt")); vct.add(new FileInputStream("2.txt")); vct.add(new FileInputStream("3.txt")); //获取三个文件的流对象 Enumeration<FileInputStream> en =vct.elements(); //合并 SequenceInputStream sis = new SequenceInputStream(en); //合并后写入另一个文件 FileOutputStream fos = new FileOutputStream("4.txt"); byte[] buf = new byte[1024]; int len = 0; while((len = sis.read(buf))!=-1) { fos.write(buf,0,len); } fos.close(); sis.close(); }}
切割文件:
利用自定义byte[]数组限制读入大小,将文件分批存入多个新建的文件中。
但是在切割较大的视频的文件时,就不能new过大的byte数组了,
应定义1024*1024(1M)大小的数组向一文件存入数据,再采用一计数器记录装入了多少数据,达到要求时,再新建一文件,继续装入下一个。无太多技术要求,纯算法,这里不再举例。
8、 FilterInputStream与FilterInputStream的子类
(1) BufferedInputStream与BufferedInputStream
功能与字符流的BufferedReader与BufferedWriter缓冲区类似,早构造时可以指定缓冲大小
下面写一个拷贝图片的例子:
import java.io.*; public class CopyPicDemo{//简化代码,没做异常的捕捉public static void main(String[] args) throws IOException{ //字节流缓冲区 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.jpg")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("2.jpg")); int by = 0;; while((by = bis.read())!=-1) { bos.write(by); } bis.close(); bos.close();}}
(2) DataOutputStream与DataIntputStream
可以对基本数据类型输入输出,构造时需传入流对象,DataOutputStream使用writeInt(int)、writeBoolen(bool)等方法向文本写入基本数据类型,用DataIntputStream的readInt()、readBoolean()等方法读出,有严格的字节顺序,读错顺序后面的数据将不能正常读出。
(3) PrintStream
类似于字符流的PrintWriter类。它为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。与其他输出流不同,
PrintStream
永远不会抛出IOException
;而是,异常情况仅设置可通过checkError
方法测试的内部标志,通过checkError()方法获得。
---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! ----------------------
- (7) - IO流 (图)
- 实验7 IO流
- 7-23 IO流
- 【IO流】IO框架
- IO流呀IO流
- 字符IO&数据流IO&对象流IO
- io流
- io流
- IO流
- IO流
- IO 流
- IO流
- io流
- IO流
- io流
- IO流
- IO流
- IO流
- 随便写了一些,练练SWING界面
- 八、结构模式之组合(Composite)模式
- 分组背包--hdu1712
- js判断ie,ff,chrome各浏览器
- 重装windows server 2003 R2 X64服务器
- (7) - IO流 (图)
- VASP安装总结
- Tomcat6 配置多虚拟主机,多域名绑定一IP
- 黑马程序员_08Java网络编程知识总结
- SequenceFile文件
- PHP 定界符<<< 使用技巧
- Android NDK 第一个例子 HelloNDK
- 2013国内IT行业薪资对照表【技术岗】
- Highcharts和EXT中panel结合