IO流

IO流

1 File流

  • 常用方法
public static void main(String[] args) throws IOException {
        // 创建了一个指向E盘下的a.txt的file对象
        // file对象在创建的时候不去检查文件是否存在
        // 只是将当前的路径标记为一个file对象
        File file = new File("E:\\svn\\第一阶段");
        // 创建文件 返回值true表示创建成功
        // 当且仅当这个文件不存在的时候,创建该文件
        // 路径必须真实存在
//        boolean newFile = file.createNewFile();
//        System.out.println(newFile);
        // 创建目录
        // 只能创建一级的目录
//        boolean mkdir = file.mkdir();
//        System.out.println(mkdir);
        // 创建多级目录
//        boolean mkdirs = file.mkdirs();
//        System.out.println(mkdirs);
        // 如果是文件直接删除,如果是目录并且这个目录非空,则删除失败
        // 如果要删除目录,要求目录必须没有内容
        // 从计算机中彻底删除
//        boolean delete = file.delete();
//        System.out.println(delete);

        // 获取所有的一级子文件和子目录
//        File[] files = file.listFiles();
//        for (File file1 : files) {
//            System.out.println(file1);
//        }

        // 判断file是否是文件
        System.out.println(file.isFile());
        // 判断file是否是目录
        System.out.println(file.isDirectory());
    }

课堂练习:删除一个目录

public static void del(File file){
        if (file.isDirectory()){
            // 获取目录中的所有的子目录和子文件
            File[] files = file.listFiles();
            for (File file1 : files) {
                del(file1);
            }
        }
        // 删除目录/文件
        file.delete();
    }

统计工作空间中java文件和class文件的数量

// 统计工作空间中java文件和class文件的数量
    public static void count(File file){
        // 判断是否是目录
        if (file.isDirectory()){
            // 获取子目录
            File[] files = file.listFiles();
            for (File file1 : files) {
                count(file1);
            }
        }else if (file.getName().endsWith(".java")){
            javaCount++;
        }else if (file.getName().endsWith(".class")){
            classCount++;
        }
    }
  • separatorChar 目录分隔符 在windows中是\ ,在linux中是/
  • pathSeparatorChar: 路径分隔符 在windows中是; 在linux中是:
static int javaCount;
    static int classCount;
    public static void main(String[] args) throws IOException {
        // 20250710
        File file = new File("E:\\test\\西游记.txt");
        // 判断文件是否是可执行文件   在windows中只要是可读写的都是可执行文件
//        file.canExecute();
        // 测试是否是可读方法  在windows中只要能打开的文件都是可读
//        file.canRead();
//        file.createNewFile();
//        // 判断文件是否可写
//        System.out.println(file.canWrite());
//        // 判断文件/目录是否存在
//        System.out.println(file.exists());
//        // 获取绝对路径(从盘符开始的路径)
//        System.out.println(file.getAbsolutePath());
//        // 获取剩余空间(单位是字节)
//        System.out.println(file.getFreeSpace());
//        // 获取可用空间
//        System.out.println(file.getUsableSpace());
//        // 获取总空间
//        System.out.println(file.getTotalSpace());
//        // 获取文件名称
//        System.out.println(file.getName());
//        // 获取父目录
//        System.out.println(file.getParent());
//        // 获取路径
//        System.out.println(file.getPath());
//        // 判断是否是绝对路径
//        System.out.println(file.isAbsolute());
//        // 判断是否是隐藏文件
//        System.out.println(file.isHidden());
//        // 获取修改时间
//        System.out.println(file.lastModified());
        //
//        File[] files = file.listFiles(new FileFilter() {
//            // 把所有的子目录和子文件传递过来
//            // 返回true的内容会留在最后的数组中
//            @Override
//            public boolean accept(File pathname) {
//                return pathname.getName().matches(".*\\d.*");
//            }
//        });
//        File[] files = file.listFiles(pathname -> pathname.getName().matches(".*\\d.*"));
//        File[] files = file.listFiles(new FilenameFilter() {
//            // dir  文件所在的父目录
//            // name 文件名
//            @Override
//            public boolean accept(File dir, String name) {
//                return name.matches(".*\\d.*");
//            }
//        });
//        File[] files = file.listFiles(((dir, name) -> name.matches(".*\\d.*")));
//        for (File file1 : files) {
//            System.out.println(file1);
//        }

        // 移动并重命名
//        file.renameTo(new File("E:\\test\\西游记.txt"));
        // 修改最后的修改时间   单位是毫秒
//        file.setLastModified(1000L);
        // 设置是否是只读文件
        file.setReadOnly();
        // 设置是否可写
        file.setWritable(false);
    }

2 IO流概述

IO流:传输数据的一套机制

I: input 输入流

O:output 输出流

输入和输出是参考内存来说的

image-20250711094040361

java中的流分为字节流和字符流

字符流只能处理和字符相关的文本

字节流可以处理任何类型的文件

输入流 输出流
字符流 Reader Writer
字节流 InputStream OutputStream

以上四个都是抽象类,真正使用的应该是它们的子类

3 字符流

3.1 FileWriter

public static void main(String[] args) throws IOException {
        // 字符输出流
        // 创建一个新文件
        // 如果原文件不存在,则使用创建的这个新文件
        // 如果原文件已存在,则使用新文件覆盖原文件
        // append:追加访问
        FileWriter fileWriter = new FileWriter("D:\\a.txt",true);
        // 写出数据
        fileWriter.write("helloworld");
        // 冲刷缓冲区
//        fileWriter.flush();
        // 关闭流  关闭流的时候会自动冲刷一次缓冲区
        fileWriter.close();
        fileWriter = null;
    }
  • 异常处理
// 字符输出流
        // 创建一个新文件
        // 如果原文件不存在,则使用创建的这个新文件
        // 如果原文件已存在,则使用新文件覆盖原文件
        // append:追加访问
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter("D:\\a.txt",true);
            // 写出数据
            fileWriter.write("helloworld");
            // 冲刷缓冲区
//        fileWriter.flush();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            // 关闭流  关闭流的时候会自动冲刷一次缓冲区
            try {
                if (fileWriter != null){
                    fileWriter.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }finally {
                fileWriter = null;
            }
        }
  • JDK1.7 try-with-resources
public static void main(String[] args) throws IOException {

        demo2(new FileWriter("D:\\a.txt"));
    }

    private static void demo2(FileWriter writer) {
        // jdk1.7出现 try-with-resources
        // 运行代码完成之后会自动关流
        // 要求对象对应的类必须实现AutoCloseable接口
        try (writer){
            writer.write("尚马");
        }catch (IOException e){
            e.printStackTrace();
        }
    }

3.2 FileReader

public static void main(String[] args) throws IOException {
        // 字符输入流
        FileReader fileReader = new FileReader("D:\\a.txt");
        // 一次读取一个字符  如果读取不到返回-1
//        int read = fileReader.read();
//        System.out.println((char)read);
        // 以下方式每次读取一个字符,效率较低
//        int ch;
//        while ((ch = fileReader.read()) != -1){
//            System.out.print((char) ch);
//        }

        // 一次读取多个字符 创建缓冲数组
        char[] cs = new char[5];
        int len;
        // 返回值是读取的实际个数  读取不到返回-1
//        int read = fileReader.read(cs);
//        System.out.println(read);
//        System.out.println(cs);
        while ((len = fileReader.read(cs)) != -1){
            System.out.print(new String(cs,0,len));
        }

        // 关流  释放资源
        fileReader.close();
    }

拷贝文件:

// 拷贝文件
        // 创建字符输入流和字符输出流
        FileReader fileReader = new FileReader("D:\\西游记.txt", Charset.forName("gbk"));
        FileWriter fileWriter = new FileWriter("D:\\test\\红楼梦.txt",Charset.forName("gbk"));
        // 读取内容
        // 创建字符数组作为缓冲区
        char[] cs = new char[1024 * 8];
        // 实际读取到的个数
        int len;
        while ((len = fileReader.read(cs)) != -1){
            // 写出到文件中
            fileWriter.write(cs,0,len);
        }

        // 关流  从里向外关
        fileWriter.close();
        fileReader.close();

3.3 BufferedReader和BufferedWriter

这两个类自动具有缓冲区,读取和写入非常高效

BufferedReader属于字符输入流
BufferedWriter属于字符输出流

23种常用的设计模式之一 -- 装饰设计模式

模式:针对某一类问题的统一的处理方法

设计模式:在软件开发中针对遇到的问题所提供的统一的解决方案

装饰设计模式:利用同类对象来构建本类对象,然后对所构建的对象进行功能的改善或者增强

  • BufferedReader
public static void main(String[] args) throws IOException {
        // 创建字符输入流
        FileReader fileReader = new FileReader("D:\\test\\红楼梦.txt", Charset.forName("gbk"));
        // 装饰设计模式
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        // 每次能够读取一行内容,读取到末尾返回null
        // 读取到换行符就结束,不会读取换行符
//        String s = bufferedReader.readLine();
//        System.out.println(s);
        String str;
        while ((str = bufferedReader.readLine()) != null){
            System.out.println(str);
        }

        // 关流
        bufferedReader.close();
        fileReader.close();
    }
  • BufferedWriter
public static void main(String[] args) throws IOException {
        // 创建字符输出流
        FileWriter fileWriter = new FileWriter("D:\\hello.txt");
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        bufferedWriter.write("hellohello");
        // 写出一个换行符
        bufferedWriter.newLine();
        // 关流
        bufferedWriter.close();
        fileWriter.close();
    }
  • 拷贝文件
// 拷贝文件
    private static void demo3() throws IOException {
        // 创建高效字符流
        BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\西游记.txt",Charset.forName("gbk")));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\test\\水浒传.txt",Charset.forName("gbk")));
        String str ;
        while ((str = bufferedReader.readLine()) != null){
            bufferedWriter.write(str);
            bufferedWriter.newLine();
        }
        // 关流 关闭外层流,内层流也会跟着关闭
        bufferedWriter.close();
        bufferedReader.close();
    }
  • 课堂练习:统计工作空间中java代码的行数
//统计工作空间中java代码的行数
    private static int count = 0;// 代码的行数
    private static void demo4(File file) throws IOException {
        if (file.isDirectory()){
            // 获取子目录或者子文件
            for (File listFile : file.listFiles()) {
                demo4(listFile);
            }

        }else if (file.getName().endsWith(".java")){ //判断是否是java文件
            BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
            while (bufferedReader.readLine() != null){
                count++;
            }
            // 关闭 资源
            bufferedReader.close();
        }
    }

4 字节流

字节流可以操作任意类型的文件

private static void demo2() throws IOException {
        // 创建字节输入流
        FileInputStream fileInputStream = new FileInputStream("D:\\a.txt");
        // 读取数据  一次读取一个字节  读取不到返回-1
//        int read = fileInputStream.read();
//        System.out.println((char) read);


        // 一次获取所有需要的长度  OutOfMemoryError
//        byte[] bys = new byte[fileInputStream.available()];
//        int len = fileInputStream.read(bys);
//        System.out.println(len);
//        for (byte by : bys) {
//            System.out.println((char)by);
//        }


        // 返回实际读取到的个数  读取不到返回-1
//        int len = fileInputStream.read(bys);
//        System.out.println(bys);
//        System.out.println(len);
        // 推荐
//        int len;
//        while ((len =  fileInputStream.read(bys)) != -1){
//            System.out.print(new String(bys,0,len));
//        }

        // 读取所有的字节
        byte[] bytes = fileInputStream.readAllBytes();
        for (byte aByte : bytes) {
            System.out.print((char)aByte);
        }

        // 关流
        fileInputStream.close();

    }

    private static void demo1() throws IOException {
        // 创建字节输出流
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
        // 写出数据到文件中
        // 字节流没有缓冲区
        fileOutputStream.write("helloworld".getBytes());
        // 关流
        fileOutputStream.close();
    }
  • 课堂练习:拷贝文件
private static void demo3() throws IOException {
        // 拷贝文件
        // 创建字节输入和输出流
        FileInputStream fileInputStream = new FileInputStream("E:\\jdk-17.0.15_doc-all.zip");
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\jdk17.zip");
        // 创建缓冲数组
        byte[] b = new byte[1024];
        int len;
        while ((len = fileInputStream.read(b)) != -1){
            // 写入数据
            fileOutputStream.write(b,0,len);
        }

        // 关流
        fileOutputStream.close();
        fileInputStream.close();
    }

5 读取内存的流

public static void main(String[] args) throws IOException {
//        String str = "abcdefg";
//        // 创建读取字符串的流
//        StringReader stringReader = new StringReader(str);
//
//        // 循环读取内容
//        char[] cs = new char[3];
//        int len;
//        while ((len = stringReader.read(cs)) != -1){
//            System.out.print(new String(cs,0,len));
//        }
//
//        // 关流
//        stringReader.close();
        StringWriter stringWriter = new StringWriter();
        stringWriter.write("abc");
        // 关流
        stringWriter.close();

//        ByteArrayOutputStream
//        ByteArrayInputStream
//        CharArrayWriter
//        CharArrayReader
    }

6 转换流

    public static void main(String[] args) throws IOException {
        // 转换流就是可以将字节流转换成字符流
        // 底层实际上是依靠传入的字节流来写出数据
        // 输出流
//        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("E:\\abc.txt"));
//        // 写出数据
//        outputStreamWriter.write("abc");
//
//        // 关流
//        outputStreamWriter.close();

        // 输入流
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("E:\\abc.txt"));
        char[] chars = new char[3];
        inputStreamReader.read(chars);
        System.out.println(chars);

        // 关流
        inputStreamReader.close();
    }

7 系统流

System.out 系统输出流
System.in 系统输入流
System.err 系统错误流
    public static void main(String[] args) throws IOException {
        // 一次读取一个字符
        // System.in 字节输入流
//        int read = System.in.read();
//        // System.out 字节输出流
//        System.out.println((char) read);
//        // System.err 字节输出流
//        System.err.println((char) read);

        for (int i = 0; i < 10000; i++) {
            System.out.println('a');
            System.err.println('a');
        }
    }
  • 课堂练习:用已知的流从控制台读取一行数据
//        用已知的流从控制台读取一行数据
        // BufferedReader  能够读取一行
        // System.in       从控制台获取数据
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        // 读取一行数据
        String line = bufferedReader.readLine();
        System.out.println(line);
        // 关流
        bufferedReader.close();

Scanner为什么不关流?

public static void main(String[] args) throws IOException {
        // in是一个静态的流对象
        // 意味着多个Scanner用的是同一个in
        // 一个被关了,其他地方都不可以使用了
        Scanner scanner = new Scanner(System.in);
        String next = scanner.next();
        System.out.println(next);
    }

8 打印流

PrintWriter和PrintStream

只有输出流,没有输入流l

PrintWriter属于字符输出流
PrintStream属于字节输出流

public static void main(String[] args) throws IOException {
        PrintStream printStream = new PrintStream("a.txt");
        // 输出
        printStream.write("尚马".getBytes());
        // 输出并换行
        printStream.println("教育");
        printStream.print("谷丰硕");
        // 关流
        printStream.close();


        PrintWriter printWriter = new PrintWriter("b.txt");
        printWriter.println("cbd");
        printWriter.write("abc");

        // 关流
        printWriter.close();
    }

9 合并流

public static void main(String[] args) throws IOException {
        // 创建要合并的流
        InputStream in1 = new FileInputStream("E:\\a.txt");
        InputStream in2 = new FileInputStream("E:\\b.txt");
        InputStream in3 = new FileInputStream("E:\\c.txt");
        InputStream in4 = new FileInputStream("E:\\d.txt");
        // 创建向量
        Vector<InputStream> vector = new Vector<>();
        vector.add(in1);
        vector.add(in2);
        vector.add(in3);
        vector.add(in4);
        // 合并流
        SequenceInputStream sequenceInputStream = new SequenceInputStream(vector.elements());
        // 创建输出流
        FileOutputStream fileOutputStream = new FileOutputStream("E:\\e.txt");
        // 创建缓冲数组
        byte[] bs = new byte[20];
        // 读取到的实际个数
        int len;
        while ((len = sequenceInputStream.read(bs)) != -1){
            fileOutputStream.write(bs,0,len);
        }

        // 关流
        fileOutputStream.close();
        sequenceInputStream.close();

    }

10 随机获取流

mode:

  • r 读
  • rw 读写
  • rws 读写并写入硬盘
  • rwd 读写并写入硬盘,同步保存
public static void main(String[] args) throws IOException {
        // 创建随机获取流对象  双向流
        RandomAccessFile randomAccessFile = new RandomAccessFile("c.txt","rw");
        // 向文件中写入123
        // 底层把操作文件看作一个字节数组,索引从0开始
        randomAccessFile.write("123".getBytes());
        System.out.println((char)randomAccessFile.read());
        // 可以指定索引
        randomAccessFile.seek(0);
        // 已经指定了索引是0,读取的时候从头读取 结果是1
        System.out.println((char)randomAccessFile.read());
        // 设置跳过n个索引
        randomAccessFile.skipBytes(5);
        System.out.println((char)randomAccessFile.read());
        // 关流
        randomAccessFile.close();
    }

11 序列化和反序列化流

序列化:将对象以及其中的信息转换成字节进行完成保存

反序列化:将存储的字节数组取出来还原成对应的对象

如果一个对象想要被序列化,对应的类要实现Serializable接口

被static修饰的属性称之为静态变量,属性类不属于对象,所以不能序列化,因为没有意义

被transient修饰的属性强制性不能序列化

serialVersionUID: 版本号
每一个类在实现Serializable接口之后这个类会自动产生一个版本号。如果这个版本号没有手动指定,那么java在编译的时候会根据当前类中的属性和方法自动计算,也就意味着当类中的属性和方法产生变动的时候,版本号也会重新计算。序列化的时候版本号会随着对象一起序列化出去。当对象反序列化的时候,会拿着原来的版本号和当前类中的版本号进行比较。如果版本号一致,则允许反序列,否则抛出异常InvalidClassException

Peson类

package cn.javasm.demo;

import java.io.Serializable;

/**
 * @className: Person
 * @description:
 * @author: gfs
 * @date: 2025/7/11 17:05
 * @version: 0.1
 * @since: jdk17
 */
public class Person implements Serializable {
    // 手动指定版本号
    private static final long serialVersionUID = 4654757657546346L;
    private String name;

    private int age;

    private String address;

    static String classroom;

    private transient double height;

    private String gender;

    public static String getClassroom() {
        return classroom;
    }

    public static void setClassroom(String classroom) {
        Person.classroom = classroom;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", height=" + height +
                ", gender='" + gender + '\'' +
                '}';
    }
}

测试方法

public static void main(String[] args) throws IOException, ClassNotFoundException {
        demo2();
    }

    private static void demo2() throws IOException, ClassNotFoundException {
        // 反序列化
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("p.data"));
        // 读取对象
        Person person = (Person) objectInputStream.readObject();
        System.out.println(person);
        // 关流
        objectInputStream.close();
    }

    private static void demo1() throws IOException {
        Person person = new Person();
        person.setName("周杰伦");
        person.setAge(45);
        person.setAddress("台湾");
        person.classroom = "三年二班";
        person.setHeight(175.4);
        // 一个对象要想序列化,这个对象对应的类必须实现Serializable接口
        //  序列化
        ObjectOutputStream  objectOutputStream = new ObjectOutputStream(new FileOutputStream("p.data"));
        // 保存对象
        objectOutputStream.writeObject(person);
        // 关流
        objectOutputStream.close();
    }

12 Properties

Properties是Hashtable的子类:同步线程安全的,key和value都不能是null,key和value的类型都是字符串

public static void main(String[] args) throws IOException {
      Properties properties = new Properties();
        // 添加数据
        properties.setProperty("name","胡理想");
        properties.setProperty("age","23");
        properties.setProperty("gender","male");
        // 持久化到硬盘中
//            存储数据
        properties.store(new FileOutputStream("person.properties"),"this is a comment");


        // 读取数据
        properties.load(new FileInputStream("person.properties"));
        // 根据key获取value
        String name = properties.getProperty("name");
        System.out.println(name);
        System.out.println(properties);
    }
posted @ 2025-07-10 14:49  小胡coding  阅读(4)  评论(0)    收藏  举报