java文件和流的相关知识点总结

  • 文件类File
  • 构造方法
  • 常用方法
  • 斐波那契数列
  • 递归遍历文件夹
  • IO
  • 流Stream
  • 流的分类
  • 字节输入流InputStream
  • 字节输出流OutputStream
  • 字符输入流Reader
  • 字符输出流Writer
  • 流的四个父类的特点
  • FileInputStream文件字节输入流(掌握)
  • 构造方法
  • 常用方法
  • FileOutputStream文件字节输出流(掌握)
  • 构造方法
  • 常用方法
  • 使用FileInputStream和FileOutputStream读写时的注意事项
  • 使用FileInputStream和FileOutputStream实现单文件的复制
  • 文件夹的复制
  • FileReader文件字符输入流
  • 构造方法
  • 常用方法
  • FileWriter文件字符输出流
  • 构造方法
  • 常用方法
  • BufferedReader缓冲字符输入流(掌握)
  • 构造方法
  • 常用方法
  • 读取文本练习
  • BufferedWriter缓冲字符输出流(掌握)
  • 构造方法
  • 常用方法
  • 写入文本练习
  • ObjectOutputStream对象字节输出流(序列化)(掌握)
  • 构造方法
  • 常用方法
  • ObjectInputStream对象字节输入流(反序列化)(掌握)
  • 构造方法
  • 常用方法
  • 序列化和反序列化案例
  • 转换流
  • OutputStreamWriter
  • InputStreamReader
  • 转换流的使用


文件类File

Java中的File类,表示本地硬盘中的文件(文件和目录)的一个类。

通过这个类创建的对象,可以操作对应的文件。

构造方法

常用构造方法

说明

File(String pathName)

根据文件的完整路径创建File对象

File(String parent,String child)

根据文件的父目录路径和自身路径创建File对象

File(File parent,String child)

根据文件的父目录对应的File对象和自身路径创建File对象

//如想要表示 “F:\221001\笔记\面向对象部分回顾.pdf”  这个文件

//File(String pathName)
File file1 = new File("F:\\221001\\笔记\\面向对象部分回顾.pdf");

//File(String parent,String child)
File file2 = new File("F:\\221001\\笔记", "面向对象部分回顾.pdf");

//File(File parent,String child)
File parent = new File("F:\\221001\\笔记");
File file3 = new File(parent, "面向对象部分回顾.pdf");

//file1、file2、file3都表示同一个文件

常用方法

常用方法

说明

exists()

判断文件是否存在

isFile()

判断是否为文件

isDirectory()

判断是否为目录

getName()

获取文件名

getPath()

获取文件相对路径

getAbsolutePath()

获取文件绝对路径

getParent()

获取父目录的名称

getParentFile()

获取父目录对象

lastModified()

获取最后一次修改时间对应的毫秒数

length()

获取文件所占字节

isHidden()

判断文件是否隐藏

delete()

删除文件或空目录

renameTo(File newFile)

将原文件重命名且移动到指定目录

mkdir()

创建目录

list()

获取某个目录下的第一层子文件的名称的数组

listFiles()

获取某个目录下的第一层子文件对象的数组

斐波那契数列

package com.hqyj.FileTest;

public class Test2 {
    public static void main(String[] args) {
        //兔子问题
        //有一对兔子在第三个月开始,每个月都能生一对小兔子
        //如果所有兔子不死亡,且每次生下的都是一雌一雄,问10个月后共有多少对兔子
        //1月    2月  3月  4月  5月  6月  7月  8月  9月  10月
        //1     1    2    3    5   8    13   21   34   55
        //斐波那契数列
        //f(n)=f(n-1)+f(n-2)  n>2
        Test2 t = new Test2();
        System.out.println(t.f(20));
    }

    /*
     * 递归方法
     * */
    public int f(int n) {
        if (n > 2) {
            return f(n - 1) + f(n - 2);
        }
        return 1;
    }
}

递归遍历文件夹

package com.hqyj.FileTest;

import java.io.File;
import java.util.Date;

public class Test3 {
    //查看某个目录下的所有文件
    public static void main(String[] args) {

        File source = new File("E:\\adobe");


        Test3 t = new Test3();
        t.fun(source);

    }

    /*
     * 递归遍历文件夹
     * */
    public void fun(File source) {
        //输出某个目录中超过3个月未使用且大于500MB的文件
        /*
        long start = source.lastModified();
        long end = System.currentTimeMillis();
        if ((end - start) / 1000 / 3600 / 24 > 90 && source.length() / 1024 / 1024 > 500) {
            System.out.println(source.getName() + "\t" + new Date(source.lastModified()) + "\t" + source.length() / 1024 / 1024);
        }*/

        //判断是否为目录
        if (source.isDirectory()) {
            //将其展开
            for (File child : source.listFiles()) {
                //因为子文件有可能是目录,继续调用本方法
                fun(child);
            }
        }
    }
}

IO

I:Input输入

O:Output输出

流Stream

在Java中,流用于表示计算机硬盘与内存之间传输数据的通道。

内存中的数据存入到硬盘中,称为写write,也称为输出Output

硬盘中的数据存入到内存中,称为读read,也称为输入Input

流的分类

Java中将流定义为类,以对象的形式表现流。流有"四大家族",是所有流的父类。

字节输入流InputStream

FileInpuStreamObjectInputStream

字节输出流OutputStream

FileOutputStreamObjectOutputStream

字符输入流Reader

FileReader、BufferedReader、OutputStreamWriter

字符输出流Writer

FileWriter、BufferedWriter、InputStreamReader

按方向分类

  • 输入流:InputStream、Reader
  • 将硬盘中的数据读取到内存中
  • 输出流:OutputStream、Writer
  • 将内存中的数据写入到硬盘中

按类型分

  • 字节流:InputStream、OutputStream
  • 读写非文本类型文件。如图片、音视频、其他文件等。
  • 字符流:Reader、Writer
  • 读写纯文本类型文件。如txt、md等

如要将硬盘中某个txt文件中的内容读取到程序中,使用Reader

如要将硬盘中的某个图片读取到程序中,使用InputStream

如要将程序中的文本写入到硬盘中为txt类型文件时,使用Writer

如要将程序中的数据写入到硬盘中为非文本文件时,使用OutputStream

流的四个父类的特点

  • 这四个父类都是在java.io包下,都是抽象类,不能直接创建其对象,使用其子类创建对象
  • 这四个父类中都定义了close()方法,用于关闭流对象,释放资源
  • 输入流(InputStream和Reader)都有read()方法读取数据到内存中,输出流都有write()方法写入数据到硬盘中
  • 输出流(OutputStream和Writer)都有flush()方法,用于将流中的数据冲刷到硬盘中
  • 在使用输出流对象时,一定要调用flush()或close()方法后,才能真正将数据写入到硬盘中
  • 所有的流中,以Stream结尾,都是字节流,数据以字节传输;以Reader或Writer结尾的,都是字符流,数据以字符传输
  • 读取硬盘中的数据,使用输入流,读取的文件必须存在;将数据写入到硬盘中,使用输出流,文件可以不存在,但父目录必须存在。
  • 读入或写入文本时,使用字符流;读取或写入非文本时,使用字节流

FileInputStream文件字节输入流(掌握)

按字节读取硬盘中的文件。

构造方法

常用构造方法

说明

FileInputStream(String pathName)

根据文件名创建流对象

FileInputStream(File file)

根据文件对象创建流对象

常用方法

常用方法

说明

read()

读取一个字节,返回读取到的字节

read(byte[] bytes)

按字节数组读取,返回读取到的字节数量,读取到的内容保存在字节数组中

close()

关闭流对象

FileOutputStream文件字节输出流(掌握)

按字节将内存中的数据写入到硬盘中。

构造方法

常用构造方法

说明

FileOutputStream(String pathname)

根据文件名创建输出流对象,写入时覆盖原内容

FileOutputStream(String pathname,boolean append)

根据文件名创建输出流对象,第二个参数为true,写入时追加在原内容之后

FileOutputStream(File file)

根据文件对象创建输出流对象,写入时覆盖原内容

FileOutputStream(File file,boolean append)

根据文件对象创建输出流对象,第二个参数为true,写入时追加在原内容之后

常用方法

常用方法

作用

write(int i)

写入一个指定字节

write(byte[] bytes)

写入一个字节数组

write(byte[] bytes,int off,int len)

写入字节数组中从off开始的len个字节

flush()

将流中的数据冲刷到硬盘中

close()

关闭流对象

使用FileInputStream和FileOutputStream读写时的注意事项

  • 在通过FileInputStream对象使用read(byte[] bytes)方法时,每次读取指定数组的字节,将读取到的字节保存在字节数组中,该方法返回读取到的字节数量。如果最后一次读取的字节数不足字节数组的大小时,只会将读取到内容覆盖数组中最前的几个元素。所以会导致读取到的内容多于实际内容。
  • 在通过FileOutputStream对象使用write(byte[] bytes)方法时,会将字节数组中的所有内容写入到输出流中,在最后一次写入时,可能会写入多余的内容。所以在写入时,最好使用write(byte[] bytes,int off,int lef)方法,表示将字节数组中的内容,从off开始写入len个。
    如有word.txt文件,其中保存aaabbbccc
FileInputStream fis = new FileInputStream("d:/word.txt");
FileOutputStream fos = new FileOutputStream("d:/copy.txt");

byte[] bytes = new byte[4];
//第一次读取4个字节,即aaab,count为4
int count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);
//第二次读取4个字节,即bbcc,count为4
count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);
//第三次读取1个字节c,覆盖数组中的第一个元素,即数组现在为cbcc,count为1
count=fis.read(bytes);
//写入数组中的全部内容
fos.write(bytes);//最终会写入aaabbbcccbcc
fos.write(bytes,0,count);//这样最后一次只会写入实际读取到的c

fos.close();
fis.close();

使用FileInputStream和FileOutputStream实现单文件的复制

package com.hqyj.IOTest;

import java.io.*;

public class CopyFile {
    public static void main(String[] args) throws IOException {
        //定义原文件和目标文件
        File source = new File("F:\\221001\\录屏\\FileInputStream和FileOutputStream.mp4");
        File target = new File("F:\\221001\\copy.mp4");

        //定义文件字节输入流,用于读取原文件
        FileInputStream fis = new FileInputStream(source);
        //定义文件字节输出流,用于写入文件
        FileOutputStream fos = new FileOutputStream(target);


        /*
        //调用无参的read()方法,表示读取一个字节,返回读取到的字节
        int read = fis.read();
        //如果能读取到内容
        while (read > -1) {
            //将读取到的内容写入到文件中
            fos.write(read);
            //继续读取
            read = fis.read();
        }
        */

        //定义一个字节数组,大小为8MB
        byte[] bytes = new byte[1024 * 1024 * 8];

        //按字节数组读取,返回读取到的字节数量
        int count = fis.read(bytes);
        //循环读取写入
        while (count > -1) {
            //将读取的字节数组写入到文件中
            // fos.write(bytes);//如果调用该方法,最后一次会多写入上一次残留的数据
            fos.write(bytes,0,count);//如果调用该方法,实际读取到了多少字节就写入多少
            count = fis.read(bytes);
        }


        fis.close();
        fos.close();

        if (target.exists()) {
            System.out.println("复制成功");
        }

    }
}

文件夹的复制

package com.hqyj.IOTest;

import java.io.*;

public class CopyDirectory {
    public static void main(String[] args) {


        /*File source = new File("F:\\221001\\录屏\\流的基本概念.mp4");
        File target = new File("F:\\221001\\copy.mp4");
        copyFile(source, target);*/

        File source = new File("F:\\221001\\笔记");
        File target = new File("F:\\221001\\笔记副本");
        /*
         * source    F:\221001\笔记
         * target    F:\221001\笔记副本
         * 1.调用copyDir方法,判断发现source是一个文件夹,创建目标文件夹target:“F:\221001\笔记副本”
         * 2.遍历source,如其中有xxx.md文件,即child
         * 此时的source是F:\221001\笔记\xxx.md,即child
         * 此时的target是F:\221001\笔记副本\xxx.md,用File(File parent,String child)构造方法表示这个目标文件
         * 所以创建File newTarget = new File(target,child.getName())
         *
         * */

        copyDir(source, target);
    }


    /*
     * 定义复制文件夹的方法
     * */
    public static void copyDir(File source, File target) {
        //如果是文件,调用单文件复制的方法
        if (source.isFile()) {
            copyFile(source, target);
        } else {//如果是文件夹
            //创建要复制的目标文件夹
            target.mkdir();
            //展开原文件夹
            for (File child : source.listFiles()) {
                //定义复制后的新目标文件
                //如source为F:\221001\笔记\day1.md时,递归调用的target为F:\221001\笔记副本\day1.md
                File newTarget = new File(target, child.getName());//这里使用File(File parent,String child)构造方法创建target对象
                //递归调用的原文件依然是当前遍历出来的子文件,目标文件就是最终复制的F:\221001\笔记副本\day1.md
                copyDir(child, newTarget);
            }
        }
    }


    /*
     * 定义单文件复制的方法
     * */
    public static void copyFile(File source, File target) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //创建用于输入输出的流对象
            fis = new FileInputStream(source);
            fos = new FileOutputStream(target);
            //定义字节数组
            byte[] bytes = new byte[1024 * 1024 * 8];
            //按数组读取
            int count = fis.read(bytes);
            while (count != -1) {
                fos.write(bytes, 0, count);
                count = fis.read(bytes);
            }
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在" + e);
        } catch (IOException e) {
            System.out.println("读写异常" + e);
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                System.out.println("关闭流对象异常" + e);
            }
        }
    }
}

断点调试执行细节

FileReader文件字符输入流

按字符读取文件。

构造方法

常用构造方法

说明

FileReader(String fileName)

根据文件名创建文件字符输入流对象

FileReader(File file)

根据文件对象创建文件字符输入流对象

常用方法

常用方法

作用

ready()

判断是否还有下一个字符

read()

读取下一个字符,返回读取到的字符

read(char[] chars)

按字符数组读取,返回读取到的字符数量,读取到的字符保存在字符数组中

close()

关闭流对象

FileWriter文件字符输出流

按字符写入文件。

构造方法

常用构造方法

作用

FileWriter(String fileName)

按文件名创建字符输出流对象,覆盖写入

FileWriter(String fileName,boolean append)

按文件名创建字符输出流对象,如果append为true,表示追加写入

FileWriter(File file)

按文件对象创建字符输出流对象,覆盖写入

FileWriter(File file,boolean append)

按文件对象创建字符输出流对象,如果append为true,表示追加写入

常用方法

常用方法

作用

write(String str)

按字符串写入

flush()

将流中的数据冲刷到硬盘中的文件,必须调用该方法或close方法后,才能真正写入

close()

关闭流对象

BufferedReader缓冲字符输入流(掌握)

自带缓冲区(字符数组)的字符输入流。默认字符数组大小为8192,每次最多读取8192个字符。

在读取纯文本文件(txt或md)时,首选该类。

构造方法

常用构造方法

作用

BufferedReader(Reader in)

创建一个带有缓冲区(大小为8192的char数组)的字符输入流对象,参数为Reader类型对象,Reader是抽象类,所以实际参数为Reader的子类,如FileReader,在FileReader对象中定义要读取的文件

BufferedReader(Reader in,int size)

创建一个指定缓冲区(字符数组)大小的字符输入流对象

常用方法

常用方法

作用

ready()

判断是否还有字符

readLine()

读取整行字符

close()

关闭流对象

读取文本练习

package com.hqyj.ReaderAndWriter;

import java.io.*;

public class Test2 {
    public static void main(String[] args) throws IOException {

        /*
        File file = new File("F:\\221001\\笔记\\Java基础回顾.md");
        //FileReader(File file)
        Reader fr = new FileReader(file);
        //BufferedReader(Reader in)
        BufferedReader br = new BufferedReader(fr);
        */

        //创建带有缓冲区的字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("F:\\221001\\笔记\\Java基础回顾.md"));
        //循环判断是否还有字符
        while (br.ready()) {
            //读取整行
            System.out.println(br.readLine());
        }
        //关闭最大的流对象即可
        br.close();
    }
}

BufferedWriter缓冲字符输出流(掌握)

自带缓冲区(字符数组)的字符输出流

构造方法

常用构造方法

说明

BufferedWriter(Writer writer)

创建一个自带缓冲区的字符输出流对象,参数为一个Writer对象,Writer是一个抽象类,实际参数为Writer的子类,如FileWriter,在FileWriter中定义要将输入写入的目标文件

BufferedWriter(Writer writer,int size)

创建一个指定缓冲区大小的字符输出流对象

常用方法

常用方法

作用

write(String str)

写入字符串

newLine()

换行

flush()

冲刷流中的数据到硬盘

close()

关闭流对象

写入文本练习

package com.hqyj.ReaderAndWriter;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.SimpleFormatter;

public class Test3 {
    public static void main(String[] args) throws IOException {

        File file = new File("221001.txt");
        //创建缓冲字符输入流对象,读取文本
        BufferedReader br = new BufferedReader(new FileReader(file));
        //创建集合,保存读取到的姓名
        ArrayList<String> list = new ArrayList<>();
        //循环读取文件中的所有字符
        while (br.ready()) {
            String name = br.readLine();
            list.add(name);
        }
        //关闭
        br.close();
        //打乱集合中的元素
        Collections.shuffle(list);


        //创建日期字符串
        String today = new SimpleDateFormat("yyyy.MM.dd").format(new Date());
        //创建缓冲字符输出流,用于写文本,文件名为"日期+作业情况.txt",如果每次都是新建,这样写
        // BufferedWriter bw = new BufferedWriter(new FileWriter(today + "作业情况.txt"));
        //如果要追加,在new FileWriter("文件名",true)设置
        BufferedWriter bw = new BufferedWriter(new FileWriter(today + "作业情况.txt",true));
        //写入字符串
        bw.write("姓名\t\t是否完成");
        //换行
        bw.newLine();


        Scanner sc = new Scanner(System.in);
        //随机3个人
        for (int i = 0; i < 3; i++) {
            String name = list.get(i);
            System.out.println(name + "完成情况:");
            String str = sc.next();
            //写入读取到的内容
            bw.write(name + "\t\t" + str);
            //换行
            bw.newLine();
        }

        bw.close();
    }
}

ObjectOutputStream对象字节输出流(序列化)(掌握)

序列化:将对象转换为文件的过程

被序列化的对象,必须要实现Serializable接口。

这个接口是一个特殊的接口,没有定义任何方法,只是给该类加上标记,表示该类可以被序列化

构造方法

构造方法

说明

ObjectOutputStream(OutputStream os)

创建一个对象字节输出流对象,参数为一个字节输出流对象,由于OutputStream是抽象类,所以使用其子类,如FileOutputStream对象,在其中定义要写入的文件

常用方法

常用方法

作用

writeObject(Object obj)

将一个对象写入到本地文件中

close()

关闭流对象

ObjectInputStream对象字节输入流(反序列化)(掌握)

反序列化:将文件转换为对象的过程

构造方法

常用构造方法

说明

ObjectInputStream(InputStream is)

创建一个对象字节输入流对象,参数为一个字节输入流对象,由于InputStream是抽象类,所以使用其子类,如FileInputStream对象,在其中定义要读取的文件

常用方法

常用方法

作用

readObject()

读取序列化后的文件,返回类型为Object

close()

关闭流对象

序列化和反序列化案例

Person类,实现Serializable接口

package com.hqyj.ObjectStream;

import java.io.Serializable;
/*
* 如果希望该类的对象能序列化,写入对象到本地,必须要实现Serializable接口
* Serializable接口中没有任何方法,是一个标记接口,表示该类的对象可以被序列化
* */
public class Person implements Serializable {
    private String name;
    private int age;
    private String sex;

 	//省略getter/setter和toString()
}

Main类

package com.hqyj.ObjectStream;

import java.io.*;
import java.util.ArrayList;

public class Test1 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person p1 = new Person("王海", 22, "男");
        Person p2 = new Person("赵敏", 24, "女");
        Person p3 = new Person("刘涛", 21, "女");
        ArrayList<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);

        //创建OutStream的实现类,设置写入的文件路径
        OutputStream os = new FileOutputStream("F:\\221001\\person.p");
        //创建对象输出字节流,参数为OutStream类型
        ObjectOutputStream oos = new ObjectOutputStream(os);
        //调用writeObject(Object obj)方法,将对象写入到硬盘中(序列化)
        oos.writeObject(list);

        oos.close();

        //创建对象输入字节流,将上一步保存的文件进行反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F:\\221001\\person.p"));

        //使用readObject()方法,将写入的文件进行读取(反序列化)
        ArrayList<Person> pList = (ArrayList<Person>) ois.readObject();

        for (Person person : pList) {
            System.out.println(person);
        }
        ois.close();
    }
}

转换流

实际属于字符流,作用为将一个字节流对象转换为字符流对象

OutputStreamWriter

将字节输出流转换为字符输出流

InputStreamReader

将字节输入流转换为字符输入流

转换流的使用

如果只提供了一个字节流,但要向其中写入或读取字符时,就可以使用转换流将字节流转换为字符流。

使用字符流读写字符时比字节流更方便。

//假如只提供一个字节输出流对象
FileOutputStream fos = new FileOutputStream("文件路径");
//fos.write(97);//这时如果写入数据,只能按字节写入,不方便

//使用转换流,将字节流对象fos转换为字符流对象
Writer writer = OutputStreamWriter(fos);
//将字符流对象writer包装成缓冲字符流对象
BufferedWriter bw = new BufferedWriter(writer);
bw.write("hello你好");
bw.newLine();

bw.close();


//只提供字节输入流对象
FileInputStream fis = new FileInputStream("221001.txt");

// fis.read()每次只能读取一个字节
//将字节流转换为字符流
Reader reader = new InputStreamReader(fis);
//创建缓冲字符流,将字符流包装为缓冲流
BufferedReader br = new BufferedReader(reader);
//整行读取
while (br.ready()) {
    System.out.println(br.readLine());
}
br.close();