-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
Java基础之IO流
1.概述:
IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中,根据数据不同可以将流分为两个:字符流、字节流,如果根据数据传输的方向不同又可以分为输入流,输出流,总得来说流可以分为四类如下:
分类方式 | 字节 | 字符 |
输入 | InputStream | Reader |
输出 | OutputStream | Writer |
注意:这里的输入与输出是一个相对的概念,相对的对象是程序本向,从其它地方读取数据到程序中就是输入,从程序到其它地方就是输出;
这四个类都是抽象类,是所有操作流相关类的顶级父类,其它类都直接间接继承这四个类中的一个。
对于流对象来说最主要的方法就是读数据与写数据。
2.InputStream
字节输入流程,主要是用来读取数据,常用的方法:
方法摘要 | |
| close |
| read |
| read |
| read |
常用的子类为:
FileInputStream(从文件系统中的某个文件中获取输入字节),
StringBufferInputStream(此类允许应用程序创建输入流,在该流中读取的字节由字符串内容提供)。
3.OutputStream
字节输出流程,主要是用来输出数据,主要的方法有:
方法摘要 | |
| close |
| flush |
| write |
| write |
| write |
常用的子类:
FileOutputStream:文件输入流(将数据写入到文件中),需要注意的,默认情况下这个类写到文件的数据会复盖前文件前面的数据,为防止这个情况,可以在实例化这个对象的时候用这个构造函数FileOutputStream(Stringname,booleanappend):后面那个参数取”true”;
ObjectOutputStream:将Java对象的基本数据类型和图形写入OutputStream。可以使用ObjectInputStream读取(重构)对象。通过使用流中的文件可以实现对象的持久存储(序列化的)。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
使用字节流程操作文件传输例子:
***************************************************************
//关输入流与一个文件路径关联,表示从这个文件中读数据
InputStream is=new FileInputStream("e:/hibernate练习.txt");
//通过File关联一个文件路径,用于存放输出流程输出的数据(当这个文件不存在时会被创建
File file=new File("e:/hibernate练习(复制).txt");
//实例一个文件输出流程,并将之前创建的file传入,关联
OutputStream os=new FileOutputStream(file);
intlen;
byte[]buff=newbyte[1024];//将数据先读到这里
//通过数据的读写将文件写到指定的地方
while((len=is.read(buff))!=-1){
os.write(buff,0,len);
}
System.out.println("复制成功");
//关闭资源
os.close();
is.close();
***************************************************************
4.Reader和Writer是直接操作字符的输入输出流,使用方式与字符流相似(示例代码略去)。
小结:通过io流程读写数据的步骤可以分为:
第一步:实例化操作输入输出流程,并与目标源关联(数据源及输出目的地);
第二步:实例化一个数组(字节或字符),用于暂时存放输入流程读取的数据;
第三步:通过输入流将数据从数据源中读取出来;
第四步:通过输出流将数据从程序中写入到目的地中;
第五步:关闭流。
字节流可以处理声音、图相等文件及文字的数据操作,而字符流只能用来处理文字数据的操作,且字符流的底层还是字节流,只是它内部使用缓存的技术,将读到的字节先进行缓存。
因此,使用字符输出流程的时候要调用flush()方法将数据刷新到目的地,否则,数据只写到缓存中去,另外,如果调用了关闭资源的方法,在关闭资源前会自动调用此方法,将数据刷新到止目的地中。
因IO流是一种资源,用完后需要关闭,通常会将关闭流的步骤放入到try{}catch{}finally{}结构中的finally块中,因此以上代码可以优化为:
***************************************************************
InputStreamis=null;
Filefile=null;
OutputStreamos=null;
intlen;
byte[]buff=newbyte[1024];
try{
//数据源
is=newFileInputStream("e:/hibernate练习.txt");
//目的地
file=newFile("e:/hibernate练习(复制).txt");
os=newFileOutputStream(file);
//数据读写
while((len=is.read(buff))!=-1){
os.write(buff,0,len);
}
}catch(Exceptione){
//异常处理代码
}finally{
if(is!=null){
try{
is.close();
}catch(IOExceptione){
//异常处理代码
}
}
if(os!=null){
try{
os.close();
}catch(IOExceptione){
//异常处理代码
}
}
}
***************************************************************
5.缓冲流程的使用
通过以上的例子可以看到,无论是用字节流,还是字符流程来操作数据的读写,都是需要直接读写字节或字符,这样的操作效率是比较差的,因此,在IO的操作中,会使用许多缓存的技术提高数据读写的效率,主要有四种缓冲流的类:
BufferedReader(Readerin)
BufferedReader(Readerin,intsz)//sz表示自定义缓冲区大小
BufferedWriter(Writerout)
BufferedWriter(Writerout,intsz)
BufferedInputStream(InputStreamin)
BufferedInputStream(InputStreamin,intsz)
BufferedOutputStream(OutputStreamout)
BufferedOutputStream(OutputStreamout,intsz)
BufferedReader提供readLine方法用于读取一行字符串,BufferedWriter提供了newLine方法用于写入一个行分隔符。对于输出的缓冲流,写出的数据会先在内存中缓冲,使用flush方法将会使内存中的数据立刻写出。
用缓冲流程操作数据的读写:
***************************************************************
//数据源
BufferedReader buffReader=new BufferedReader(new FileReader("e:/hibernate练习.txt"));
//目的地
BufferedWriter buffWriter=newBufferedWriter(new FileWriter("e:/hibernate练习(复制).txt"));
Stringline;
//读写操作
while((line=buffReader.readLine())!=null){
buffWriter.write(line);
buffWriter.newLine();//换行
}
buffWriter.flush();//刷新缓存
buffWriter.close();//关闭前会调用刷新的方法
buffReader.close();
System.out.println("操作完成");
***************************************************************
输出到文件时,默认情况下也会复盖前面的数据,如果想不复盖,可以在构建这个对象的时候传入的输出流中设置,如下
***************************************************************
BufferedWriter buffWriter=new BufferedWriter(newFileWriter(
"e:/hibernate练习(复制).txt",true));
***************************************************************
注意:字节类的缓冲流程没有操作一行数据的方法,而字符类的有此相应的方法。
缓冲流原理:采用装饰设计模式,将一个流进行包装,内部定义了一个数组,将数据读写到这个数组中,再从数据中将数据中传递到目的地;
装饰设计模式简介:
装饰设计的作用是对已有的类进行功能增强,底层还是用到这个类的方法;装饰设计模式的基本原则可以概括为”有你还是你”!这里的你就是这个需要功能增加的类(用A类表述),指的是在增加这个类的时个新设计的类(用B类表述)要继承A类,并在B类内部有一个A类的引用,例如:
***************************************************************
classA{
成员变量…
方法1…
方法2…
…….
}
classBextendsA{
publicA a;
publicB(Aa){//构造方法
this.a=a;
}
方法1增强….
方法2增强….
……
}
B类是A类的装饰类,B类继承了A类,并在B类内部有一个A类的引用,有一个参数是A类的构造方法。
通过对A类的方法进行加强改造,实现对A类的装饰增强的效果。
***************************************************************
装饰和继承的区别:装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系;装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系;从继承结构转为组合结构。
6.其它流程的使用
6.1打印流:PrintStream,PrintWriter
打印流有非常好的打印功能,可以打印任何的数据类型。如,整数,小数,字符串等。
PrintStream类的构造:
PublicPrintStream(File file);
publicPrintStream(OutputStream out);
虽然PrintStream是OutputStream的子类,但是在实例化的时候依然需要一个OutputStream的对象。
PrintWriter和PrintStream都属于输出流,分别针对字符和字节。PrintWriter和PrintStream重载的print()和println()用于多种数据类型的输出。print()里的参数不能为空;println()可以PrintWriter和PrintStream输出操作不抛出异常PrintStream调用println方法有自动flush功能;
演示:
***************************************************************
PrintStreamprintStream=newPrintStream(newFileOutputStream("e:/test1.txt",true));//传入true自动刷新
PrintWriterprintWriter=newPrintWriter(newFileOutputStream("e:/test2.txt",true));//没有自动刷新功能
printStream.println(false);
printWriter.println(12.222);
printWriter.close();//关闭前调用刷新
printStream.close();
***************************************************************
6.2标准流
标准输入流:System.in默认表示的是键盘录入;
标准输出流:System.out默认表示的是屏幕输出。
在System类是声明了一个InputStreamint和一个PrintStreamout,可以通过相应的set方法修改流的具体实列,从而改变这两个流程的读写方向。
staticvoid | setIn(InputStream in)重新分配“标准”输入流。 |
staticvoid | setOut(PrintStream out)重新分配“标准”输出流。 |
演示代码如下:
***************************************************************
//修改输入的数据源为本地的文件
System.setIn(new FileInputStream("e:/hibernate练习.txt"));
//修改输出的目的地为本地的文件
System.setOut(new PrintStream(new FileOutputStream("e:/test3.txt")));
int len;
byte[] buff=newbyte [1024];
//数据读写
while((len=System.in.read(buff))!=-1){
System.out.write(buff,0,len);
}
***************************************************************
6.3字节流转字符流
OutputStreamWriter:把字节输出流对象转成字符输出流对象;
InputStreamReader:把字节输入流对象转成字符输入流对象;
FileWriter和FileReader分别是OutputStreamWriter和InputStreamReader的直接子类,而不(很容易搞反!!)
OutputStreamWriter和InputStreamReader是Writer和Reader的直接子类,与FileInputStream和InputStream的向上的继承关系有所不同。无论使用字节流还是字符流实际上在内存中最终都是通过字节的形式来操作流的。
InputStreamReader、OutputStreamWriter与FileReader,FileWriter读写操作基本一致,代码省略。
6.4合并流(SequenceInputStream)
SequenceInputStream(需要两个源文件,还有输出的目标文件):
将两个文件的内容合并成一个文件,该类提供的方法:
SequenceInputStream(InputStreams1,InputStreams2):根据两个字节输入流对象来创建合并流对象,谁放在前面,谁就先打印出来。
演示代码:
***************************************************************
//实现两个文件输入流程关联本地的两个文件
FileInputStream fis1=new FileInputStream("e:/hibernate练习.txt");
FileInputStream fis2=new FileInputStream("e:/生成工资表.txt");
//实列合并流将前面构建的两个输入流程传入
SequenceInputStream sis=new SequenceInputStream(fis1,fis2);
//实列一个输出流程
FileOutputStream fout=new FileOutputStream("e:/合并流程测试.txt");
intlen;
byte[]buff=newbyte[1024];
//数据读写
while((len=sis.read(buff))!=-1){
fout.write(buff,0,len);
}
//刷新并关闭资源
fout.flush();
fout.close();
sis.close();
System.out.println("合并输出成功");
***************************************************************
7.File类介绍
此类是文件和目录路径名的抽象表示形式,表示一个文件或文件夹。常用的构造方法用:
File |
File |
方法摘要 | |
| canRead |
| canWrite |
| createNewFile |
| delete |
| deleteOnExit |
| exists |
getAbsoluteFile | |
getAbsolutePath | |
getCanonicalFile | |
getCanonicalPath | |
getName | |
getParent | |
getParentFile | |
getPath | |
| isAbsolute |
| isDirectory |
| isFile |
| isHidden |
| lastModified |
| length |
String | list |
String | list |
File | listFiles |
File | listFiles |
File | listFiles |
| mkdir |
| mkdirs |
| setLastModified |
文件操作演示:
***************************************************************
System.out.println(file.canRead());//是否可读
System.out.println(file.canWrite());//是否可修改
System.out.println(file.exists());//是否存在
System.out.println(file.getAbsolutePath());//得到绝对路径
System.out.println(file.getName());//得到名称
System.out.println(file.getPath());//得到绝对路径
System.out.println(file.getParent());//得到上级目录
System.out.println(file.isFile());//是否是文件
System.out.println(file.isAbsolute());//是否为绝对路径名
System.out.println(file.lastModified());//最后修改时间
System.out.println(file.length());//长度
//利用递归的将文件夹所的文件名打印出来(名句前含路径名)
// File[] files = file.listFiles();
// for (File f : files) {
// if (f.isDirectory()) {
// test6(f);
// }
// System.out.println(f.getPath()+f.getName());
// }
String[] fileNames = file.list(new MyFileFilter("txt"));//得到文件名后面为"txt"的文件名集合,MyFileFilter为自定义文件过滤器
for(String string : fileNames) {
System.out.println(string);
}
***************************************************************
最后总结一下IO操作相关的类之前的继承关系: