Bootstrap

黑马程序员--Java基础之IO流(1)

黑马程序员--Java基础之IO流(1)

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

一、概述

1、IO流用来处理设备之间的数据传输。

流操作数据分为两种:字节流与字符流。字符流的对象中糅合了编码表。

流按流向又分为:输入流,输出流。一般都是成对出现。

2、IO流常用基类

(1)字节流的抽象基类:InputStream,OutputStream

(2)字符流的抽象基类:Reader,Writer

二、常用流

1、字符流FileWriter,对文件操作的字符流,写入流。

 FileWriter fw = newFileWriter("demo.txt");//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,该同名文件将会被覆盖。
//其实该步骤就是在明确数据要存放的目的地。
 fw.write("afgsdhdf");//write方法,将字符串写入到流中。但是这样并没有将字符串真正的写进目的地,而是写进了流中去
//所以要刷新一下才能将缓冲区中的字符串写入到目的地。
 fw.flush();//刷新之后还可以再写再刷。
 fw.close();//关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据,将数据存入到目的地中,关闭之后不能再写。
//close和flush的区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。

对已有文件的数据续写:FileWriter的另一个构造函数:FileWriter(StringfileName ,boolean append);

FileWriter fw = newFileWriter("demo.txt",true);
fw.write("sidjfvsldo\r\nvskirfj");//传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写。

2、字符流FileReader,对文件操作的字符流,读取流。

第一种读取方式:通过字符进行读取。

FileReader fr =new FileReader("demo.txt");//创建一个文件读取流对象,和指定名称的文件相关联。要保证该文件是已经存在的,如果不存在,会发生异常:FileNotFoundException。接下来调用read()方法一次读一个字符,读取完毕会返回-1,然后利用循环。
int ch = 0;
while((ch =fr.read()) != -1){
System.out.println((char)ch);} 

方式二:通过字符数组进行读取。

原理:定义一个数组缓冲区,将文件中的内容先读取到这个缓冲数组中,然后读出来,接着读取下一轮,下一轮取出的数覆盖原来的数组中的内容。

FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024];//定义一个字符数组,用于存储读到的字符,一般用1024,这样比较合理,文件内容多了不至于多次循环
int num =0;
while((num = fr.read(buf)) != -1){System.out.print(new String(buf,0,num));}//读几个,打印几个,并且转化成字符串。
fr.close();

3、字符流的缓冲区:BufferedWriter,BufferedRead

缓冲区的出现提高了对数据的读写效率,在流的基础上对流的功能进行了增强。

4、通过缓冲区复制文本文档

package cn.itheima.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
 
public class CopyPractice {
   public static void main(String[] args)
   {  //定义一个写一个读的缓冲区
      BufferedWriter bfw = null;
      BufferedReader bfr = null;
      try
      {
        FileWriter fw = new FileWriter("BufferDemo.txt");
          bfw = newBufferedWriter(fw);
        FileReader fr = new FileReader("Test.txt");
        bfr = new BufferedReader(fr);
        String line = null;
        while((line=bfr.readLine())!= null)//一行一行读
        {
           bfw.write(line);//每读完一行就写一行
           bfw.newLine();//写完一行就换行
           bfw.flush();//刷新一下
        }
      }
      catch(IOException ie)
      {
        System.out.println(ie.getMessage());
      }
      finally
      { 
        if(bfw!= null)//不为空要关闭资源
        {
           try
           {
              bfw.close();
           }
           catch(IOException io)
           {}
        }
        if(bfw!= null)
        {
           try
           {
              bfr.close();
           }
           catch(IOException io)
           {}
        }
      }
   }
}

5、装饰设计模式:当想要对已有的对象进行功能增强时,自定义一个类,将已有对象传入,基于已有的功能,提供加强功能,那么自定义的该类称为装饰类。

装饰类通常会通过构造方法接受被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。

装饰和继承的区别:要加强某个类的某个功能,可以使用继承的方法,但是如果想要加强方法的类有很多,用继承就会使该继承体系臃肿,可扩展性也差。所以,可以找到其参数的共同类型,通过多态的形式,可以提高扩展性。

6、字节流:FileInputstream,FileOutPutStream,BufferedInputStream,BufferedOutputStream。

练习拷贝图片文件:

package cn.itheima.io;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class CopyPicture {
    public static void main(String[] args){
       FileOutputStream fos = null;
       FileInputStream fis = null;
       try {
           fos = new FileOutputStream("2.bmp");
           fis = new FileInputStream("1.bmp");
          
           byte[] buf = new byte[1024];
           int len = 0;
           while((len = fis.read(buf))!=-1){
              fos.write(buf,0,len);
           }
       } catch (IOException e) {
           e.printStackTrace();
       }finally{
           try {
              if(fis!=null)
                  fis.close();
           } catch (IOException e) {
              e.printStackTrace();
           }
           try {
              if(fos!=null)
                  fos.close();
           } catch (IOException e) {
              e.printStackTrace();
           }
       }
    }
}

7、转换流:OutputStreamWriter,InputStreamReader。

       这是字符流通向字节流的桥梁。

8、流操作的基本规律

明确源和目的。

       源:输入流。InputStream  Reader

       目的:输出流。OutputStreamWriter

操作的数据是否是纯文本。

       是:字符流。

       不是:字节流。

再通过设备来明确要使用哪个具体的对象:

       源设备:

       键盘System.in,硬盘 FileStream, 内存 ArrayStream.

目的设备:

       控制台System.out,硬盘 FileStream,内存ArrayStream。

 

9、File

FIle用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作,File对象可以作为参数传递给流的构造函数。

1、File常用方法

*创建。

booleancreateNewFile();//f.createNewFile()在指定位置创建该对象的文件,如果该文件已经存在,则不创建,返回false;这跟输出流不一样,输出流对象一建立就创建文件,而且文件已经存在,会覆盖。
static File createTempFile()//创建临时文件。
boolean mkdir();//创建一级文件夹目录
boolean mkdirs();//创建多级文件夹目录

*删除。

boolean delete();//f.delete()删除失败返回假
void deleteOnExit();//f.deleteOnExit()程序退出时删除文件,常在临时文件时使用。不管有没有异常都删除
*判断。

boolean canExecute();//判断文件是否可以执行
boolean exists();//判断该文件是否存在,未执行创建方法是不存在的
boolean isAbsolute();//也是可以判断出来的创建方法判断是否是绝对路径,这个文件对象不执行
boolean isDirectory();//判断是否为文件目录(文件夹),需要先判断是否存在
boolean isFile();//判断是否为文件,需要先判断是否存在
boolean isHidden;//  判断是否为隐藏文件

*获取信息。

getName();//获取文件对象名字
getPath();//获取文件对象的路径,对象里封装什么路径就得到什么路径,
getParent();//该方法返回的是绝对路径中的父目录,如果获取的是相对路径,返回null,如果相对路径中有上一层目录那么该目录就是返回结果。也就是说,该方法返回的是文件对象中封装的除去本文件的上层目录。
getAbsolutePath();//获取文件的绝对路径,不管对象中有没有封装都获取
long lastModified();//获取上次修改时间
long length(); //获取文件大小。

注意:创建文件对象之后,文件并没有存在,必须执行创建方法,文件才会存在。

2、 File对象功能--文件列表

static File[] listRoots();//File.listRoots返回的是文件数组File[],返回的是电脑中有效盘符。
String[] list();//f.list()//列出当前目录下所有文件,包含隐藏文件。返回的是String[]。

3、 File对象功能--文件列表2

String[] list(FilenameFilter filter);//用于过考虑给定文件夹下的符合条件的文件,FilenameFilter是一个文件过滤接口
File dir = newFile("d:\\java1223\\day18");
String[] arr =dir.list(new FilenameFilter(){//这是一个匿名内部类,实现FilenameFilter接口,
              public boolean accept(Filedir,String name){
                     returnname.endsWith(".bmp");//这个条件,将只能返回d:\\java1223\\day18目录下含有.bmp的文件
              }
              });
File[] listFiles();//返回的是对象列表,实际开发中,使用这一个。返回指定目录下的文件对象。但是只能拿当前目录下的东西

4、列出目录下所有内容--递归

也就是函数自身调用自身,这种表现形式,或者叫编程手法,成为递归。

递归注意事项:

*限定条件

*要注意递归的次数,尽量避免内存溢出。

递归举例:

//列出指定文件夹下的所有文件,包括子文件夹下的所有文件
public voidshowDir(File dir){
       System.out.println(dir);
       File[] files = dir.listFiles();
       for(int x = 0;x<files.length;x++){
              if(files[x].isDirectory())
                     showDir(files[x]);
              else
                     System.out.println(files[x]);
 
       }
}
******************************************
//sum =1+2+3+4.....+(sum-1)+sum;
public intgetSum(int n){
       if(n==1)
              return 1;
       return n+getSum(n-1);
}
 
******************************
//十进制转为二进制的代码简化
public voidtoBin(int num){
       if(num>0){
              toBin(num/2);
              System.out.println(num%2);
       }    
}
 
*********************************************
 
//列出目录下所有内容--带层次
public  String getLevel(int level){
       StringBuilder sb = new StringBuilder();
       for(int x = 0; x<level,x++){
              sb.append("  ");
       }
       sb.append("|--");
       return sb.toString();
}
 
//列出指定文件夹下的所有文件,包括子文件夹下的所有文件
public voidshowDir(File dir,int level){
       System.out.println(getLevel(level)+dir.getName());
       level++;
       File[] files = dir.listFiles();
       for(int x = 0;x<files.length;x++){
              if(files[x].isDirectory())
                     showDir(files[x],level);
              else
                     System.out.println(getLevel(level)+files[x]);
 
       }
}

删除带内容的目录

删除原理:在windows中,删除目录从里面往外删除的。

既然是从里往外删除,就需要用到递归。

public void removeDir(File dir){
	File[] files = dir.listFiles();
	for(int x = 0;x<fils.length;x++){
		if(files[x].isDirectory()){removeDir(files[x]);}
		else
			System.out.println(files[x].toString()+":file:"+files[x].delete());
	}
	System.out.println(dir+":dir:"+dir.delete());
}

;