文章目录

  • 一、流的概念
  • 二、流的分类
  • 三、字节流
  • 文件字节流
  • 复制文件
  • 字节缓冲流
  • 四、对象流
  • 序列化与反序列化
  • 序列化
  • 反序列化
  • 序列化和反序列化的注意事项
  • 六、字符编码
  • 七、字符流
  • 文件字符流
  • 复制文件
  • 字符缓冲流
  • PrintWriter 打印流
  • 转换流
  • 八、File类
  • File类的使用
  • 递归遍历和递归删除
  • Properties


一、流的概念

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

java 恶心 javai_java


水借助管道传输 = 数据借助流传输。

二、流的分类

  • 按方向【重点】
  • 输入流:将<存储设备>中的内容读到<内存>中。
  • 输出流:将<内存>中的内容写到<存储设备>中。

java 恶心 javai_java 恶心_02

  • 按单位
  • 字节流:以字节为单位,可以读写所有数据
  • 字符流:以字符为单位,只能读写文本数据。
  • 按功能
  • 节点流:具有实际传输数据的读写功能。
  • 过滤流:在节点流的基础之上增强功能。

三、字节流

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

  • InputStream 字节输入流
public int read(){}
public int read(byte[] b){}
public int read(byte[] b, int off, int len){}
  • OutputStream 字节输出流
public void write(int n){}
public void write(byte[] b){}
public void write(byte[] b, int off, int len){}

文件字节流

  • 文件输入流FileInputStream :
  • public int read(byte[] b):从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件的尾部,则返回-1。
public static void main(String[] args) throws Exception{
        //文件字节输入流FileInputStream的使用
        //1 创建FileInputStream 并指定文件路径
        FileInputStream fis = new FileInputStream("d:\\aaa.txt");

        //2 读取文件
        //fis.read();

        //2.1 单字节读取
        //int data = 0;
        //while((data = fis.read()) != -1){
        //    System.out.print((char)data);//helloworld
        //}
        //2.2 一次读取多个字节
        byte[] buf = new byte[4]; // 大小为4的缓存区
        //int count = fis.read(buf); // 一次读4个
        //System.out.println(new String(buf));//hell
        //System.out.println(count);//4
        //int count2 = fis.read(buf); // 再读4个
        //System.out.println(new String(buf));//owor
        //System.out.println(count2);//4
        //int count3 = fis.read(buf); // 再读4个
        //System.out.println(new String(buf));//ldor
        //System.out.println(new String(buf, 0, count3));
        //System.out.println(count3);//2  实际上就读取了两个!!!

        //上述优化后
        int count4 = 0;
        while((count4 = fis.read(buf)) != -1){
            System.out.println(new String(buf, 0, count4));
        }
        //hell
        //owor
        //ld

        //3 关闭
        fis.close();
    }
  • 文件输出流FileOutputStream :
  • public void write(byte[] b){}:一次写多个字节,将b数组中所有字节,写入输出流。
public static void main(String[] args) throws Exception{
        //FileOutputStream文件字节输出流
        // 1 创建文件字节输出流
        FileOutputStream fos = new FileOutputStream("d:\\bbb.txt", true);// true表示不覆盖 接着写
        // 2 写入文件
        fos.write(97);
        fos.write('b');
        String string = "helloworld";
        fos.write(string.getBytes());
        // 3 关闭
        fos.close();
    }

java 恶心 javai_System_03

复制文件

public static void main(String[] args) throws Exception{
        //使用文件字节流来实现文件的复制
        //1 创建流
        //1.1 文件字节输入流
        FileInputStream fis = new FileInputStream("d:\\loading.gif");
        //1.2 文件字节输出流
        FileOutputStream fos = new FileOutputStream("d:\\loading1.gif");
        //2 一边读一边写
        byte[] buf = new byte[1024];
        int count = 0;
        while((count = fis.read(buf)) != -1){
            fos.write(buf, 0, count);
        }
        //3 关闭
        fis.close();
        fos.close();
    }

字节缓冲流

缓冲流:BufferedInputStream/ BufferedOutputStream

  • 提高IO效率,减少访问磁盘次数。
  • 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close。
public static void main(String[] args) throws Exception{
        //使用字节缓冲流读取文件
        //1 创建BufferedInputStream
        FileInputStream fis = new FileInputStream("d:\\aaa.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);

        //2 读取
        //int data = 0;
        //while((data = bis.read()) != -1){
        //    System.out.println((char)data);
        //}
        //用自己创建的缓冲流
        byte[] buf = new byte[1024];
        int count = 0;
        while((count = bis.read(buf)) != -1){
            System.out.println(new String(buf, 0, count));
        }

        //3 关闭  关闭缓冲流,内部就会自动关闭文件输入流!
        bis.close();
    }
public static void main(String[] args) throws Exception{
        //使用字节缓冲流写入文件
        //1 创建BufferedInputStream
        FileOutputStream fos = new FileOutputStream("d:\\buffer.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        //2 写入文件
        for(int i = 0; i < 10; i ++){
            bos.write("helloworld\r\n".getBytes());// 内容没有超过8k的话,都是先写入8k缓冲区!
            // \r\n 为换行
            bos.flush(); //刷新到硬盘
        }
        //3 关闭
        bos.close();//实际上内部也会调用flush()方法
    }

四、对象流

对象流:ObjectOutputStream / ObjectInputStream

  • 增强了缓冲区功能。
  • 增强了读写8种基本数据类型和字符串的功能。
  • 增强了读写对象的功能。
  • readObject()从流中读取一个对象(反序列化)。
  • writeObject(Object obj)向流中写入一个对象(序列化)。
  • 使用流传输对象的过程称为序列化、反序列化

序列化与反序列化

序列化

public static void main(String[] args) throws Exception{
        //使用ObjectOutputStream实现序列化(写入文件的操作)
        //1 创建对象流
        FileOutputStream fos = new FileOutputStream("d:\\stu.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //2 序列化(写入操作)
        //要求:序列化的对象必须要实现Serializable接口!!
        Student zhangsan = new Student("zs", 20);
        oos.writeObject(zhangsan);
        //3 关闭
        oos.close();
        System.out.println("序列化完毕");
    }
//java.io.NotSerializableException
//实现Serializable,仅仅是标志这个类可以序列化
//这个接口本身没有任何方法
public class Student implements Serializable {
    private String name;
    private int age;
    //get和set、构造方法、toString()
}

反序列化

public static void main(String[] args) throws Exception{
        //使用ObjectInputSteam实现反序列化(读取重构对象=文件读到内存当中,重新构成一个对象)
        //1 创建对象流
        FileInputStream fis = new FileInputStream("d:\\stu.bin");
        ObjectInputStream ois = new ObjectInputStream(fis);
        //2 读取文件(反序列化)
        Student s = (Student)ois.readObject();
        //Student s2 = (Student)ois.readObject();//多次读取就会报错 java.io.EOFException
        //3 关闭
        ois.close();//关闭了ObjectInputStream,内部就自动关闭了文件输入流
        System.out.println("执行完毕");
        System.out.println(s.toString());//Student{name='zs', age=20}
    }

序列化和反序列化的注意事项

  • 某个类要想序列化必须实现Serializable接口。
  • 序列化类中对象属性private address address;//一个类也要求实现Serializable接口。
  • 序列化版本号IDprivate static final long serialVersionUID = 1L;,保证序列化的类和反序列化的类是同一个类。
  • 使用transient(瞬间的)修饰属性,这个属性就不能序列化。private transient int age;
  • 静态属性不能序列化。public static String country="中国";
  • 序列化多个对象,可以借助集合来实现。
public static void main(String[] args) throws Exception{
        //使用ObjectOutputStream实现序列化多个对象
        //1 创建对象流
        FileOutputStream fos = new FileOutputStream("d:\\stu.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //2 序列化(写入操作)
        //序列化的对象要继承Serializable!!
        Student zhangsan = new Student("zs", 20);
        Student lisi = new Student("lisi", 20);
        ArrayList<Student> list=new ArrayList<>();
        list.add(zhangsan);
        list.add(lisi);
        oos.writeObject(list);
        //3 关闭
        oos.close();
        System.out.println("序列化完毕");
    }

	    public static void main(String[] args) throws Exception{
        //使用ObjectInputSteam实现反序列化
        //1 创建对象流
        FileInputStream fis = new FileInputStream("d:\\stu.bin");
        ObjectInputStream ois = new ObjectInputStream(fis);
        //2 读取文件(反序列化)
        ArrayList<Student> list=(ArrayList<Student>) ois.readObject();
        //3 关闭
        ois.close();//关闭了ObjectInputStream,内部就自动关闭了文件输入流
        System.out.println("执行完毕");
        System.out.println(list.toString());
        //[Student{name='zs', age=0}, Student{name='lisi', age=0}]
    }

六、字符编码

  • ISO-8859-1:收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。(采用一个字节来表示,最多可以表示256个字符)
  • UTF-8 :针对Unicode码表的可变长度字符编码
  • GB2312:简体中文
  • GBK:简体中文、扩充
  • BIG5:台湾,繁体中文

当编码方式和解码方式不一致时,会出现乱码。

七、字符流

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

  • Reader :字符输入流
public int read(){}
public int read(char[] c){}
public int read(char[] b, int off, int len){}
  • Writer: 字符输出流
public void write(int n){}
public void write(String str){}
public void write(char[] c){}

文件字符流

FileReader文件字符输入流:
- public int read(char[] c):从流中读取多个字符,将读到内容存入c数组,返回实际读到的字符数;如果达到文件的尾部,则返回-1。

public static void main(String[] args) throws Exception{
        //使用FileReader读取文件(中文字符)
        //1 创建FileReader 文件字符输入流 既可以读取中文,也可以读取英文的!!
        FileReader fr = new FileReader("d:\\aaa.txt");
        //2 读取
        //2.1 单个字符读取
        //int data = 0;
        //while((data = fr.read()) != -1){
        //    System.out.println((char)data);// 读取一个字符
        //}
        char[] buf = new char[1024];// 字符缓冲区读取
        int count = 0;
        while((count = fr.read(buf)) != -1){
            System.out.println(new String(buf, 0, count));//好好学习
        }
        //3. 关闭
        fr.close();
    }

FileWriter文件字符输出流:
- public void write(String c){}:一次写多个字符,将字符串c中所有字符,写入输出流。

public static void main(String[] args) throws Exception{
        //FileWriter 文件字符输出流的使用
        //使用FileWriter写入文件
        //1 创建FileWriter对象
        FileWriter fw = new FileWriter("d:\\write.txt");
        //2 写入
        for(int i = 0; i < 10; i ++){
            fw.write("好好学习");
            fw.flush();
        }
        //3 关闭
        fw.close();
        System.out.println("执行完毕");
    }

复制文件

使用FileReader和FileWriter只能复制文本文件,不能复制图片或二进制文件,但是可以使用字节流可以复制任意文件!!!

  • 原因:因为字符流读取是有字符编码的,而图片的本质就是二进制文件。字符流在读取图片时,会把读取到的二进制转换有字符编码的字符,而二进制本身并没有编码,这可能会导致读取出乱码,所以不能读取没有字符编码的文件。
public static void main(String[] args) throws Exception{
        //1. 创建
        FileReader fr = new FileReader("d:\\write.txt");
        FileWriter fw = new FileWriter("d:\\write1.txt");
        //2. 读写
        int data = 0;
        while((data = fr.read()) != -1){
            fw.write(data);
            fw.flush();
        }
        //3. 关闭
        fr.close();
        fw.close();
    }

字符缓冲流

缓冲流:BufferedReader / BufferedWriter

  • 高效读写
  • 支持输入换行符
  • 可一次写一行读一行

BufferedReader :

public static void main(String[] args) throws Exception{
        //使用字符缓冲流读取文件
        //1 创建缓冲流
        FileReader fr = new FileReader("d:\\write.txt");
        BufferedReader br = new BufferedReader(fr);
        //2 读取
        //2.1 第一种方式
        //char[] buf = new char[1024];
        //int count = 0;
        //while((count = br.read(buf)) != -1){
            //System.out.println(new String(buf, 0, count));
        //}
        //2.2 第二种方式 一行一行读取
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }

        //3 关闭
        br.close();
    }

BufferedWriter:

public static void main(String[] args) throws Exception{
        //BufferedWriter的使用
        //1 创建BufferedWriter对象
        FileWriter fw = new FileWriter("d:\\buffer.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        //2 写入
        for(int i = 0; i < 10; i ++){
            bw.write("好好学习");
            bw.newLine(); // 写入一个换行符
            bw.flush();
        }
        //3 关闭
        bw.close(); //此时会自动关闭fw
    }

PrintWriter 打印流

PrintWriter

  • 封装了print()/ println()方法 支持写入后换行。
  • 支持数据原样打印。
public static void main(String[] args)  throws Exception{
        //PrintWriter的使用
        //1 创建打印流
        PrintWriter pw = new PrintWriter("d:\\print.txt");
        //2 打印
        pw.println(97);
        pw.println(true);
        pw.println(3.14);
        pw.println('a');
        //3 关闭
        pw.close();
    }

java 恶心 javai_序列化_04

转换流

桥转换流 InputStreamReader/ OutputStreamWriter

  • 可将字节流转换为字符流。
  • 可设置字符的编码方式。

InputStreamReader :字节流–>字符流

public static void main(String[] args) throws Exception{
        //使用FileInputStream读取文件,指定使用的编码
        //1 创建InputStreamReader对象
        FileInputStream fis = new FileInputStream("d:\\write.txt");
        InputStreamReader isr = new InputStreamReader(fis, "utf-8");
        //注意:文件的编码和读取的编码要一致!否则会乱码
        //2 读取文件
        int data = 0;
        while((data = isr.read()) != -1){
            System.out.print((char)data);
        }
        //3 关闭
        isr.close();
    }

OutputStreamWriter:字符流–>字节流

public static void main(String[] args) throws Exception{
        //使用OutputStreamWriter写入文件,并指定编码
        //1 创建OutputStreamReader对象
        FileOutputStream fos = new FileOutputStream("d:\\info.txt");
        OutputStreamWriter osw = new  OutputStreamWriter(fos, "utf-8");
        //2 写入
        for(int i = 0; i < 10; i ++){
            osw.write("好好学习,天天向上");
            osw.flush();
        }
        //3 关闭
        osw.close();
    }

八、File类

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

  • createNewFile()创建一个新文件
  • mkdir()创建一个新目录
  • delete()删除文件或空目录
  • exists()判断File对象所代表的文件或文件夹是否存在
  • getAbsolutePath()获取文件的绝对路径
  • getName()获取文件名,注意会带文件后缀
  • getParent()获取文件/目录所在的目录
  • isDirectory()判断是否是目录
  • isFile()是否为文件
  • length()获取文件的长度
  • listFiles()列出目录中的所有内容
  • renameTo()修改文件名为
  • deleteOnExit()jvm退出后删除文件
  • canWrite()判断文件是否可写入

FileFilter接口:

@FunctionalInterface
public interface FileFilter {
    boolean accept(File pathname);
}

当调用File类中的listFiles()方法时,支持传入FileFilter接口实现类,对获取文件进行过滤,只有满足条件的文件才可出现在listFiles()的返回值中。

File类的使用

/*
File类的使用
1 分隔符
2 文件操作
3 文件夹操作
*/
public class Demo01 {
    public static void main(String[] args) throws Exception{
        separator();
        fileOpen();
        directoryOpe();
    }

    //1 分隔符
    public static void separator(){
        System.out.println("路径分隔符:" + File.pathSeparator);//
        System.out.println("名称分隔符:" + File.separator);//
    }
    //2 文件操作
    public static void fileOpen() throws  Exception{
        //1 创建文件 createNewFile()
        File file=new File("d:\\file.txt");//创建文件对象
        System.out.println(file.toString());
        if(!file.exists()){// 是否存在
            boolean b = file.createNewFile();//创建文件
            System.out.println("创建结果:"+b);
        }

        //2 删除文件
        //2.1 直接删除
        //file.delete();//成功true
        //2.2 使用jvm退出时删除
        //file.deleteOnExit();
        //Thread.sleep(5000);

        //3 获取文件信息
        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()).toLocaleString());

        //4 判断
        System.out.println("是否可写:" + file.canWrite());
        System.out.println("是否是文件:" + file.isFile());
        System.out.println("是否隐藏:" + file.isHidden());
    }

    //文件夹操作
    public static void directoryOpe() throws Exception{
        //1 创建文件夹
        File dir = new File("d:\\aa\\bb\\cc");
        System.out.println(dir.toString());
        if(!dir.exists()){
            //dir.mkdir();//只能创建单级目录
            dir.mkdirs();//创建多级目录
        }

        //2 删除文件夹
        //2.1 直接删除  只能删除空目录!!
        //dir.delete();//只能删除最底层空目录=删除cc目录 前提:cc目录必须是空目录
        //2.2 使用jvm删除
        //dir.deleteOnExit();

        //3 获取文件夹信息
        System.out.println("获取绝对路径:" + dir.getAbsolutePath());
        System.out.println("获取路径:" + dir.getPath());
        System.out.println("获取文件夹名称:" + dir.getName());
        System.out.println("获取父目录:" + dir.getParent());
        //System.out.println("获取文件长度:" + dir.length());//文件夹没有长度!!!
        System.out.println("文件夹创建时间:" + new Date(dir.lastModified()).toLocaleString());

        //4 判断
        System.out.println("是否是文件夹:" + dir.isFile());
        System.out.println("是否隐藏:" + dir.isHidden());

        //5 遍历文件夹
        //第一种方式
        File dir2 = new File("d:\\图片");
        String[] files = dir2.list();
        for(String string : files){
            System.out.println(string);
        }

        //第二种方式
        //FileFilter接口的使用
        File[] files2 = dir2.listFiles(new FileFilter(){
            
            @Override
            public boolean accept(File pathname){
                if(pathname.getName().endsWith(".jpg")){
                    return true;
                }
                return false;
            }
        });
        for(File file : files2){
            System.out.println(file.getName());
        }
    }
}

递归遍历和递归删除

public class Demo02 {
    public static void main(String[] args) {
        listDir(new File("d:\\j2ee"));
        //deleteDir(new File("d:\\j2ee"));
    }

    //递归遍历文件夹
    public static void listDir(File dir) {
        File[] files = dir.listFiles();
        System.out.println(dir.getAbsolutePath());
        if (files != null && files.length > 0) {
            for (File file : files) {
                if (file.isDirectory()) {
                    listDir(file);//递归
                } else {
                    System.out.println(file.getAbsolutePath());
                }
            }
        }
    }

    //递归删除文件夹
    public static void deleteDir(File dir){
        File[] files = dir.listFiles();
        if(files != null && files.length > 0){
            for(File file : files){
                if(file.isDirectory()){
                    deleteDir(file);//递归
                }else{
                    // 删除文件
                    System.out.println(file.getAbsolutePath() + "删除" + file.delete());
                }
            }
        }
        //删除文件夹
        System.out.println(dir.getAbsolutePath() + "删除" + dir.delete());
    }
}

Properties

Properties:属性集合,线程安全。
特点

  • 存储属性名和属性值(键值对)。
  • 属性名和属性值都是字符串类型。
  • 没有泛型。
  • 和流有关。
public static void main(String[] args) throws IOException {
        //Properties集合的使用
        //1 创建集合
        Properties properties = new Properties();
        //2 添加数据
        properties.setProperty("username", "fashi");
        properties.setProperty("age", "20");
        System.out.println(properties.toString());//{age=20, username=fashi}
        //3 遍历  keySet  entrySer  stringPropertyNames
        Set<String> strings = properties.stringPropertyNames();//属性名集合
        for (String string : strings) {
            System.out.println("Key:"+string+";"+properties.getProperty(string));
        }
        //Key:age;20
		//Key:username;fashi

        //和流有关的方法
        //4 打印 list方法
        PrintWriter pw = new PrintWriter("d:\\pro.txt");
        properties.list(pw);
        pw.close();
        //5 保存  store方法
        FileOutputStream fos = new FileOutputStream("d:\\pro.properties");
        properties.store(fos, "注释");
        fos.close();
        //6 加载 load方法
        Properties properties2 = new Properties();
        FileInputStream fis=new FileInputStream("d:\\pro.properties");
        properties2.load(fis);
        fis.close();
        System.out.println(properties2.toString());//{age=20, username=fashi}
    }

pro.txt:

java 恶心 javai_System_05


pro.properties:

java 恶心 javai_反序列化_06