Java IO流什么是流?

概念:内存和存储设备之间传输数据的通道。

数据借助流传输。

流分类:

  • 按照方向:输入流(将存储设备中的内容读入到内存中)和输出流(将内存中的内容写入到存储设备中)
  • 按照单位:字节流(以字节为单位,可以读写所有数据)和字符流(以字符为单位,只能读取文本数据)
  • 按照功能:节点流(具有实际传输数据的读写功能)和过滤流(在节点流的基础之上增强功能)

字节流

字节流的父类(抽象类):

  • InputStream:字节输入流:提供一些如read(),close()的方法
  • OutputStream:字节输出流:提供一些如write(),close()的方法

文件字节流

  • FileInputStream:文件字节输入流,继承字节输入流
  • FileOutputStream:文件字节输出流,继承字节输入流

文件字节输入流操作:

//创建FileInputStream并且指定文件路径FileInputStream fis = new FileInputStream("d:\\aa.txt");int data = 0;//read返回的int,当等于-1表示读完了,如果是字符返回对应的asc码//一次读取一个字节while ((data=fis.read())!=-1){    System.out.println((char) data);}/*abc

什么为一次读取一个字节的情况

当需要一次读取多个字节

//创建FileInputStream并且指定文件路径FileInputStream fis = new FileInputStream("d:\\aa.txt");//一次读取多个个字节byte[] buf = new byte[3];//本处read返回实际读取个数,读完返回-1,并且将读取到的存储在buf中//因为数组大小一次读取三个System.out.println(fis.read(buf));System.out.println(new String(buf));fis.close();/*3abc*///或者FileInputStream fis = new FileInputStream("d:\\aa.txt");        byte[] buf = new byte[3];        int count=0;        while ((count=fis.read(buf))!=-1){         System.out.println(new String(buf,0,count));        }        fis.close();/*abcdefg

本处只是例子,实际操作时缓冲区数组不需要创建得太小,可以是1024以上

文件字节输出流操作:

//创建文件字节输出流,为true代表文件已经存在时追加,false每次都会覆盖(默认)FileOutputStream fos=new FileOutputStream("d://aa.txt",false);fos.write(97);fos.write('b');fos.write('c');//文件中:abc//要写入字符串:转成byte数组String s = "helloworld";fos.write(s.getBytes());//文件中:abchelloworld

实现复制操作:

FileInputStream fis = new FileInputStream("d:\\aa.txt");FileOutputStream fos = new FileOutputStream("d:\\bb.txt");byte[] buf = new byte[1024];int count=0;while ((count=fis.read(buf))!=-1){    fos.write(buf,0,count);}fis.close();fos.close();

字节缓冲流

  • 缓冲流:BufferedInputStream/BufferedOutputStream
  • 继承了过滤流(FilterOutputStream/FilterInputStream),而过滤流又继承了文件字节流
  • 内置了缓存区(8k)
  • 作用:提高IO效率,减少访问磁盘次数;数据存储在缓存区,flush是将缓冲区的内容写入文件中,也可以直接close,后面实现缓冲区的类类似

字节输入缓冲流:

//        创建BufferedInputStream,需要传入一个底层流        FileInputStream fis = new FileInputStream("d:\\aa.txt");        BufferedInputStream bis = new BufferedInputStream(fis);//        读取:类似,但是这个有缓冲区效率更高        int data = 0;        while ((data=bis.read())!=-1){            System.out.print((char)data);        }        //当然也可以和文件字节流一样,直接再创建一个缓冲区实现,一模一样但是因为内部缓冲区的存在效率更高        //        关闭这一个就行        bis.close();//out:abchelloworld

字节输出缓冲流:

FileOutputStream fos = new FileOutputStream("d://bb.txt");BufferedOutputStream bos = new BufferedOutputStream(fos);//转义符如换行等也可以写入也可以String s = "hello\r\n";bos.write(s.getBytes());//这是写入了缓冲区,没有写入文件bos.flush();//需要刷新才能从缓冲区真正写入文件bos.close();//当然close时自动flush

对象流

  • 对象流:ObjectOutputStream/ObjectInputStream
  • 可以实现写入或者读取对象
  • 增强了缓冲区功能
  • 增强了读写8种基本数据类型和字符串的功能,不只是能读写int和byte
  • readObject()从流中读取一个对象;writeObject(Object obj)向流中写入一个对象
  • 使用流传输对象的过程被称为序列化(写入)和反序列化(读取)
  • 继承文件字节流,需要基于其才能创建
  • 序列化和反序列化的对象类都必须实现Serializable接口(该接口本身没有任何方法仅仅标志该类可以序列化),而且其中关联的其他类也要实现该接口
  • 可以在类中自定义生成常量private static final long serialVersionUID ,该常量为序列化版本号用来标识该类,即使是同一个类如果UID不同依旧被认为不是同一个类无法反序列化不同UID的类
  • 使用transient修饰实现,表示该属性不需要序列化(例如:private transient int age )
  • 静态属性不能序列化

序列化:

public class  Student  implements Serializable {}//main:FileOutputStream fos = new FileOutputStream("d://aa.txt");        ObjectOutputStream oos = new ObjectOutputStream(fos);//        序列化        Student student = new Student();        oos.writeObject(student);//        oos.writeBoolean();写入boolean//         oos.writeBytes("hellow");//写入字符串//        其他基本类型也有相应的办法写入        oos.close();

反序列化:

FileInputStream fis = new FileInputStream("d://aa.txt");ObjectInputStream ois = new ObjectInputStream(fis);//读取存入的第一个对象Student s = (Student)ois.readObject();ois.close();

序列化、反序列化多个对象时可以使用集合:

//序列化 FileOutputStream fos = new FileOutputStream("d://aa.txt");        ObjectOutputStream oos = new ObjectOutputStream(fos);//        序列化        Student student = new Student();        Student student1 = new Student();        ArrayList arrayList = new ArrayList();        arrayList.add(student);        arrayList.add(student1);        oos.writeObject(arrayList);        oos.close();//反序列化FileInputStream fis = new FileInputStream("d://aa.txt");        ObjectInputStream ois = new ObjectInputStream(fis);        ArrayList arrayList = (ArrayList) ois.readObject();        ois.close();

常见字符编码

字符流

问题的引出:

FileInputStream fis = new FileInputStream("d://aa.txt");int data = 0;while ((data=fis.read())!=-1){    System.out.println((char)data);}fis.close();//上述代码当我们读取的文件中为中文时得到乱码。//原因:我们是运用字节流一个一个字节读取文件,而本处的文件编码方式是utf-8(中文常见的编码方式),每个中文字占3个字节。当一个一个字节读取时出现乱码

这种情况下我们需要字符流

字符流的父类(抽象类):

Reader(字符输入流)和Writer(字符输出流)

只能用于文本文件

文件字符流

  • FileReader和FileWriter
  • 父类是InputStreamReader和OutputStreamWriter,而这两者的父类又是Reader和Writer
  • 采用默认字符编码

FileReader:

FileReader fr = new FileReader("d://aa.txt");       //单个字符的读取//        int data = 0;//        while ((data=fr.read())!=-1){//读取一个字符//            System.out.println((char)data);//        }//创建缓冲区读取//缓冲区为2字符        char[] buf = new char[2];        int count = 0;        while ((count = fr.read(buf))!=-1){            System.out.println(new String(buf,0,count));        }        fr.close();/*out:你好呀

FileWriter:

FileWriter fw = new FileWriter("d://aa.txt");fw.write("你好吗");fw.flush();fw.close();

字符缓冲流

  • 缓冲流:BufferedReader/BufferedWriter
  • 高效读写
  • 支持输入换行符
  • 可以一次写一行、读一行
  • 可以指定缓冲区大小,也可以默认(8K)
  • 新建需要基础字符流(文件字符流)
  • 继承Reader和Writer

读取:

FileReader fr = new FileReader("d://aa.txt");       BufferedReader br = new BufferedReader(fr);//        和上面其他类类似的方法不再重写//        特有的:读一行,末尾返回null        String s = null;        //一行一行的读取        while ((s=br.readLine())!=null){            System.out.println(s);        }        br.close();//out:你好呀

写入:

      FileWriter fw = new FileWriter("d:\\aa.txt");      BufferedWriter bw = new BufferedWriter(fw);//      写入        bw.write("好好学习");//        写入一个换行windows:\r\n linux:\n        bw.newLine();        bw.write(",天天向上");        bw.close();/*文件:好好学习,天天向上

打印流

  • PrintWriter:

    • 支持print()/println(),支持写入后换行
    • 支持数据原样打印
    • 继承Writer类
    • 类似PrintStream,但是PrintWriter只能打印字符流,而PrintStream可以打印字节流
     PrintWriter pw = new PrintWriter("d://aa.txt");//      打印并且换行        pw.println(97);        pw.println(true);//打印        pw.print("a");pw.print("b");        pw.close();/*文件中:97trueab

转换流

  • 也叫桥转换流:InputStreamReader/OutputStreamWriter
  • 可以将字节流转换为字符流
  • 可设置字符的编码方式
  • 继承字符流Reader/Writer
  • 创建时需要基本的文件字符流

InputStreamReader:

FileInputStream fis = new FileInputStream("d://aa.txt");InputStreamReader isr = new InputStreamReader(fis,"utf-8");int data=0;//一个一个字符读取while ((data=isr.read())!=-1){    System.out.print((char)data);}isr.close();

OutputStreamWriter:

FileOutputStream fos = new FileOutputStream("d://aa.txt");OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");for(int i=0;i<10;i++){    osw.write("我爱中国\r\n");    osw.flush();}osw.close();

File类

  • 概念:代表物理盘符中的一个文件或者文件夹

//        分隔符        System.out.println("路径分割符"+File.pathSeparator);        System.out.println("名字分割符"+File.separator);        File file = new File("d://cc.txt");//        判断文件是否存在        if(!file.exists()){//            创建文件            boolean b = file.createNewFile();            System.out.println("创建结果:"+b);        }       if(file.exists()) {//           直接删除           System.out.println("删除结果" + file.delete());           //使用jvm退出时删除           file.deleteOnExit();       }//       获取文件信息        System.out.println("绝对路径"+file.getAbsolutePath());       //看你创建时传入的路径        System.out.println("获取路径"+file.getPath());//        获取名称        System.out.println("获取名称"+file.getName());//        获取父目录        System.out.println("获取父目录"+file.getParent());//        获取文件长度        System.out.println("获取文件长度"+file.length());//        文件创建时间        System.out.println("文件创建时间"+new Date(file.lastModified()).toString());//        判断文件是否可写        System.out.println("是否可写"+file.canWrite());//        是否是文件        System.out.println("是否是文件"+file.isFile());//        是否隐藏        System.out.println("是否隐藏"+file.isHidden());/*路径分割符;名字分割符\创建结果:true删除结果true绝对路径d:\cc.txt获取路径d:\cc.txt获取名称cc.txt获取父目录d:\获取文件长度0文件创建时间Thu Jan 01 08:00:00 CST 1970是否可写false是否是文件false是否隐藏false

文件夹操作:

File dir = new File("d://cc/aa");//        判断文件是否存在        if(!dir.exists()){//            创建文件夹:只能创建单集目录//            boolean b = dir.mkdir();//            创建多级目录            boolean b = dir.mkdirs();            System.out.println("创建结果:"+b);        }       if(dir.exists()) {//           直接删除:最下层且必须为空目录           System.out.println("删除结果" + dir.delete());           //使用jvm退出时删除,休眠结束后删除           dir.deleteOnExit();           Thread.sleep(5000);       }//       获取文件信息        System.out.println("绝对路径"+dir.getAbsolutePath());       //看你创建时传入的路径        System.out.println("获取路径"+dir.getPath());//        获取名称        System.out.println("获取名称"+dir.getName());//        获取父目录        System.out.println("获取父目录"+dir.getParent());//        文件创建时间        System.out.println("文件创建时间"+new Date(dir.lastModified()).toString());//        判断是否是文件夹        System.out.println("是否可写"+dir.isDirectory());//        是否隐藏        System.out.println("是否隐藏"+dir.isHidden());//        遍历文件夹        String[] file = dir.list();

FileFilter接口

  • public interface FileFIlter

    • boolean accept(File pathname)
  • 当调用File类的listFiles()方法时,支持传入一个实现了FileFilter接口的实现类对文件进行过滤,只有满足条件的文件才能出现在listFiles()返回值中

  • 实现过滤

File dir = new File("d://cc/aa");File[] files= dir.listFiles(new FileFilter() {            @Override            public boolean accept(File pathname) {                //如果名字以.jpg结尾返回,否则不返回                if(pathname.getName().endsWith(".jpg")){                    return  true;                }                else{                    return  false;                }            }        });

递归遍历文件夹(递归删除文件夹:先把文件内删空再删除文件夹):

public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {    listDir(new File("d://aa"));}public  static  void listDir(File dir){    File[] files = dir.listFiles();    if(files!=null && files.length>0){        for (File file : files) {            if(file.isDirectory()){                //递归                listDir(file);            }            else {                System.out.println(file.getAbsolutePath());            }        }    }}

Prorerties

  • 属性集合

  • 特点:

  1. 存储属性名和属性值
  2. 属性名和属性值都是字符串类型
  3. 没有泛型
  4. 继承Hashtable集合,具体看集合那一章笔记
  5. 和流有关
//        创建集合        Properties properties = new Properties();//        添加数据        properties.setProperty("username","zhangsan");        properties.setProperty("age","20");        System.out.println(properties.toString());        //遍历//        1.keySet遍历//        properties.keySet();//         2.entrySet遍历//        3.stringPropertyNames变量        Set set = properties.stringPropertyNames();        for (String s : set) {            System.out.println(s+":"+properties.getProperty(s));        }//        和流有关的办法//        list方法          PrintWriter pw = new PrintWriter("d://aa.txt");        //将properties写入该文件            properties.list(pw);            pw.close(); //store方法保存写入该文件        FileOutputStream fos = new FileOutputStream("d://aa.txt");        properties.store(fos,"这是注释");        fos.close();/*{age=20, username=zhangsan}age:20username:zhangsan
Properties properties1 = new Properties();FileInputStream fis = new FileInputStream("d://aa.txt");properties1.load(fis);fis.close();System.out.println(properties1.toString());//{age=20, username=zhangsan}