Java - IO流


IO前建议了解下: Java - 字符编码、编码表

第一章 IO流简介

输入流: 硬盘 -> 内存 , input , read
输出流: 内存 -> 硬盘 , ouput , write

第二章 IO流的分类

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

1. 字节输入流 InputStream

  • java.io.InputStream类: 字节输入流顶层抽象父类
常用方法:
   	public void close(): 		关闭流,释放资源
   	public int read(): 			读取一个字节,返回int数据
   	public int read(byte[] bs): 读数据到字节数组中,返回读取到的字节的数量,返回-1文件结束
  • 子类:
    • FileInputStream: 文件字节输入流,以字节为单位读取文件到内存。
    • BufferedInputStream:缓冲字节输入流

1.1 文件字节输入流 FileInputStream

使用步骤:
1. 创建FileInputStream 对象,传入读取文件的路径
2. 调用read方法,以字节为单位读取文件
3. 释放资源,关闭流。
package com.alibaba.fileinputstream_practice;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class Demo01 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            //1. 创建FileInputStream对象,构造方法传入要读取文件的地址
            fis = new FileInputStream("day11\\src\\com\\alibaba\\fileinputstream_practice\\a.txt");

            //2. 调用read方法读取
            int read = fis.read();
            System.out.println(read);
            //读取一个字节并返回对应的int数,gbk,utf-8编码的一个字节的都只使用了0x00~0x7F和ascii码一致,因此返回的int数范围就是0~127
            //当返回值为-1时,表示读到文件末尾,

            byte[] bytes = new byte[1024];
            int len = 0;//
            while ((len = fis.read(bytes)) != -1) {
                //读取多个字节,返回写入到数组bytes的字节数,当返回值为-1时表示读到文件末尾
                //用-1判断文件末尾而不是0,是因为如果数组bytes长度设为0,那不管文件有多少内容返回值恒为0,没法判断。(因为数组长度有0,为了避开吗?话说谁要读文件会把容量弄为0啊,怎么会有这样的人啊!!)
                System.out.println("本次读取了" + len + "个字节");
                System.out.println(new String(bytes, 0, len, StandardCharsets.UTF_8));
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

1.2 缓冲字节输入流 BufferedInputStream

  • 缓冲区 protected volatile byte buf[]; 默认大小8192B
package com.alibaba.bufferedinputstream_practice;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Demo01 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("day11\\src\\com\\alibaba\\bufferedinputstream_practice\\a.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);//默认缓冲字节数组大小 8192

        int read = 0;
        while ((read = bis.read()) != -1) {
            System.out.println(read); //读取到的字节int值
        }

        //fis.close(); //不需要写,因为bis.close会同时关闭
        bis.close();
    }
}

2. 字节输出流 OutputStream

  • java.io.OutputStream类: 所有字节输出流的顶层抽象父类
   	public void close(): 				关闭流,释放资源
   	public void flush():				立即写入此流
   	public abstract void write(int b):	写入一个字节
   	public void write(byte b[]): 		写入一个字节数组
   	public void write(byte b[], int off, int len): 写入一个字节数组,off:开始写的索引,len:想写入的字节数
  • 子类:
    • FileOutputStream: 文件字节输出流,以字节为单位向文件中写入。
    • BufferedOuputStream: 字节缓冲输出流。

2.1 文件字节输出流 FileOutputStream

使用步骤:
1. 创建FileOutputStream对象,构造方法中传入要写入数据的目的地
2. 调用write方法,把数据写入目的地。
3. 关闭流,释放资源。
package com.alibaba.fileoutputstream_practice;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class Demo01 {

    public static void main(String[] args) {

        FileOutputStream fos = null;
        try {
            //1. 创建FileOutputStream对象,构造方法参数传入目的地
            fos = new FileOutputStream("day11\\src\\com\\alibaba\\fileoutputstream_practice\\a.txt", true); //true 文件追加写入

            //2. 写入数据
            fos.write(65);
            //写入的时候会把十进制转为二进制0100 0001,
            //记事本打开时,0~127会根据ASCII表转换,超过127会根据系统默认字符集(windows10是GBK),转为对应的字符。
            
            fos.write(49);// 1
            fos.write(48);// 0
            fos.write(48);// 0
            //写入三个字符 组成 100;

            fos.write("路漫漫其修远兮,吾将上下而求索。".getBytes(StandardCharsets.UTF_8));
            //一次写入多个字节, utf-8中文三个字节,符号一个字节 所以字节数组长度44

            fos.write(new byte[]{65, 66, 67}, 0, 2);
            //写入字节数组的一部分,从 索引0开始写,写两个。
                        
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //3. 关闭流
                if (fos != null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2.2 缓冲字节输出流 BufferedOutputStream

  • 就多了个缓冲区 protected byte buf[]
  • write方法先写在内存中的缓冲区中,flush 或 close方法才写入到硬盘中。
package com.alibaba.bufferedouputstream_practice;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

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

        FileOutputStream fos = new FileOutputStream("day11\\src\\com\\alibaba\\bufferedouputstream_practice\\a.txt");//缓冲区默认大小 8192
        BufferedOutputStream bos = new BufferedOutputStream(fos);
		
        bos.write(97);

        byte[] bytes = {65, 66, 67, 68, 69, 70};
        bos.write(bytes);

        bos.write(bytes, 0, 2);

        bos.flush();
		//fos.close();	//不需要写,因为bos.close时会同时关闭
        bos.close();
    }
}

3. 字符输入流 Reader

1. java.io.Reader 抽象类是用于读取字符流的所有类的超类
2. 方法
    	public void close(): 关闭流,释放资源
    	public int read(): 读取一个字符,返回对应的int数字(字符对应的int数字)
    	public int read(char[] chs): 读取一些字符,返回对应的int数字(字符的个数)
  • 子类:
    • FileReader 文件字符输入流
    • BufferedReader 缓冲字符输入流,加了个缓冲区

3.1 文件字符输入流 FileReader

在这里插入图片描述

  • java.io.FileReader 类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
package com.alibaba.FileReader_practice;

import java.io.FileReader;
import java.io.IOException;

/*
FileReader 文件字符输入流
 */
public class Demo01 {
    public static void main(String[] args) {
        FileReader fileReader = null;
        try {

            //1. 创建FileReader对象,构造方法参数传入要读取的文件地址
            fileReader = new FileReader("day11\\src\\com\\alibaba\\filereader_practice\\a.txt");

            //2. 调用read方法读取字符
            int read = fileReader.read();
            System.out.println("读取了一个字符:" + read);//返回了读到字符的int值(0x00~0xffff)

            char[] chars = new char[1024];
            int len1 = 0;
            while((len1 = fileReader.read(chars)) != -1){ //读取字符, 返回值表示读取到的字符数,当为-1时表示文件末尾
                System.out.println("本次读取了" + len1 + "个字符");
                System.out.println(new String(chars,0,len1));
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                //3.关闭流
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.2 字符缓冲输入流 BufferedReader

  • 缓冲区private char cb[]; ,默认大小8192B
package com.alibaba.bufferedreader_practice;

import java.io.*;

public class Demo01 {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("day11/src/com/alibaba/bufferedwriter_practice/a.txt");
        BufferedReader br = new BufferedReader(fr);

        int read = 0;
        while ((read = br.read()) != -1) { // 读取一个字符,返回int值
            System.out.println(read);
        }

        String s = br.readLine();   //读取一行
        System.out.println(s);

        br.close();//将缓冲区文件写入硬盘并关闭系统资源。
    }
}

4. 字符输出流 Writer

java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
方法:
public abstract void close():关闭此输出流并释放与此流相关联的任何系统资源。  
public abstract void flush() :刷新此输出流并强制任何缓冲的输出字符被写出。  
public void write(int c):写出一个字符。
public void write(char[] cbuf):将 b.length字符从指定的字符数组写出此输出流。  
public abstract void write(char[] b, int off, int len):从指定的字符数组写出 len字符,从偏移量 off开始输出到此输出流。  
public void write(String str):写出一个字符串。
  • 子类
    • FileWriter 文件字符输出流
    • BufferedWriter 缓冲字符输出流

4.1 文件字符输出流 FileWriter

在这里插入图片描述

  • java.io.FileWriter 写出字符到文件,以字符为单位。构造时使用系统默认的字符编码和默认字节缓冲区。
package com.alibaba.FileWriter_practice;

import java.io.FileWriter;
import java.io.IOException;

/*
FileWriter 文件字符输入流
 */
public class Demo01 {
    public static void main(String[] args) {
        FileWriter fileWriter = null;
        try {

            //1. 创建FileWriter对象,构造方法参数传入要读取的文件地址
            fileWriter = new FileWriter("day11\\src\\com\\alibaba\\filewriter_practice\\a.txt",true); //true 续写

            //2. 调用write方法读取字符
            fileWriter.write(97);
            fileWriter.write("abc");
            fileWriter.write("abcd", 0, 2);
            fileWriter.write(new char[]{'a', 'b', 'c'});
            fileWriter.write(new char[]{'a', 'b', 'c', 'd'}, 0, 3);

            //3.调用flush方法 将内容从内存写入到硬盘中。
            fileWriter.flush(); // 未刷新或关闭流之前,写入的内容只在内存中。

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                //4.关闭流
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • flush 和 close的区别
    • flush: 刷新缓冲区,流对象可以继续使用。
    • close:先刷新缓冲区,然后通知系统释放资源。流对象不可继续使用。
  • 注:
    • 虽然参数为int类型四个字节,但是只会保留一个字符的信息写出。
    • 未调用close方法,数据只是保存到了缓冲区,并未写出到文件中。
    • 字符流,只能操作文本文件,不能操作图片,视频等非文本文件。
    • 当我们单纯读或者写文本文件时 使用字符流 其他情况使用字节流

4.2 字符缓冲输出流 BufferedWirter

  • 缓冲区private char cb[]; 默认大小8192
package com.alibaba.bufferedwriter_practice;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Demo01 {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("day11/src/com/alibaba/bufferedwriter_practice/a.txt");
        BufferedWriter bw = new BufferedWriter(fw);

        bw.write(97);
        bw.write("abcde");
        bw.write(new char[]{'a','b','c'});
        bw.write(new char[]{'a','b','c'},0,2);
        
        bw.newLine(); //写入一个行分隔符。特有方法

        bw.flush();//立即将缓冲区内容写入到硬盘中

        bw.close();//将缓冲区文件写入硬盘并关闭系统资源。
    }
}

5. 转换流

  • 字符输入输出流是在字节输入输出流的基础上,按照默认的编码格式进行编码、解码。无法设置编码格式。
  • 转换流是字节和字符之间的桥梁,且可以设置编码格式。
  • InputStreamReader
  • OutputStreamWriter

B站视频

5.1 InputStreamReader

package com.alibaba.inputstreamreader_practice;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

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

        FileInputStream fis = new FileInputStream("day11/src/com/alibaba/inputstreamreader_practice/a.txt");
        InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);

        char[] chars = new char[1024];
        int len = 0;
        while ((len = isr.read(chars)) != -1) {
            System.out.println(new String(chars, 0, len));
        }

        isr.close();
    }
}

5.2 OutputStreamWriter

package com.alibaba.outputstreamwriter_practice;

import java.io.*;

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

        FileOutputStream fos = new FileOutputStream("day11/src/com/alibaba/outputstreamwriter_practice/a.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");//可指定编码格式

        osw.write(97);
        osw.write("abcdf");

        osw.flush();
        osw.close();
    }
}

第三章 序列化和反序列化

  • 序列化:用字节序列存储一个对象的 包名.类名、字段名、字段值等信息。持久存储到硬盘中。
  • 反序列化:从硬盘文件中读取字节序列,重构成一个对象。

1. 序列化类 ObjectOutputStream

  • java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
    对象序列化前提
  1. 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException
  2. 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。
package com.alibaba.objectoutputstream_practice;
import java.io.Serializable;
public class Person implements Serializable { //要序列化的类要实现Serializable接口
    private String name;
    private int age;
    private transient String gender; // transient 瞬时的 该字段不参与序列化

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
//序列化,将对象存储到硬盘
//1. 创建ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day11/src/com/alibaba/objectoutputstream_practice/person.txt"));
Person person = new Person("zhangsan", 18);
//2.调用 writeObject方法
oos.writeObject(person);
//3. 关闭流
oos.close();

2. 反序列化类 ObjectInputStream

  • ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
        //反序列化
        //1.创建ObjectInputStream对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day11/src/com/alibaba/objectoutputstream_practice/person.txt"));
        //2.调用readObject方法
        Object o = ois.readObject();
        //3.关闭流
        ois.close();
        System.out.println(o);

3. 异常ClassNotFoundException、InvalidClassException

  • 反序列化操作,JVM会寻找要反序列化类.class文件,如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。

  • 反序列化操作,能找到该类class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。

    • 原因:
      • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
      • 该类包含未知数据类型
      • 该类没有可访问的无参数构造方法
    • 解决方法:
      • 添加版本号serialVersionUID ,用于验证序列化文件中保存的版本和当前class文件的版本是否一致。
package com.alibaba.objectoutputstream_practice;

import java.io.Serializable;

public class Person implements Serializable { //要序列化的类要实现Serializable接口
    private static final long serialVersionUID = 1L;//自定义版本号,不使用jvm的
    private int id;
    private String name;
    private int age;
    private transient String gender; // transient 瞬时的 该字段不参与序列化
    private int status;

    public Person() {
    }

    public Person(int id,String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

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

}

第四章 打印流

1. 概述

打印流是专门负责数据输出打印的流对象,我们经常使用的控制台输出语句System.out.println(),就是打印流实现的输出。

  • PrintStream继承OutputStream, 本质上是字节输出流。
  • PrintWriter继承Writer, 本质上是字符输出流。

打印流的特点:

  • 打印流指负责输出数据,不负责数据来源。
  • 打印流永远不会抛出IOException。
  • 使用PrintWriter打印流,可以开启自动刷新功能。
  • 调用println,printf,format三个方法中的一个才能自动刷新。

2. PrintWriter类

  • public PrintWriter(String fileName) : 使用指定的文件名创建一个新的打印流。
  • public PrintWriter(OutputStream out): 使用指定的字节输出流构造打印流。
  • public PrintWriter(Writer writer): 使用指定的字符输出流构造打印流。
public static void main(String[] args) throws IOException {
    // 创建打印流,输出目的是字节输出流
    //PrintWriter pw = new PrintWriter(new FileOutputStream("a.txt"),true);
    //创建打印流,输出目的是字符
    PrintWriter pw = new PrintWriter(new FileWriter("a.txt"),true);
	pw.println(97);
    pw.println(98);
	pw.close();
}

注意:打印流输出数据是原样输出,打印97,结果看到就是97,而不是a。

第五章 Properties集合和IO流

  • java.util.Properties集合,继承了HashTable<K,V>,双列集合。
  • 唯一一个和IO流结合的集合
  • 可以使用,stroe方法写入硬盘,load方法读取硬盘数据。
  • 键和值默认都是字符串
主要使用的是与String相关的方法:
    public  Object setProperty(String k,String v): 	保存一个键值对(属性名=属性值)
    public  String getProperty(String key): 		根据属性名获取属性值
    public Set<String> stringPropertyNames(): 		获取所有属性名的set集合
 */
package com.alibaba.properties_practice;

import java.io.*;
import java.util.Properties;

public class Demo01 {

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

        //1. 创建Properties集合对象
        Properties p = new Properties();

        //2. 调用setProperty 或 put方法添加键值对(键符合hash表)
        p.setProperty("username", "root");

        Object password = p.put("password", "123456");//也可以用put方法,毕竟是HashTable双列集合
        System.out.println(password);// 如果当前添加的键已经存在,则进行覆盖,返回该键对应的原来值

        //3.存储 调用store 方法将输出流内容存储到硬盘文件
        FileOutputStream fos = new FileOutputStream("day11\\src\\com\\alibaba\\properties_practice\\01.properties");
        p.store(fos, null);
        fos.close();

        //4.读取 调用load方法,从字节输入流,字符输入流,XML流读取
        Properties p1 = new Properties();
        FileInputStream fis = new FileInputStream("day11\\src\\com\\alibaba\\properties_practice\\01.properties");
        p1.load(fis);
        fis.close();
        System.out.println(p1);
    }
}

第六章 Commons IO

1. Commons IO介绍

  • Apache软件基金会,开发了IO技术的工具类commonsIO,大大简化IO开发。

2. 添加第三方jar包

jar包:就是Java自己的压缩包,包中是开发好的功能,全部以class文件形态出现,我们添加直接使用即可。

  • 将jar包文件复制到lib文件夹中
  • lib文件夹上按鼠标右键,选择Add as Library

3. CommonsIO的使用

  • IOUtils类
    • 静态方法:IOUtils.copy(InputStream in,OutputStream out)传递字节流,实现文件复制。
    • 静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close()方法抛出的异常。
  • FileUtils类
    • 静态方法:FileUtils.copyDirectoryToDirectory(File src,File dest);传递File类型的目录,进行整个目录的复制,自动进行递归遍历。
    • 静态方法:writeStringToFile(File file,String str)写字符串到文本文件中。
    • 静态方法:readFileToString(File file)读取文本文件,返回字符串。

第七章 IO练习题

1. 文件复制

使用字节流可以进行任何文件的复制,
因为字节流操作的是组成文件的最小单元-字节。
/*
字节流复制文件
实现步骤:
    1.创建文件字节输入流FileInputStream类的对象fis,绑定源文件
    2.创建文件字节输出流FileOutputStream类的对象fos,绑定目标文件
    3.循环读(源文件)写(目标文件)
    4.关闭流,释放资源
*/
package com.alibaba.io_test.input_stream_test.file_input_stream_test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopyTest {

    public static void main(String[] args) throws IOException {
        copy();
        copy2();
    }

    public static void copy() throws IOException {
        //1. 创建要读取的文件输入流对象
        String srcPath = "D:\\Project\\JavaAdvenced\\day12_review\\src\\com\\alibaba\\io_test\\input_stream_test\\file_input_stream_test\\a.txt";
        String desPath = "D:\\Project\\JavaAdvenced\\day12_review\\src\\com\\alibaba\\io_test\\input_stream_test\\file_input_stream_test\\b.txt";
        File srcFile = new File(srcPath);
        File desFile = new File(desPath);

        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(desFile); //文件不存在会帮创建,如果是文件夹会抛异常

        //2. 输入流读 ,写 到 输出流
        byte[] buffer = new byte[1024];
        int byteLen;
        while ((byteLen = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, byteLen); //读多少写多少
        }

        //3.关闭流
        fis.close();
        fos.close();
    }

    public static void copy2() throws IOException {
        //1. 创建要读取的文件输入流对象
        String srcPath = "D:\\Project\\JavaAdvenced\\day12_review\\src\\com\\alibaba\\io_test\\input_stream_test\\file_input_stream_test\\a.txt";
        String desPath = "D:\\Project\\JavaAdvenced\\day12_review\\src\\com\\alibaba\\io_test\\input_stream_test\\file_input_stream_test\\b.txt";
        File srcFile = new File(srcPath);
        File desFile = new File(desPath);
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(desFile);

        try (fis; fos) {	//jdk9
            //2. 输入流读 ,写 到 输出流
            byte[] buffer = new byte[1024];
            int byteLen;
            while ((byteLen = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, byteLen); //读多少写多少
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //3. jdk9+ 自动帮你关闭资源
    }
}

2. 文本内容排序

排序前文件内容:
3.子好勇乎?吾尝闻大勇于夫子矣:自反而不缩,虽褐宽博,吾不惴焉。自反而缩,虽千万人吾往矣。
2.舍岂能为必胜哉,能无惧而已矣!孟施舍似曾子,
北宫黝似子夏;夫二子之勇,未知其孰贤;然而孟施舍守约也
1.视不胜犹胜也;量敌而后进,虑胜而后会,是畏三军者也

排序后文件内容:
1.视不胜犹胜也;量敌而后进,虑胜而后会,是畏三军者也
2.舍岂能为必胜哉,能无惧而已矣!孟施舍似曾子,
北宫黝似子夏;夫二子之勇,未知其孰贤;然而孟施舍守约也
3.子好勇乎?吾尝闻大勇于夫子矣:自反而不缩,虽褐宽博,吾不惴焉。自反而缩,虽千万人吾往矣。
package com.alibaba.filesort_practice;

import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.stream.Stream;

public class Demo01 {
    public static void main(String[] args) throws IOException {
        /*
        1. 字符缓冲输入流读取文件,
           1.1 按行读取,如果第一个字符是阿拉伯数字,将文件按编号存到 Map集合中, HashMap<Integer,String>
        2. 获取键的Set<Integer>集合 进行排序。
        3. 按照拍好的顺序 ,写入覆盖原文件。
        */

        BufferedReader br = new BufferedReader(new FileReader("day11/src/com/alibaba/filesort_practice/a.txt"));

        HashMap<String, String> map = new HashMap<>();

        String lineStr = br.readLine();
        if (lineStr == null) {
            return;
        }
        String key = lineStr.split("\\.")[0];
        map.put(key, lineStr);

        while ((lineStr = br.readLine()) != null) {
            char c = lineStr.charAt(0); //假设都顶格写
            if ('0' <= c && c <= '9') {//是段落编号,则作为一个键,
                key = lineStr.split("\\.")[0];
                map.put(key, lineStr);
            } else {
                String s = map.get(key);
                map.put(key, s + lineStr);
            }
        }
        br.close();

        //排序
        Stream<String> sorted = map.keySet().stream().sorted();
        Object[] objects = sorted.toArray();
        BufferedWriter bw = new BufferedWriter(new FileWriter("day11/src/com/alibaba/filesort_practice/b.txt"));
        for (Object object : objects) {
            String s = map.get(object);
            System.out.println(s);
            bw.write(s);
            bw.newLine();
        }
        bw.close();
    }
}

第八章 参考资料

B站黑马程序员 | Java入门基础视频教程

https://www.bilibili.com/video/BV1Lf4y1U7Cz?p=393&spm_id_from=pageDriver

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值