java入门基础(九)


一、File

1.File概述

  • 文件和目录的抽象
  • 文件和目录可以通过File封装成对象
  • 对于File,其封装的并不是一个真正的文件,只是文件的路径,可存在可不存在,之后通过具体的操作把这个路径转化为具体的存在

2.File构造方法和创建方法

  • 构造方法

    • File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
    • File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。
    • File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。
  • 创建方法

    • public boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
    • public boolean mkdir() 创建由此抽象路径名命名的目录
    • public boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
  • 代码演示

import java.io.File;
public class FileTest {
    
    
    public static void main(String[] args) throws Exception {
    
    
        //演示第一种构造方法,text1.txt不存在
        File file1 = new File("E:\\IdeaProjects\\HuiHui\\text1.txt");
        System.out.println(file1.createNewFile());//判断抽象路径是否存在,存在返回false,不存在创建,返回true

        //演示第二种构造方法,创建File 2指向刚创建的text1.txt文件
        File file2 = new File("E:\\IdeaProjects\\HuiHui","text1.txt");
        System.out.println(file2.getName()+"========"+file1.getName());

        //调用mkdir方法只能创建单级目录data1
        File file3=new File("E:\\IdeaProjects\\HuiHui\\","data1");
        System.out.println(file3.mkdir());
        System.out.println(file3.createNewFile());

        //调用nkdirs方法创建多级目录,data2\\data,,也可创建单级目录
        File file4=new File("E:\\IdeaProjects\\HuiHui\\","data2\\data");
        System.out.println(file4.mkdirs());

        //演示第三种构造方法,data3目录不存在,text2.txt文件不存在
        File file6=new File("E:\\IdeaProjects\\HuiHui\\data3");
        File file5=new File(file6,"text2.txt");
        System.out.println(file6.mkdirs());
        System.out.println(file5.createNewFile());

        //演示创建文件方法创建目录,创建目录方法创建文件
        File file7=new File("E:\\IdeaProjects\\HuiHui\\data4");
        System.out.println(file7.createNewFile());//返回true,创建的是未知文件,带有问号标识
        File file8=new File("E:\\IdeaProjects\\HuiHui\\text3.txt");
        System.out.println(file8.mkdirs());//返回true,创建的是名为text3.txt的目录
    }
}

在这里插入图片描述

3.File基本方法

  • public boolean isDirectory() 判断抽象路径是否为目录
  • public boolean isFile() 判断抽象路径是否为文件
  • public boolean exists() 判断抽象路径是否存在
  • public String getAbsolutePath() 返回抽象路径的绝对路径字符串
  • public String getPath() 返回抽象路径的路径字符串
  • public String getName() 返回抽象路径表示路径或文件的名称
  • publci String[] list() 返回抽象路径表示目录下的目录和文件的名称
  • public File[] listFile() 返回抽象路径表示目录下的目录和文件的对象
  • public boolean delete() 删除抽象路径表示的文件或目录

代码演示

public class FileTest2 {
    
    
    public static void main(String[] args) throws IOException{
    
    
        //此处测试的data为目录,data里面有data1目录,text1.txt文件
        File file=new File("data");
        System.out.println("绝对路径"+file.getAbsolutePath());
        System.out.println("相对路径"+file.getPath());//相当于项目名称
        System.out.println(file.exists());
        if(file.isFile()){
    
    
            System.out.println("这是文件");
            System.out.println(file.getName());
        }
        else {
    
    
            System.out.println("这是目录"+file.getName());
            //两种遍历方法
            File[] files=file.listFiles();//定义为文件类型,可以使用文件的方法
            String[] strings=file.list();//定义为字符串数组类型,输出的是字符串
            System.out.println("文件调用getname输出");
            for(File f:files){
    
    
                System.out.println(f.getName());
            }
            System.out.println("字符串输出");
            for(String s:strings){
    
    
                System.out.println(s);
            }
        }
    }
}

在这里插入图片描述

4.递归删除

  • 注意:删除目录时,如果目录下有内容不能直接删除,
    需要先删除目录中的内容,再删除目录
  • 递归
    • 概述:在方法中调用方法本身
    • 思想:
      一个多层次的问题,每一层的问题都是类似的,像这种问题就可以使用递归来进行解决,使用递归只需要少量的程序就可以搞定解决问题过程中的多次重复计算

代码演示

import java.io.File;
//演示递归和删除,删除只能删除文件,或者空目录,不是空的目录不能删除
public class FileTest3 {
    
    
    //data为一个含有多级目录和多个文件的目录,需求:删除data目录
    public static void main(String[] args) {
    
    
        File file=new File("E:\\IdeaProjects\\HuiHui\\data");
        DeleteFile(file);
    }
    public static void DeleteFile(File file){
    
    
        if(file.isDirectory()) {
    
    
            File[] files = file.listFiles();
            for (File f : files) {
    
    
                DeleteFile(f);
            }
            file.delete();
        }
        else {
    
    
            file.delete();
        }
    }
}

案例:输出目录下啊所有以java结尾的文件,并统计java文件的个数

import java.io.File;
import java.util.ArrayList;

public class Demo_io {
    
    
    static int i=0;
    public static void main(String[] args) {
    
    
        File file=new File("E:\\IdeaProjects\\HuiHui");
        ArrayList<File> arrayList=new ArrayList<>();
        System.out.println("方法一");
        Printfile1(file,arrayList);
        System.out.println(arrayList.size());
        System.out.println("方法二");
        Printfile2(file);
        System.out.println(i);

    }
    public static void  Printfile1(File file,ArrayList<File> list){
    
    
        File[] file1=file.listFiles();
        for(File f:file1){
    
    
            if(f.isFile()){
    
    
                if(f.getName().endsWith(".java")){
    
    
                System.out.println(f.getName());
                list.add(f);}
            }
            else {
    
    
                Printfile1(f,list);
            }
        }
    }

    public static void Printfile2(File file){
    
    
        File[] file1=file.listFiles();
        for(File f:file1){
    
    
            if(f.isFile()){
    
    
                String name=f.getName();
                String[] strings=name.split("\\.");
                if(strings.length==2&&strings[1].equals("java")){
    
    
                    System.out.println(f.getName());
                    i++;
                }

            }
            else {
    
    
                Printfile2(f);
            }
        }

    }
}

二、IO输入输出流

1.io

  • 概述:
    IO:输入/输出(input/output)
    流:抽象的概念,数据传输的总称
    IO流:用来处理设备之间数据传输问题 如文件上传,下载,复制…

  • 硬盘—输入流(读数据)---->内存

  • 内存—输出流(写数据)—>硬盘

  • 分类:
    通过流向分类:输入流(读数据)和输出流(写数据)
    通过数据类型分类:
    字节流:字节输入流,字节输出流
    字符流:字符输入流,字符输出流

这两种流该如何使用:通过记事本打开,内容能读懂使用字符流 读不懂使用字节流,如果不知道使用什么流就只用字节流

2.字节流写数据->输出流FileOutputStream

  • InputStream:这个抽象类表示字节输入流的所有类的父类
    OutputStream:这个抽象类表示字节输出流的所有类的父类

  • FileOutPutStream:文件字节输出流(具体的字节输出流实现类)

  • FileOutPutStream(String name)创建文件字节输出流写入文件

    • 使用步骤:
      1.创建对象(1.调用系统创建空文件2.创建字节输出流对象3.让对象指向文件)
      2.调用写数据的方法(writer())
      3.释放资源(关闭文件流并释放与此相关的资源)(一般怕忘,第二步就写上)

    • 字节流写数据的三种方方式
      write(int b) 将指定的字节写入文件,一次写一个字节
      write(byte[] b) 将指定的字节数组写入文件,一次写一个字节数组
      write(byte[] b,int off,int len) 将指定的字节数组,从偏移量off开始写入文件,一次写len个字节,一次写数组的一部分

代码演示

public class Demo_io1 {
    
    
    public static void main(String[] args) throws Exception{
    
    
        //指向的对象,不管有没有,都会创建文件,有会覆盖掉之前的,没有也创建,里面是空的
        //如果指向的是目录,编译时没错,运行时报错
        FileOutputStream fos=new FileOutputStream("E:\\IdeaProjects\\HuiHui\\data\\text.txt");
        fos.write(97);//写入的是a,因为97对应的是 a,写其他数字,不一定写入,或者写入得是其他符号
        byte[] b={
    
    1,2,3,'a','b','A',98,67};//只写入了 a、b,A,C因为其他数字不一定写入
        fos.write(b);
        fos.close();
        //结果:a   abAbC

    }
}
  • 写入数据的换行和追加
  • 换行:
    文件中的换行是通过符号来进行表示,不同的操作系统有不同的换行符号,idea软件考虑到不同系统,都兼容
    windows:\r\n
    linux:\n
    mac:\r
  • 追加:
    • FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
    • FileOutputStream(new File)
      创建文件输出流以写入由指定的 File对象表示的文件。
    • FileOutputStream(String name,boolean append)
      创建文件输出流以指定的名称写入文件。append - 如果是 true ,那么字节将被写入文件的末尾,而不是开头
public class Demo_io3 {
    
    
    public static void main(String[] args) throws Exception {
    
    
        //不会覆盖,在之前的文件里追加
        //开始:cdeabcde
        //      abcde
        //      abcdabcde
        FileOutputStream fos=new FileOutputStream("E:\\IdeaProjects\\HuiHui\\data\\text.txt",true);
        byte[] b1={
    
    'a','b','c','d','e'};
        fos.write(b1,2,3);
        fos.write(b1);
        fos.write('\n');
        fos.write(b1);
        fos.write('\r');
        fos.write(b1,0,4);
        fos.write(b1);
        fos.close();

    }
}
//结果:cdeabcde
//      abcde
//      abcdabcdecdeabcde
//      abcde
//      abcdabcde

3.字节流读数据->输入流FileInputStream

  • 字节流抽象父类
    InputStream:这个抽象类表示字节输入流的所有类的父类
    OutputStream:这个抽象类表示字节输出流的所有类的父类

  • FileInputStream:文件字节输入流(具体的字节输入流实现类)

  • FileInputStream(String name)创建文件字节输出流读取文件

    • 使用步骤:

      • 1.创建对象(1.调用系统指向文件2.创建字节输入流对象3.让对象指向文件)
      • 2.调用读数据的方法(read())
      • 3.释放资源(关闭文件流并释放与此相关的资源)
    • 字节流读数据的三种方式

      • int read()
        从此输入流中读取一个数据字节。
      • int read(byte[] b)
        从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
      • int read(byte[] b, int off, int len)
        从此输入流中将最多 len 个字节的数据读入一个 byte 数组中
        len偏移量为字节数组中的偏移量

代码演示

//开始:
//cdeabcde
//abcde
//emfd
//afdmfvva
//dkhnvjdflbn
public class Fileinput_io1 {
    
    
    public static void main(String[] args)throws Exception {
    
    
        FileInputStream fis=new FileInputStream("E:\\IdeaProjects\\HuiHui\\data\\text.txt");

        int c=fis.read();//不能定义为char型去接受读入的第一个数据字节
        System.out.println("第一次读取的字节"+c);
        int d=fis.read();
        System.out.println("第二次读取的字节"+d);

        byte[] b=new byte[5];//长度一般定义为1024的整数倍
        fis.read(b,0,5);//读过的将不在读,从未读的地方开始,读取五个字节存入b,偏移量为写在b中的偏移量
        for(byte b1:b){
    
    
            System.out.println(b1);
        }

        //将剩下的全部读完,有如下两种方法,但不能同时存在
        // 因为只读一次,第一个全部读完后,后面的方法将无数据可读,这里演示第一种
        int a= 0;
        while ((a= fis.read()) != -1) {
    
    
            System.out.print((char) a);
        }

//        int len=0;
//        byte[] by = new byte[1024];
//        while ((len = fis.read(by)) != -1) {
    
    
//            System.out.println(new String (by,0,len));
//        }

         fis.close();
    }
}
//控制台输出结果:
//第一次读取的字节99
//第二次读取的字节100
//101
//97
//98
//99
//100
//e
//abcde
//emfd
//afdmfvva
//dkhnvjdflbn

4.案例一:将一个文件夹下的所有文件复制到一个txt文件中

需求:将data文件夹下的所有txt文件内容复制到test.txt文件中,txt中的所有内容,数字、汉字、字母、符号都将写入

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
//需求:将data文件夹下的所有txt文件内容复制到test.txt文件中
public class Fileinput_io2{
    
    
    public static void main(String[] args) throws Exception {
    
    
        File file =new File("E:\\IdeaProjects\\Hui\\data");
        copy(file);
    }

    public static void copy(File file)throws Exception{
    
    
        File[] files=file.listFiles();
        for(File f:files){
    
    
            if(f.isFile()){
    
    
                if(f.getName().endsWith("txt")){
    
    
                    FileInputStream fis=new FileInputStream(f.getAbsolutePath());
                    FileOutputStream fos=new FileOutputStream("E:\\IdeaProjects\\Hui\\test.txt",true);
                    byte[] bytes=new byte[1024];
                    int len=0;
                    while ((len=fis.read(bytes))!=-1){
    
    
                        fos.write(bytes,0,len);
                    }
                    fis.close();;
                    fos.close();

                }

            }
            else {
    
    
                copy(f);
            }
        }
    }
}

5.案例二:统计不同文件中的换行单词的个数

需求:将data文件夹下的记事本文件中的单词种类和数量统计写入test.txt文件中
前提:data中只有记事本文件和目录,不含其它类型的文件,记事本中的单词,必须是一行一个的
例如:
hello
world
java

public class WRTest {
    
    
    static Map<String, Integer> map = new HashMap<>();
    //用StringBuider方便添加,是一个可变的字符序列,但线程不安全,StringBuffer线程安全
    static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) throws Exception {
    
    
        File file = new File("E:\\IdeaProjects\\HuiHui\\data");
        readsave(file);
        System.out.println(sb);
        countnumytype();
        write();
    }

    public static void readsave(File file) throws Exception {
    
    
        File[] files = file.listFiles();
        for (File f : files) {
    
    
            if (f.isFile()) {
    
    
                FileInputStream fis = new FileInputStream(f.getAbsolutePath());
                byte[] bytes = new byte[1024];
                int len = 0;
                while ((len = fis.read(bytes)) != -1) {
    
    
                    String string = new String(bytes, 0, len);
                    sb.append(string);
                }
                fis.close();
            } else {
    
    
                readsave(f);
            }
        }
    }

    public static void countnumytype() {
    
    
        String[] strings = sb.toString().split("\r\n");
        for (String s : strings) {
    
    
            map.put(s, 0);
        }
        for (String s1 : strings) {
    
    
            if (map.containsKey(s1)) {
    
    
                map.put(s1, map.get(s1) + 1);
            }
        }
    }

    public static void write() throws Exception {
    
    
        FileOutputStream fos = new FileOutputStream("E:\\IdeaProjects\\HuiHui\\text.txt", true);
        for(Map.Entry<String,Integer> mm:map.entrySet()){
    
    
            byte[] byte1=mm.getKey().getBytes();
            byte[] byte2=mm.getValue().toString().getBytes();
            fos.write(byte1);
            fos.write(',');
            fos.write(byte2);
            fos.write('\n');
        }
        fos.close();
    }

}

6.BufferedOutputStream字节缓冲流

  • 继承FileOutputStream,是一个字节缓冲流,该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

  • 创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。

  • 构造方法:
    BufferedOutputStream(OutputStream out)
    BufferedOutputStream(OutputStream out, int size)
    创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。一般用默认值。采用第一种构造方法创建对象

注意: 字节缓冲流仅仅提供缓冲区,真正的读写数据还是依靠基本的字节流对象进行操作>

7.BufferedInputStream字节缓存流

  • BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。
  • 构造方法:
    BufferedInputStream(InputStream input)
    BufferedInputStream(InputStream in, int size)
    创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用
  • 字节缓存流和字节输入输出流用法差不多,为了减少对底层系统的调用次数,高效读写而继承了字节流。

8.案例三:将案例二用字节缓冲流操作

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class BufferedTest {
    
    
    public static void main(String[] args) throws Exception{
    
    
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream("E:\\IdeaProjects\\HuiHui\\data\\data1\\text1.txt"));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("E:\\IdeaProjects\\HuiHui\\test.txt"));

        //方法一,每次写入一个字节数组
        byte[] bytes=new byte[1024];
        int len;
        while ((len=bis.read(bytes))!=-1){
    
    
            bos.write(bytes,0,len);
        }

        //方法二,每次读写一个字节
//        int b;
//        while ((b=bis.read())!=-1){
    
    
//            bos.write(b);
//        }

        //注意:当前内容都是写在缓冲区的,需要flush一下,或者close,才能写入文件
        bos.flush();
        
        bis.close();
        bos.close();
    }
}

9.编码表

  • 计算机中存储的信息都是使用的二进制的方式,而我们所看的英文\汉字都是二进制转换之后的结果
    例如:a 97 01100001

  • 编码:按照某种规则,将字符存储到计算机中,看得懂—>看不懂
    byte[] getBytes():使用平台的默认字符编码集将String存储字节数组
    byte[] getBytes(String chareName):使用指定的编码集String存储字节数组

  • 解码:将存储在计算机中的二进制按照某种规则进行解析,看不懂–>看得懂
    String(byte[] bytes):通过默认字符集解码指定的数组来构造新的String
    String(byte[] bytes,String chareName):通过指定字符集解码指定的数组来构造新的String

  • 注意:编码和解码所使用的规则要保持一直,不然会出现乱码问题
    这里的规则就是编码表

  • 常用编码表:ASCII,GBK,Unicode
    Unicode统一编码表,标准万国码,使用最多4个字节的数字表达字母,有三种编码格式,UTF-8 UTF-16和UTF32,常用UTF-8

注意:只有字符流会出现编码乱码问题

10.字符流

  • 字符流
    Read:这个抽象类表示字符输入流的所有类的父类
    Write:这个抽象类表示字符输出流的所有类的父类
    OutputStreamWrite:文件字符输出流(具体的字符输出流实现类)
    OutputStreamWrite(OutputStream out)创建文件字节输出流写入文件

注意:字符流构造中的参数不是具体的文件路径 而是字节流对象
说明了字符流才具体的操作文件内容时,本质上还是通过字节流 操作

(1)OutputStreamWrite字符流写数据

构造方法
在这里插入图片描述

写数据的5种方式
在这里插入图片描述
代码演示写入字符得五种方法

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

public class OutputStreamWriter_Test {
    
    
    public static void main(String[] args)throws Exception {
    
    
        FileOutputStream fos=new FileOutputStream("E:\\IdeaProjects\\HuiHui\\test.txt");
        OutputStreamWriter osw=new OutputStreamWriter(fos);
        //写入一个字符
        osw.write(97);
        osw.write("\r\n");
        osw.write('字');
        osw.write("\n");
        //写入一个字符串
        osw.write("helloworld");
        osw.write("\r");
        //写入指定字符串
        osw.write("helloworld",2,5);
        osw.write('\r');
        //写入一个字符数组
        char[]cbuf={
    
    'h','e','l','l','o'};
        osw.write(cbuf);
        osw.write(cbuf,2,2);
        //和buffered一样需要刷新或者关闭才能写入文件
        osw.close();
        fos.close();
    }
}
//结果:
//a
//字
//helloworld
//llowo
//helloll

(2)InputStreamReader字符流读数据

构造方法
在这里插入图片描述
读数据得两种方法
int read()
读取单个字符。
int read(char[] cbuf, int offset, int length)
将字符读入数组中的某一部分。

注意:读文件时,如果该行含有\r得换行符 ,idea程序无法读取此行

代码演示

import java.io.FileInputStream;
import java.io.InputStreamReader;

public class InputStreamReader_Test {
    
    
    public static void main(String[] args) throws Exception {
    
    
        FileInputStream fis = new FileInputStream("E:\\IdeaProjects\\HuiHui\\test.txt");
        InputStreamReader isr = new InputStreamReader(fis);

//        int i = 0;
//        while ((i = isr.read()) != -1) {
    
    
//            System.out.println((char)i);
//        }

        char[] c = new char[1024];
        int len;
        while ((len = isr.read(c)) != -1) {
    
    

            System.out.println(new String(c,0,len));
        }
        fis.close();
        isr.close();
    }
}

(3)案例四:不同得编码,写入得结果

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

public class Test1 {
    
    
    public static void main(String[] args) throws Exception {
    
    
        FileOutputStream fos = new FileOutputStream("E:\\IdeaProjects\\HuiHui\\data\\data1\\text1.txt",true);
        OutputStreamWriter osw1 = new OutputStreamWriter(fos,"UTF8");
        OutputStreamWriter osw2=new OutputStreamWriter(fos,"GBK");
        OutputStreamWriter osw3=new OutputStreamWriter(fos,"GB2312");
        OutputStreamWriter osw4=new OutputStreamWriter(fos,"Unicode");
        OutputStreamWriter osw5=new OutputStreamWriter(fos);
        //以追加得方法,以不同得编码多次写入,不能一起运行,会涉及到线程等问题运行时出现异常
//        osw1.write("我爱学语文");
//        System.out.println(osw1.getEncoding());//UTF8  此处控制台结果不演示,在注释里标明,以下同
//        osw1.close();
//        fos.close();


//        osw2.write("我爱学语文");
//        System.out.println(osw2.getEncoding());//GBK
//        osw2.close();
//        fos.close();

//        osw3.write("我爱学语文");
//        System.out.println(osw3.getEncoding());//EUC_CN
//        osw3.close();
//        fos.close();

//        osw4.write("我爱学语文");
//        System.out.println(osw4.getEncoding());//UTF-16
//        osw4.close();
//        fos.close();

        osw5.write("我爱学语文");
        System.out.println(osw5.getEncoding());//UTF8
        osw5.close();
        fos.close();
    }
}
//记事本中结果:
//我爱学语文�Ұ�ѧ�����Ұ�ѧ������br1[f��e�我爱学语文
//可知idea默认编码为UTF8,编码和解码过程中要注意,采用得编码规则相同,否则会出现乱码

(4)字符流便捷版

  • 通过OutputStreamWrite和InputStreamRead构造对象太繁琐,这里可以使用子类FileWrite和FileRead来构建对象

  • FileWriter使用方式/构造方法
    FileWriter(File file)
    根据给定的 File 对象构造一个 FileWriter 对象。
    FileWriter(File file, boolean append)
    根据给定的 File 对象构造一个 FileWriter 对象。
    FileWriter(FileDescriptor fd)
    构造与某个文件描述符相关联的 FileWriter 对象。
    FileWriter(String fileName)
    根据给定的文件名构造一个 FileWriter 对象。
    FileWriter(String fileName, boolean append)
    根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

  • FileReader使用方式/构造方法
    FileReader(File file)
    在给定从中读取数据的 File 的情况下创建一个新 FileReader。
    FileReader(FileDescriptor fd)
    在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。
    FileReader(String fileName)
    在给定从中读取数据的文件名的情况下创建一个新 FileReader

  • 为了简便继承字符流得子类,构造方法区别于字符流,字符流构造得参数是必须是流对象,而简便版的参数是文件路径或者文件对象

注意:简化了字符流的创建对象,不能指定编码集只能使用平台默认的编码集,不能指定缓冲区的大小

(5)案例五:字符流简单版复制文件

import java.io.FileReader;
import java.io.FileWriter;
//要复制的内容:
//hello
//world
//我是学生,我爱学习,我爱java
public class Test2 {
    
    
    public static void main(String[] args)throws  Exception {
    
    
        FileReader fr=new FileReader("E:\\IdeaProjects\\HuiHui\\data\\data1\\data2\\text1.txt");
        FileWriter fw=new FileWriter("E:\\IdeaProjects\\HuiHui\\data\\data1\\text2.txt");

        char[] cbuf=new char[1024];
        int len;
        while ((len=fr.read(cbuf))!=-1){
    
    
            fw.write(cbuf,0,len);
        }

        fr.close();
        fw.close();
    }
}

(6)案例六:将一个文件夹里的文件里的单词,统计汇总到另一个文件中

不考虑递归,文件夹下只能是txt文件,文件中每个单词之间以“,”分割
例如:
hello,world,java,python
python,world,java,world
python,hello,world

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ReadCountTest {
    
    
    static StringBuilder sb=new StringBuilder();
    static Map<String,Integer> map=new HashMap<>();
    static List<String> list=new ArrayList<>();
    public static void main(String[] args)throws  Exception{
    
    
        File file=new File("E:\\IdeaProjects\\HuiHui\\data");
        readfile(file);
        split();
        count();
        System.out.println(map);
        writer();
    }
    public static void readfile(File file)throws Exception{
    
    
        File[] f=file.listFiles();
        for(File ff:f){
    
    
            if(ff.isFile()){
    
    
                FileReader fd=new FileReader(ff);
                char[] cbuf=new char[1024];
                int len;
                while ((len=fd.read(cbuf))!=-1){
    
    
                    sb.append(new String(cbuf,0,len));
                }
            }

        }
    }

    public static void split(){
    
    
        String[] strings=sb.toString().split("\r\n|,");
        for(String s:strings){
    
    
            list.add(s);
        }
    }

    public static void count(){
    
    
        for(String s1:list){
    
    
            map.put(s1,0);
        }
        for(String s2:list){
    
    
            if(map.containsKey(s2)){
    
    
                map.put(s2,map.get(s2)+1);
            }
        }
    }

    public static void writer()throws Exception{
    
    
        FileWriter fw=new FileWriter("E:\\IdeaProjects\\HuiHui\\text.txt");
        fw.write(map.toString());
        fw.close();
    }
}

{python=3, world=4, java=2, hello=2}

(7)字符缓冲流

  • BufferedRead:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。 可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。

  • BufferedWrite:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。 可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。

  • 构造方法摘要 (参数为Reader,Writer的实例对象)
    BufferedReader(Reader in)
    创建一个使用默认大小输入缓冲区的缓冲字符输入流。
    BufferedReader(Reader in, int sz)
    创建一个使用指定大小输入缓冲区的缓冲字符输入流。
    BufferedWriter(Writer out)
    创建一个使用默认大小输出缓冲区的缓冲字符输出流。
    BufferedWriter(Writer out, int sz)
    创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

  • 特殊方法:
    void newLine()
    写入一个行分隔符。
    String readLine()
    读取一个文本行。

(8)案例六:将一个文件里的内容,追加到另一个文件里

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class BufferedTest {
    
    
    public static void main(String[] args)throws Exception {
    
    
        FileReader fd=new FileReader("E:\\IdeaProjects\\HuiHui\\data\\data1\\data2\\text1.txt");
        FileWriter fw=new FileWriter("E:\\IdeaProjects\\HuiHui\\data\\data1\\text2.txt",true);
        BufferedReader br=new BufferedReader(fd);
        BufferedWriter bw=new BufferedWriter(fw);
        char[] cbuf=new char[1024];
        //方法一
//        int len;
//        while((len=br.read(cbuf))!=-1){
    
    
//            bw.write(cbuf,0,len);
//        }
        //方法二
        String string;
        while((string=br.readLine())!=null){
    
    
            bw.write(string);
            bw.newLine();
        }

        br.close();
        bw.close();

    }
}

(9)对象流

  • 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
    这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型,对象中存储的对象详细信息
  • 字节序列写入到文件之后,相当于文件持久保存了一个对象的信息
    反之,改该字节序列也可以从文件中读取对象信息,称之为反序列化
  • 对象流:
    对象序列化流:ObjectOutputStream
    对象反序列化流:ObjectInputStream
  • 注意:
    从流中读取支持java.io.Serializable或java.io.Externalizable接口的对象。 Serializable是一个标识接口,实现该接口,不需要重写任何方法
  • 成员变量如何不被序列化?
    给该成员加上一个transient关键字修饰,标识了该成员不参与序列化

代码演示用法:

import java.io.Serializable;

public class Student implements Serializable {
    
    
    private String name;
    private int age;
    transient String sex;

    public Student(){
    
    }

    public Student(String name, int age,String sex) {
    
    
        this.name = name;
        this.age = age;
        this.sex=sex;
    }

    public String getSex() {
    
    
        return sex;
    }

    public void setSex(String sex) {
    
    
        this.sex = sex;
    }

    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;
    }
}

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class StudentTest {
    
    
    public static void main(String[] args)throws Exception {
    
    
        Student zs=new Student("张三",23,"女");
        //序列化
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("E:\\IdeaProjects\\HuiHui\\data\\test.txt"));
        oos.writeObject(zs);
        //反序列化
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("E:\\IdeaProjects\\HuiHui\\data\\test.txt"));
        Object o=ois.readObject();
        //需向下转型,调用子类方法
        Student s=(Student)o;
        System.out.println(s.getAge()+"========="+s.getName()+"========"+s.getSex());
        oos.close();
        ois.close();

    }
}

在这里插入图片描述

三、总结

IO流:数据传输,读取或写入数据到文件,文件是存放在目录

File:文件或目录的抽象
	文件和目录可以通过File封装成对象
	构造没有无参构造,而通过有参构造创建对象时,对于File,其封装的并不是一个真正的文件,只是文件的路径,可存在可不存在,之后通过具体的操作把这个路径转化为具体的存在
	构造:File(String pathname)通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
		 File(String parent, String child)	从父路径名字符串和子路径名字符串创建新的 File实例。
		 File(File parent, String child)	从父抽象路径名和子路径名字符串创建新的 File实例。 
	创建的方法:不能通过路径来判断是目录还是文件
		public boolean createNewFile()	当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。 
		public boolean mkdir() 	创建由此抽象路径名命名的目录
		public boolean mkdirs() 	创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
		注意:如果创建文件,文件已存在,不会进行创建
			 如果创建目录,目录已存在,不会进行创建 
	相对路径:构造方法中的字符串,相对于当前项目所在路径,相对路径前不需要加上\\
	绝对路径:从盘符开始的路径
    	获取:         public boolean isDirectory()	判断抽象路径是否为目录 
		public boolean isFile()	判断抽象路径是否为文件
		public boolean exists() 	判断抽象路径是否存在
		public String getAbsolutePath()	返回抽象路径的绝对路径字符串  
		public String getPath()	返回抽象路径的路径字符串
		public String getName()	返回抽象路径表示路径或文件的名称
		publci String[] list()	返回抽象路径表示目录下的目录和文件的名称
		public File[] listFiles()	返回抽象路径表示目录下的目录和文件的对象	
		注意:list和listFiles不能获取到当前目录下,目录之中的内容
		     使用list和listFiles时,抽象路径不能指向文件
   	 删除方法
    		public boolean delete()	删除抽象路径表示的文件或目录
    		注意:删除目录时,只能删除空目录		

递归:方法调用方法   

IO流:用于数据传输
	分类:
		流向:输入流input 读数据
		       输出流outPut 写数据
	    	类型:字节 字节输入流 字节输出流
	         	       字符 字符 输入流 字符输出流 
	 
	注意:字节和字符的使用场景,记事本打开能读懂的可以使用字符流和字节流
	       读不懂的使用字节流
	       字节流是万能的,因为电脑最底层存储方式是二进制 字节的存储方式就是二进制

	FileOutPutStream:继承了字节输出流的父类OutPutStream
		使用方式: 1.创建对象(1.1调用系统创建空文件2.创建对象3.对象指向文件)
		               2.close()
		               3.调用writer方法

	构造:FileOutputStream(String name)	创建文件输出流以指定的名称写入文件。 
			FileOutputStream(new File)  创建文件输出流以写入由指定的 File对象表示的文件。 
			FileOutputStream(String name,boolean append)创建文件输出流以指定的名称写入文件。append - 如果是 true ,那么字节将被写入文件的末尾,而不是开头  	
			注意:前两个构造中boolean append默认是false,不能进行数据的追加,想要实现追加把false改为true 
		write三种方式:
			1.write(int b):写入一个字节  int和char可以相互转换
			2.write(byte[] b):按数组进行写入
			3.write(byte[] b,int off,int len):写入数组的一部分 偏移量off等同索引,len依次写入几个数据
		换行:windows:\r\n
			linux:\n
			mac:\r
			
输入流FileInputStream
	使用步骤:1.创建对象
	              2.关闭资源
	              3.读取数据
		例如:1.FileInputStream fis=new FileInputStream("C:\\test.txt");
			3.byte[] bytes=new byte[1024];
			  int i;
			  while((i=fis.read(bytes))!=-1){
			  		System.out.println(new String(bytes,0,i));
			  }
		    2.fis.close();
	读取数据的方法:
		1.int read() 从该输入流读取一个字节的数据。
 		2.int read(byte[] b) 从该输入流读取最多 b.length个字节的数据为字节数组。
 		3.int read(byte[] b, int off, int len)从该输入流读取最多 len字节的数据为字节数组
 		注意:使用方法3时,off表示数组中开始存储的位置,len表示存储多少个数据,需要注意索引越界的问题
 			byte数组的通常给1024
 			获取读取的数据时,选择new String(byte[] bytes,int offer,int lenght)解析byte数组中的数据,解决了可能会出现数据重复,和位置为空(就是值为0)
 			写入数据时,String类型的数据通过getBytes()转化为byte数组进行写入
 			写入数据时,Ineter类型的数据不能转化为byte,因为写入时,是以二进制的方式进行写入,需要转化为byte数组进行写入

字节缓冲流:简化字节流的操作,在文件和程序之间构建一个缓冲区来进行简化操作,避免了底层系统的多次调用
	BufferedOutputStream(OutPutStream out):OutPutStream是抽象类,选择通过FIleOutPutStream构建对象
	BufferedInputStream(InputStream in):InputStream是抽象类,选择通过FIleInputStream构建对象
	注意:写入数据时,数据是在缓冲区之中,需要flush或者直接close
编码集:
	编码:byte[] getBytes():使用平台的默认字符编码集将String存储字节数组
	       byte[] getBytes(String chareName):使用指定的编码集String存储字节数组
	解码:String(byte[] bytes):通过默认字符集解码指定的数组来构造新的String
	       String(byte[] bytes,String chareName):通过指定字符集解码指定的数组来构造新的String
	注意:编码和解码所使用的编码集要保持一直,不然会出现乱码问题

字符流:字符流构造中的参数不是具体的文件路径 而是字节流对象
          说明了字符流才具体的操作文件内容时,本质上还是通过字节流操作

   	   Read:抽象类,是字符输入流的父类
 	   Write:抽象类,是字符输出流的父类

    想要创建对象,需要通过具体的子类实现
	字符输出流OutpurStreamWriter:
		OutputStreamWriter(OutputStream out)  	创建一个使用默认字符编码的OutputStreamWriter。
		OutputStreamWriter(OutputStream out, Charset cs)	创建一个使用给定字符集的OutputStreamWriter。
	字符输入流:InputStreamReader:
		InputStreamReader(InputStream in) 	创建一个使用默认字符集的InputStreamReader。
		FileReader(InputStream in, Charset cs)	创建一个使用给定字符集的InputStreamReader。
		注意:同时使用字符输出流和字符输入流要注意,
			如果是先写再读的话,数据在缓冲区还没有写入文件时,已近去读了,结果读的就是空
			解决方式,写数据之后进行flush()
	字符流的简化写法:
		字符输出流FileWriter:
			FileWriter(String path)
			FileWriter(String path,boolean append)
		字符输入流FileReader:
			FileReader(String path)
			FileReader(String path,boolean append)
		注意:简化写法好处:简化了字符流的构建对象的方式,
		     弊端:不能指定编码集和不能指定缓冲区
    字符缓冲流:
    	字符缓冲输出流:BufferedWriter(Writer in)
    		newLine();换行 不用手动指定换行符,因为换行符有三种
    	字符缓冲输入流:BufferedReader(Reader out)	   
    		readLine():读取一行数据,不能读取换行符,因为换行符做分割了  
    序列化
	    序列化流:ObjectOutputStream(OutputStream in)
	    	  writerObject(Object o) 写入对象到文件
	    反序列化流:ObjectInputStream(InputStream out)	
	    	     readObject(Objectt o) 读取文件中对象的详细信息
	    Serializable接口:没有任何内容,只起到标识的作用,标识当前类可以进行序列化
	    给该成员加上一个transient关键字修饰,标识了该成员不参与序列化
	    注意:对象序列化必须实现Serializable接口	
	            序列化之后,如果类的结构发生改变,再进行序列化时,会报错,因为实现Serializable接口之后,当前类会与一个UID相关联,如果结构改变,UID就会发生改变,UID发生改变之后,在反序列化时,UID不匹配就会出现InvalidClassException
	    	 可以通过自定义UID来解决这样的问题
			自定义UID,静态的 最终的 long类型的 名字为serialVersionUID
			transient加载变量数据类型之前

四、习题

(一)填空题

1.Java IO流可以分为    节点流      和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通
过他们进行。

2.输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数据,read()            
方法给程序提供了一个从输入流中读取数据的基本方法。

3.read方法从输入流中顺序读取源中的单个字节数据,该方法返回字节值(0-255之间的一个整数),如
果到达源的末尾,该方法返回   -1        。

4.Java系统的标准输入对象是System.in,标准输出对象有两个,分别是标准输出 
__System.out_____和标准错误输出______System.err_____________。

5.Java IO体系中,____ObjectInputStream_______________是字节输入流,不仅提供了存取所有
Java基础类型数据(如:int,double 等)和String的方法,也提供了提供存取对象的方法。

6.Java IO体系中,____DataOutputStream________________是字节输出流,提供了可以存取所有
Java基础类型数据(如:int,double 等)和String的方法,但没有提供存取对象的方法。

7.___序列化_________是指将Java对象转换成字节序列,从而可以保存到磁盘上,也可以在网络上传
输,使得不同的计算机可以共享对象。

(二)选择题

1.	使用Java IO流实现对文本文件的读写过程中,需要处理下列(    B )异常。(选择一项)
		
	A	ClassNotFoundException
	B.	IOException
	C.	SQLException
	D.	RemoteException

2.	在Java的IO操作中,(   BD  )方法可以用来刷新流的缓冲。(选择两项)
		
	A	void release()
	B.	void close()
	C.	void remove()
	D.	void flush()

3.	在Java中,下列关于读写文件的描述错误的是(   b  )。(选择一项)
		
	A	Reader类的read()方法用来从源中读取一个字符的数据
	B.	Reader类的read(int n )方法用来从源中读取一个字符的数据
	C.	Writer类的write(int n)方法用来向输出流写入单个字符
	D.	Writer类的write(String str)方法用来向输出流写入一个字符串



4.	阅读下列文件定入的Java代码,共有(    C )处错误。(选择一项)
	import java.io.*;
public class TestIO {
	public static void main(String []args){
		String str ="文件写入练习";
		FileWriter fw = null;        //1
		try{
			fw = new FileWriter("c:\mytext.txt");  //2
			fw.writerToEnd(str);   //3
		}catch(IOException e){   //4
			e.printStackTrace();
		}finally{
			//此处省略关闭流
		}
	}
}
		
	A	0
	B.	1
	C.	2
	D.	3

5.	分析如下Java代码,有标注的四行代码中,有错误的是第( D  )处。(选择一项)
	import java.io.FileWriter;
import java.io.IOException;
public class Test {
	public static void main(String[ ] args) {
		String str = "Hello World";
		FileWriter fw = null;
		try {
			fw = new FileWriter("c:\\hello.txt"); // 1
			fw.write(str);                     // 2
		} catch (IOException e) {
			e.printStackTrace();                // 3
		} finally {
			fw.close();                        // 4
		}
	}
}
		
	A	1
	B.	2
	C.	3
	D.	4

6.	以下选项中关于如下代码的说法正确的是( A D  )。(选择二项)
	public class TestBuffered {
	public static void main(String[] args) throws IOException {
		BufferedReader br = 
			new BufferedReader(new FileReader("d:/bjsxt1.txt"));
		BufferedWriter bw = 
			new BufferedWriter(new FileWriter("d:/bjsxt2.txt"));
		String str = br.readLine();
		while(str !=null){ 
			bw.write(str); 
			bw.newLine();
			str = br.readLine();
		} 
		br.close();
		bw.close();	
	}
}
		
	A.	该类使用字符流实现了文件复制,将d:/bjsxt1.txt复制为d:/bjsxt2.txt
	B.	FileReader和FileWriter是处理流,直接从文件读写数据
	C.	BufferedReader和BufferedWriter是节点流,提供缓冲区功能,提高读写效率
	D.	readLine()可以读取一行数据,返回值是字符串类型,简化了操作

7.	InputStreamReader是转换流,可以将字节流转换成字符流,是字符流与字节流之间的桥梁。它的实现使用的设计模式是(  C   )。(选择一项)
		
	A.	工厂模式
	B.	装饰模式
	C.	适配器模式
	D.	代理模式

(三)判断题

1.假设文件”a.txt”的长度为100字节,那么当正常运行语句”FileOutputStreamf=new 
FileOutputStream(“a.txt”);”之后,文件”a.txt”的长度变为0字节。(T)

2.ByteArrayInutStream和ByteArrayOutputStream对内存中的字节数组进行读写操作,属于字节流,
属于处理流而不是节点流。 (    x )

3.实现Serializable接口的可以被序列化和反序列化。该接口中没有定义抽象方法,也没有定义常量。
( T    )

4.序列化是指将字节序列转换成Java对象,只有实现了Serializable接口的类的对象才可以被序列化。
(  X  ) 

(四)简答题

1.输入流和输出流的联系和区别,字符流和字节流的联系和区别
答:
Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。
输入流是将资源数据读入到缓冲Buffer中,输出流是将缓冲Buffer中的数据按照指定格式写出到一个指定的位置,所以这两个流一般同时使用,才有意义。

2.节点流和处理流的联系和区别
答:
节点流:可以从某节点读数据或向某节点写数据的流。如 FileInputStream
处理流:对已存在的流的连接和封装,实现更为丰富的流数据处理,处理流的构造方法必需其他的流对象参数。如 BufferedRead进行了操作(加工)的类,例如InputStreamReader.

3.列举常用的输入流和输出流并说明其特点,至少3对。
答:
1、字节流
字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是
·字节输出流:OutputStream 具体实现类 FileOutputStream
·字节输入流:InputStream 具体实现类 FileInputStream

2、字符流
在程序中一个字符等于2个字节,那么java提供了Reader、Writer两个专门操作字符流的类。
·字符输出流:Writer 具体实现类:OutputStreamWriter也叫转换流
·字符输入流:Reader 具体实现类:InputStreanReader也叫转换流

3.对象流:
·对象序列化流:ObjectOutputStream
·对象反序列化流:ObjectInputStream

4.说明缓冲流的优点和原理
答:
不带缓冲的流的工作原理:它读取到一个字节/字符,就向用户指定的路径写出去 读一个写一个 所以就慢了

带缓冲的流的工作原理:读取到一个字节/字符,先不输出,等凑足了缓冲的最大容量后一次性写出去,从而提高了工作效率

5.序列化的定义、实现和注意事项
答:
在java中只要一个类实现了Serializable接口的类就被认为是序列化的类,这种类的对象就是序列化的对象

只有被序列化的数据才允许被存储到文件、数据库之中或者通过网络协议进行传输,没有被序列化的数据是不能存储到硬盘上,不能通过网络协议进行网络传输

(五)编程题

1.实现字符串和字节数组之间的相互转换。必如将字符串“北京尚学堂bjsxt”转换为字节数组,并将字节数组再转换回字符串。

public class TransformTest {
    
    
    public static void main(String[] args) {
    
    
        String string="北京尚学堂bjsxt";
        byte[] bytes=string.getBytes();
        for(byte b:bytes){
    
    
            System.out.println(b);
        }
        String string1=bytes.toString();
        System.out.println(string1);

    }
}

2.复制文件夹data下面所有文件和子文件夹内容到data1
提示:涉及单个文件复制、目录的创建、递归的使用

public class Test1 {
    
    
    public static void main(String[] args) throws Exception{
    
    
        File file=new File("E:\\IdeaProjects\\HuiHui\\data");
        File filecooy=new File("E:\\IdeaProjects\\HuiHui\\data1");
        readfiecopy(file,filecooy);

    }
    public static void readfiecopy(File file,File filecopy)throws Exception{
    
    
        File[] files=file.listFiles();
        for(File f:files){
    
    
            if(f.isFile()){
    
    
                FileInputStream fis=new FileInputStream(f.getAbsolutePath());
                String path=filecopy.getAbsolutePath()+"\\"+f.getName();
                FileOutputStream fos=new FileOutputStream(path);
                byte[] bytes = new byte[1024];
                int len;
                while ((len=fis.read())!=-1){
    
    
                    fos.write(bytes,0,len);
                }
                fis.close();
                fos.close();
            }
            else {
    
    
                String path1=filecopy.getAbsolutePath()+"\\"+f.getName();
                File file1=new File(path1);
                file1.mkdirs();
                readfiecopy(f,file1);
            }
        }
    }
}

3.使用IO包中的类读取D盘上exam.txt文本文件的内容,每次读取一行内容,将每行作为一个输入放入ArrayList的泛型集合中并将集合中的内容使用加强for进行输出显示。

import java.io.Serializable;

public class Student implements Serializable,Comparable<Student> {
    
    
    private String id;
    private String name;
    private Integer age;
    public Student(){
    
    }

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

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

    public String getId() {
    
    
        return id;
    }

    public void setId(String id) {
    
    
        this.id = id;
    }

    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;
    }

    @Override
    public int compareTo(Student o) {
    
    
        int i=this.getAge()-o.getAge();
        return i;
    }
}
public class StudentTest {
    
    
    static TreeSet<Student> tree=new TreeSet<>();
    public static void main(String[] args)throws Exception {
    
    
        System.out.println("请以如下格式学生信息");
        System.out.println("1123#张三#12");
        acceptinformation();
        System.out.println(tree);
        writetxt();
    }
    public static void acceptinformation(){
    
    
        while(true){
    
    
            Scanner scanner=new Scanner(System.in);
            String string=scanner.next();
            if(string.equals("exit")){
    
    
                break;
            }
            else {
    
    
                String[] strings=string.split("#");
                Student s=new Student(strings[0],strings[1],Integer.valueOf(strings[2]));
                tree.add(s);
            }
            System.out.println("请继续输入学生信息,退出输入exit");

        }
    }
    public static void writetxt()throws Exception{
    
    
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("E:\\IdeaProjects\\HuiHui\\data\\text.txt"));
        for(Student student:tree){
    
    
            oos.writeObject(student);
            oos.write('\n');
        }
        oos.close();
    }

}

java入门基础学习(一)
java入门基础学习(二)
java入门基础学习(三)
java入门基础学习(四)
java入门基础学习(五)
java入门基础学习(六)
java入门基础学习(七)
java入门基础学习(八)
java进阶之常见对象(一)
java进阶之常见对象(二)
java进阶之冒泡排序
java进阶之选择排序
java进阶之面向对象(封装)
java进阶之面向对象(代码块、继承)
java进阶之面向对象(多态、抽象、接口)
java进阶之匿名内部类、访问修饰符、包

猜你喜欢

转载自blog.csdn.net/qq_45798550/article/details/108188201