黑马程序员——Java基础之IO流

-----------android培训java培训、java学习型技术博客、期待与您交流!------------

Java基础之IO流

1.概述:

        IO流用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中,根据数据不同可以将流分为两个:字符流、字节流,如果根据数据传输的方向不同又可以分为输入流,输出流,总得来说流可以分为四类如下:

分类方式

字节

字符

输入

InputStream

Reader

输出

OutputStream

Writer

        注意:这里的输入与输出是一个相对的概念,相对的对象是程序本向,从其它地方读取数据到程序中就是输入,从程序到其它地方就是输出;

        这四个类都是抽象类,是所有操作流相关类的顶级父类,其它类都直接间接继承这四个类中的一个。

        对于流对象来说最主要的方法就是读数据与写数据。

2.InputStream

字节输入流程,主要是用来读取数据,常用的方法:

方法摘要

void

close()
关闭此输入流并释放与该流关联的所有系统资源。

abstractint

read()
从输入流读取下一个数据字节。

int

read(byte[]b)
从输入流中读取一定数量的字节并将其存储在缓冲区数组b中。

int

read(byte[]b,intoff,intlen)
将输入流中最多len个数据字节读入字节数组。

 

常用的子类为:

FileInputStream(从文件系统中的某个文件中获取输入字节),

StringBufferInputStream(此类允许应用程序创建输入流,在该流中读取的字节由字符串内容提供)。

3.OutputStream

字节输出流程,主要是用来输出数据,主要的方法有:

方法摘要

void

close()
关闭此输出流并释放与此流有关的所有系统资源。

void

flush()
刷新此输出流并强制写出所有缓冲的输出字节。

void

write(byte[]b)
b.length个字节从指定的字节数组写入此输出流。

void

write(byte[]b,intoff,intlen)
将指定字节数组中从偏移量off开始的len个字节写入此输出流。

abstractvoid

write(intb)
将指定的字节写入此输出流。

常用的子类:

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;

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(Fileparent,Stringchild)
根据parent抽象路径名和child路径名字符串创建一个新File实例。

File(Stringpathname)
通过将给定路径名字符串转换成抽象路径名来创建一个新File实例。

File(Stringparent,Stringchild)
根据parent路径名字符串和child路径名字符串创建一个新File实例。

 

方法摘要

boolean

canRead()
测试应用程序是否可以读取此抽象路径名表示的文件。

boolean

canWrite()
测试应用程序是否可以修改此抽象路径名表示的文件。

boolean

createNewFile()
当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。

boolean

delete()
删除此抽象路径名表示的文件或目录。

void

deleteOnExit()
在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。

boolean

exists()
测试此抽象路径名表示的文件或目录是否存在。

File

getAbsoluteFile()
返回抽象路径名的绝对路径名形式。

String

getAbsolutePath()
返回抽象路径名的绝对路径名字符串。

File

getCanonicalFile()
返回此抽象路径名的规范形式。

String

getCanonicalPath()
返回抽象路径名的规范路径名字符串。

String

getName()
返回由此抽象路径名表示的文件或目录的名称。

String

getParent()
返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回null

File

getParentFile()
返回此抽象路径名的父路径名的抽象路径名,如果此路径名没有指定父目录,则返回null

String

getPath()
将此抽象路径名转换为一个路径名字符串。

boolean

isAbsolute()
测试此抽象路径名是否为绝对路径名。

boolean

isDirectory()
测试此抽象路径名表示的文件是否是一个目录。

boolean

isFile()
测试此抽象路径名表示的文件是否是一个标准文件

boolan

isHidden()
测试此抽象路径名指定的文件是否是一个隐藏文件。

long

lastModified()
返回此抽象路径名表示的文件最后一次被修改的时间。

long

length()
返回由此抽象路径名表示的文件的长度。

String[]

list()
返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。

String[]

list(FilenameFilterfilter)
返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。

File[]

listFiles()
返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。

File[]

listFiles(FileFilterfilter)
返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。

File[]

listFiles(FilenameFilterfilter)
返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。

boolean

mkdir()
创建此抽象路径名指定的目录

boolean

mkdirs()
创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。

boolean

setLastModified(longtime)
设置由此抽象路径名所指定的文件或目录的最后一次修改时间。

 

文件操作演示:

***************************************************************

        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操作相关的类之前的继承关系:

 

 

 

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值