Java深入理解——IO流

Java深入理解——IO流

输入输出流:

Input:输入

Output:输出

IO流是一个水流模型,IO理解成水管,把数据理解成水流

IO流的分类:

按照流的方向分为:输入流,输出流

  1. 输出流:以内存为基准,吧内存中的数据写出到磁盘文件或者网络介质中的流称为输出流
  2. 输入流:以内存为基准,把磁盘文件中的数据或者网络中的数据读入到内存中去的流称为输入流

按照流的内容分为:字节流,字符流

  1. 字节流:流中的数据最小单位是一个一个的字节
  2. 字符流:流中的数据最小单位是一个一个的字符

完整的流式家族:

image-20210727160401391

常用的流有

image-20210725213852900

附:

字节与字符:

  • ASCII 码中,一个英文字母(不分大小写)为一个字节,一个中文汉字为两个字节。
  • UTF-8 编码中,一个英文字为一个字节,一个中文为三个字节。
  • Unicode 编码中,一个英文为一个字节,一个中文为两个字节。
  • 符号:英文标点为一个字节,中文标点为两个字节。例如:英文句号 . 占1个字节的大小,中文句号 。占2个字节的大小。
  • UTF-16 编码中,一个英文字母字符或一个汉字字符存储都需要 2 个字节(Unicode 扩展区的一些汉字存储需要 4 个字节)。
  • UTF-32 编码中,世界上任何字符的存储都需要 4 个字节。

File类

由于IO流是对文件进行操作的,就需要用到File这个对象

构造方法:

  • File(File parent, String child)
    根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
  • File(String pathname)
    通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
  • File(String parent, String child)
    根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
  • File(URI uri)
    通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例。

注意:

  • 一个File对象代表硬盘中实际存在的一个文件或者目录。
  • File类构造方法不会给你检验这个文件或文件夹是否真实存在,因此无论该路径下是否存在文件或者目录,都不影响File对象的创建。
File file1 = new File("src\\test.txt");//相对路径
System.out.println(file1.length());

File file2 = new File("D:\\RootJavaProjectDir\\javaIndepthUnderstanding\\classLearning\\src\\test.txt");//绝对路径
System.out.println(file2.length());

String fatherStr = "D:\\RootJavaProjectDir\\javaIndepthUnderstanding\\classLearning\\src\\";//父路径
String childStr = "test.txt";//子路径
File file3 = new File(fatherStr,childStr);
System.out.println(file3.length());

File fileFather = new File("D:\\RootJavaProjectDir\\javaIndepthUnderstanding\\classLearning\\src\\");//父File对象
String childStr2 = "test.txt";//子路径
File file4 = new File(fileFather,childStr);
System.out.println(file4.length());

常用的获取类方法:

1、public String getAbsolutePath() :返回此File的绝对路径名字符串。

2、public String getPath():将此File转换为路径名字符串。

3、public String getName() :返回由此File表示的文件或目录的名称。

4、public long length() :返回由此File表示的文件的长度

eg:

@Test
public void test1(){
    File file1 = new File("src\\test.txt");//相对路径
    System.out.println("文件字节长度:"+file1.length());
    System.out.println("文件名:"+file1.getName());
    System.out.println("文件相对路径:"+file1.getPath());
    System.out.println("文件绝对路径"+file1.getAbsolutePath());
}

image-20210726155406998

判断类功能:

1、 public boolean exists() :此File表示的文件或目录是否实际存在。
2、 public boolean isDirectory() :此File表示的是否为目录。
3、public boolean isFile() :此File表示的是否为文件

创建删除功能:

  1. public boolean createNewFile()文件不存在,创建一个新的空文件并返回true,文件存在,不创建文件并返回false。
  2. public boolean delete() :删除由此File表示的文件或目录。
  3. public boolean mkdir() :创建由此File表示的目录。
  4. public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。

其中,mkdirs()和mkdir()方法类似,但mkdir(),只能创建一级目录,mkdirs()可以创建多级目录比如//a//b//c,所以开发中一般用mkdirs()

目录的遍历:

  • public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
  • public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录
@Test
public void Test2(){
    File file1 = new File("C:\\Program Files");

    //获取当前目录下的文件以及文件夹的名称。
    String[] list = file1.list();
    for (String s : list) {
        System.out.println(s);
    }

    //获取当前目录下的文件对象
    File[] files = file1.listFiles();
    for (File file : files) {
        System.out.println(file.getName());
    }
}
public static void main(String[] args) {
    File file = new File("D:\\Download");
    if (file.exists()){
        fileTraver(file);
    }
}

public static void fileTraver(File file) {
    System.out.println(file.getName());
    if (!file.isDirectory()){
        return;
    }
    File[] files = file.listFiles();
    for (File file1 : files) {
        fileTraver(file1);
    }

}

FileInputStream

FileInputStream继承自InputStream,作用为从文件中读取字节

构造方法

  • FileInputStream(File file)
    通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
  • FileInputStream(String name)
    通过打开一个到实际文件的连接(就是文件路径)来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。

读取字节数据

读取字节:read方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1

  1. 一个字节一个字节的读取:

    @Test
    public void test2() throws IOException {
        FileInputStream fis = new FileInputStream("src/test.txt");
        int read1 = fis.read();
        System.out.println((char) read1);
        int read2 = fis.read();
        System.out.println((char) read2);
        int read3 = fis.read();
        System.out.println((char) read3);
        fis.close();
    }
    

image-20210728202431877

image-20210728202201825

  1. 单个字节循环读取

    @Test
    public void test3() throws IOException {
        FileInputStream fis = new FileInputStream("src/test.txt");
        int read;
        while(  (read = fis.read()) != -1){
            System.out.println((char) read);
        }
        fis.close();
    }
    

image-20210728203018268

  1. 桶式读取(普通读取):

    @Test
    public void test4() throws IOException {
        FileInputStream fis = new FileInputStream("src/test.txt");
        byte[] read = new byte[2];
        int len;
        while((len = fis.read(read)) != -1) {
            System.out.println(new String(read));
        }
        fis.close();
    }
    

    image-20210728211026809

注意,这里由于byte数组只有2个字节输出,文件有5个字节,会出现自动填充的现象,结果输出如下:

image-20210729192833408

原因如下图:

image-20210729193517185

为了解决这个问题我们在构建字符串时,应从0到read方法所读取到的长度截取,并且使用较大桶(一般为1024,即1kb)

@Test
public void test5() throws IOException {
    FileInputStream fis = new FileInputStream("src/test.txt");
    byte[] read = new byte[1024];
    int len;
    while((len = fis.read(read)) != -1){
        System.out.println(new String(read,0,len));
    }
    fis.close();
}

注意:在执行完方法后要记得用close方法关闭资源

FileOutputStream

FileOutputStream用来写出数据通过write方法,而write方法主要分为三种

  1. public void write(int b)

    public void test1() throws IOException {
        FileOutputStream fos = new FileOutputStream("src/test.txt");
        fos.write(65);
        fos.close();
    }
    //在文件中写入字节为65(A)的数据
    

    image-20210729215309692

  2. public void write(byte[] b)

    public void test2() throws Exception{
        FileOutputStream fos = new FileOutputStream("src/test.txt");
        byte[] bytes = "今天星期几".getBytes(StandardCharsets.UTF_8);
        fos.write(bytes);
        fos.close();
    }
    

    image-20210729220139966

    这个方法会覆盖文本中的内容

  3. public void write(byte[] b,int off,int len) //从off索引开始,len个字节

由上文可知,我们每次创建流对象都会清空目标文件中的数据,**如何保留原有文件数据,实现追加数据并且实现换行?**其实在FileOutputStream的另外的构造方法中给出了答案

FileOutputStream(File file, boolean append)

FileOutputStream(String name, boolean append)

当我们把这两个构造方法设置为true时,就表示可以追加数据

public void test3() throws Exception{
    FileOutputStream fos = new FileOutputStream("src/test.txt",true);
    byte[] bytes = "今天星期一".getBytes(StandardCharsets.UTF_8);
    fos.write(bytes);
    fos.close();
}
//执行前:今天星期几
//执行后:今天星期几今天星期一

回车换行符的说明:

回车符\r和换行符\n :

  • 回车符:回到一行的开头(return)。
  • 换行符:下一行(newline)。
    系统中的换行:
  • Windows系统里,每行结尾是 回车+换行 ,即\r\n;
  • Unix系统里,每行结尾只有 换行 ,即\n;
  • Mac系统里,每行结尾是 回车 ,即\r。

eg:

public void test4() throws Exception{
    FileOutputStream fos = new FileOutputStream("src/test.txt");
    byte[] bytes = new byte[]{65,66,67,68,69,70,71,72,73,74,75,76,77,78};
    for (int i = 1; i <= bytes.length; i++) {
        fos.write(bytes[i-1]);
        if (i % 4 == 0){
            fos.write("\r\n".getBytes(StandardCharsets.UTF_8));
        }
    }
    fos.close();
}

执行结果:

image-20210730154435076

字符流

由于字节流在处理文本文件时,需要对文件进行编解码,比较麻烦,故Java推出了字符流用来处理文本文件。我们主要学习FileReader,和FileWriter

FileReader

父类是Reader,FileReader的主要方法还是read

int read()
读取单个字符。
int read(char[] cbuf)
将字符读入数组。
abstract int read(char[] cbuf, int off, int len)
将字符读入数组的某一部分

  • 单个字符循环读取
public void test1() throws Exception{
    FileReader fr = new FileReader("src/test.txt");
    int i = 0;
    while((i = fr.read()) != -1){
        System.out.print((char) i);
    }
    fr.close();
}

image-20210730181937339

可以读取换行符

  • 字符数组截取长度读取

    public void test2 () throws Exception{
        FileReader fr = new FileReader("src/test.txt");
        int len = 0;
        char[] chars = new char[1024];
        while((len = fr.read(chars)) != -1){
            System.out.println(new String(chars, 0, len));
        }
    }
    

image-20210730183410493

FileWriter

作用为把字符写出到文件,其父类是Writer,构造时使用系统默认的字符编码和默认字节缓冲区。

构造方法还是以前我们熟悉的通过文件路径名和File对象来构造

FileWriter的常用的成员方法为:

abstract void flush()
刷新该流的缓冲。
void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(int c)
写入单个字符。
void write(String str)
写入字符串。
void write(String str, int off, int len)
写入字符串的某一部分。

值得注意的几点是:

  • 如果我们创建对象时磁盘中没有此真实文件会怎样?

    那么会自动创建一个文件,不写路径就直接创建在Javaproject工程的下面

  • 写入文件时,文件原本就有数据会怎样?

    会覆盖掉原来的内容

  • 怎样实现换行?

    与前面FileInputStream一样,在Windows系统中写入\r\n到文件中即可

  • 怎么向原有文件中追加数据?

    与前面FileInputStream一样,FileWriter fw = new FileWriter("文件名",true);

演示:

public void test3() throws Exception{
    FileWriter fw = new FileWriter("src/test.txt");
    //write方法的第一种重载形式,
    fw.write(65);
    fw.write(66);
    fw.write(67);
    fw.write(68);

    fw.write("\r\n");

    //第二种重载形式:直接写入字符串
    fw.write("远方传来风笛~");

    fw.write("\r\n");

    //第三种重载形式,截取字符数组
    char[] chars = new char[]{'a','b','c','d','e'};
    fw.write(chars,0,3);

    fw.close();//一定要记得close
}

注意:与FileOutputStream不同的是,FileWriter如果不用close方法关闭资源,数据只是保存到缓存区,并没有保存到文件

close与flush:

flush :刷新缓冲区,把数据存入文件,流对象可以继续使用。
close:先刷新缓冲区,把数据存入文件,然后通知系统释放资源。流对象不可以再被使用了。

缓冲流

缓冲流可以提高字节字符读取写入的性能,带一个前缀Buffered

与FileInputStream,FileOutputStream,FileReader,FileWriter对应的,缓冲流也有以下四种:

  • BufferedInputStream:字节缓冲输入流
  • BufferedOutputStream:字节缓冲输出流
  • BufferedReader:字符缓冲输入流
  • BufferedWriter:字符缓冲输出流

字节缓冲流

与普通的字节流相比,字节缓冲流的构造方法比较特殊

  • BufferedInputStream(InputStream in)
    创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
  • BufferedInputStream(InputStream in, int size)
    创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
  • BufferedOutputStream(OutputStream out)
    创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
  • BufferedOutputStream(OutputStream out, int size)
    创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

创建对象实例如下:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src/test.txt"));

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src/test.txt"));

字符缓冲流的主要使用方法与前面的FileInputStream和FileOutputStream差不多,主要是性能上更高效一些

下面我们来探究缓冲流与前面普通的IO流的性能差异,以复制一个100多MB视频文件为例

public void test2(){
    long begin = System.currentTimeMillis();
    int len;
    byte[] bytes = new byte[1024];
    try (FileInputStream fis = new FileInputStream("D:\\音乐\\血腥爱情故事.mp4");
    FileOutputStream fos = new FileOutputStream("D:\\音乐\\普通流.mp4")){
        while((len = fis.read(bytes)) != -1){
            fos.write(bytes,0,len);
        }

    }catch (Exception e){
        e.printStackTrace();
    }
    long end = System.currentTimeMillis();
    System.out.println("用时:"+(end-begin)+"ms");
}

普通IO流用时:1781ms

public void test1() throws FileNotFoundException {

    long begin = System.currentTimeMillis();
    byte[] bytes = new byte[1024];
    int len;
    try( BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\音乐\\血腥爱情故事.mp4"));
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\音乐\\缓冲流得到的.mp4"))) {
        while((len = bis.read(bytes)) != -1){
            bos.write(bytes,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    long end = System.currentTimeMillis();
    System.out.println("用时:"+(end-begin)+"ms");

缓冲流用时:235ms

可以看到看到二者相差了8倍之多,如果文件更大,二者差距讲更加明显,所以缓冲流性能更优,一般操作大文件时,建议使用缓冲流

缓冲流速度快的原因:

计算机访问外部设备或文件,要比直接访问内存慢的多。如果我们每次调用read()方法或者writer()方法访问外部的设备或文件,CPU就要花上最多的时间是在等外部设备响应,而不是数据处理。
为此,我们开辟一个内存缓冲区的内存区域,程序每次调用read()方法或writer()方法都是读写在这个缓冲区中。当这个缓冲区被装满后,系统才将这个缓冲区的内容一次集中写到外部设备或读取进来给CPU。使用缓冲区可以有效的提高CPU的使用率,能提高整个计算机系统的效率。

在读写数据时,让数据在缓冲区能减少系统实际对原始数据来源的存取次数,因为一次能做多个数据单位的操作,相较而言,对于从文件读取数据或将数据写入文件,比起缓冲区的读写要慢多了。所以使用缓冲区的 流,一般都会比没有缓冲区的流效率更高,拥有缓冲区的流别称为缓冲流,包括BufferedInputStream、BufferedOutputStream类和BufferedReader、BufferedWriter类。缓冲流把数据从原始流成块读入或把数据积累到一个大数据块后再成批写出,通过减少通过资源的读写次数来加快程序的执行

字符缓冲流

包括BufferedReader,和BufferedWriter,其构造与字符缓冲流类似

BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)
创建一个使用指定大小输入缓冲区的缓冲字符输入流。

BufferedWriter(Writer out)
创建一个使用默认大小输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz)
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

字符缓冲流与之前的字符流基本使用方法一致,但是字符缓冲流有其特有方法

  • BufferedReader:public String readLine(): 读一行数据。 读取到最后返回null
  • BufferedWriter:public void newLine(): 换行,由系统属性定义符号。

下面演示readLine方法:

public void test3(){
    try(BufferedReader br = new BufferedReader(new FileReader("src/test.txt"));) {
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}
//文件内容:
//ABCD
//远方传来风笛~
//abc
//输出内容:
//ABCD
//远方传来风笛~
//abc

newLine的演示:

try(BufferedWriter bw = new BufferedWriter(new FileWriter("src/test.txt"))){
    bw.write("Why we're all part of the masterplan");
    bw.newLine();
    bw.write("Oasis" + "-" + "The Masterplan");
}catch (IOException e){
    e.printStackTrace();
}

转换流

字节文件转换为字符文件输出时,需要采用与编码方式相同的解码方式,不然就会乱码,下面是一些常见的编码方式

  • GBK:最常用的中文码表,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
  • UTF-8:UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
    • 128个US-ASCII字符,只需一个字节编码。
    • 拉丁文等字符,需要二个字节编码。
      大部分常用字(含中文),使用三个字节编码。
    • 其他极少使用的Unicode辅助字符,使用四字节编码。

编解码不一致导致乱码:

Windows系统默认采用GBK编码,而idea采用UTF-8,由此就会产生乱码问题

public void test1() throws IOException {
    FileInputStream fis = new FileInputStream("D:\\测试.txt");
    byte[] bytes = new byte[1024];
    int len = 0;
    while((len = fis.read(bytes)) != -1){
        System.out.println(new String(bytes));
    }
    fis.close();
}

String的构造方法使用的是UFT-8编码,而文件我们采用GBK编码,故执行结果就会乱码

image-20210801194907289

而文件原文是

image-20210801195311720

此时就需要用到转换流,来达到统一解码的目的

image-20210801200130672

InputStreamReader

是Reader的子类,他是从字节流到字符流的桥梁

构造方法如下:

InputStreamReader(InputStream in)
创建一个使用默认字符集的 InputStreamReader。

InputStreamReader(InputStream in, String charsetName)
创建使用指定字符集的 InputStreamReader。

常用的就是第二种指定编码的,示例如下

public void test2() throws IOException{
    //指定编码,文件为GBK编码
    InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\测试.txt"), "GBK");
    int len;
    char[] chars = new char[1024];
    while((len = isr.read(chars)) != -1){
        System.out.println(new String(chars,0,len));
    }
    isr.close();
}

执行截图:

image-20210801204347909

OutputStreamWriter

从字符到字节的桥梁,是Writer的子类写入到文件时,可以指定字符集

构造方法与InputStreamReader类似

OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。

下面是示例:

public void test3() throws IOException{
    //指定文件编码为GBK
    OutputStreamWriter osw  = new OutputStreamWriter(new FileOutputStream("D:\\测试.txt"),"GBK");
    osw.write("你的脸像田里熟透的番茄");
    osw.close();
}

序列化流

序列化是Java提供的一种将对象用一个字节序列表示的机制,该字节序列包括该对象的数据,类型和属性等信息,字节序列写出到文件后,相当于文件中持久保存了一个对象的信息

而将该字节序列从文件中读取回来,重构对象的操作,称作反序列化

字节--------------------------------------->对象:ObjectInputStream,反序列化

对象--------------------------------------->字节:ObjectOutputStream,序列化

ObjectOutputStream

作用为将Java对象的原始数据类型写出到文件,实现对象的持久储存

构造方法:

ObjectOutputStream(OutputStream out)
创建写入指定 OutputStream 的 ObjectOutputStream

一个对象想要序列化,必须实现Serializable接口,如果有一个属性不需要可序列化,则该属性必须著名是使用transient,修饰Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

常用的方法就是:

public final void writeObject(Object obj):将指定的对象写出。

package stage04.IODemo;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @author YJL
 */
public class IODemo6 {
    public static void main(String[] args) {
        Student student = new Student();
        student.age = 18;
        student.name = "张三";
        student.gender = "女";
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.txt"));
            oos.writeObject(student);
            oos.close();
            System.out.println("对象已序列化");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @author YJL
     */
    static class Student implements Serializable {
        private int age;
        private String name;
        private transient String gender;

        public Student() {
        }

        public int getAge() {
            return age;
        }

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

        public String getName() {
            return name;
        }

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

        public String getGender() {
            return gender;
        }

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

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

ObjectInputStream

称为反序列化流,用于将之前使用ObjectOutputStream序列化的原始数据恢复为对象

构造方法:

```public ObjectInputStream(InputStream in)`: 创建一个指定InputStream的ObjectInputStream。``

  • 第一种方法

    通过对象的class文件,调用ObjectInputStream的readObject方法,进行反序列操作

    ```public final Object readObject ()` : 读取一个对象``

    public static void main(String[] args) {
        IODemo6.Student student = null;
        try {
            FileInputStream fis = new FileInputStream("test.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);
            student = (IODemo6.Student) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } catch (ClassNotFoundException e) {
            System.out.println("class not found");
            e.printStackTrace();
            return ;
        }
        System.out.println("Name:"+student.getName());
        System.out.println("age:"+student.getAge());
        System.out.println("gender:"+student.getGender());
    }
    

    执行结果:

    image-20210803183459469

    这种方式要求要能够找到class文件的类,如果找不到要抛出一个ClassNotFound异常

  • 第二种方法

    如果能够找到class文件,但是class文件在序列化之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。发生这个异常的原因有:

    1. 该类的序列版本号与从流中读取的类描述符的版本号不匹配
    2. 该类包含未知数据类型
    3. 该类没有可访问的无参数构造方法

Serializable接口给需要序列化的类,提供了一个序列版本号,serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

static class Student implements Serializable {
    private int age;
    private String name;
    private transient String gender;
    private static final long serialVersionUID = 1L;
    public Student() {
    }
    
    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public String getGender() {
        return gender;
    }

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

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

打印流

作用:方便可以快速搞笑的写数据出去

PrintStream

可以打印一切数据,int,double,float,char,Object等

构造器:

public PrintStream(OutputStream os);

public PrintStream(String filepath);

public PrintStream(File file)

常用方法为print(),写啥打印啥

public static void main(String[] args) throws FileNotFoundException {
    PrintStream ps = new PrintStream("D:\\RootJavaProjectDir\\javaIndepthUnderstanding\\classLearning\\src\\test1.txt");
    ps.println(212);
    ps.println("啦啦啦");
    ps.println(false);
    ps.println(ps);
    ps.close();
}

Properties属性类

用于保存数据到属性文件,在框架的底层使用(配置文件)

Properties集合属于Map集合,Properties代表的是一个属性文件,可以把键值对的数据存入到一个属性文件中去

构造方法

public Properties() :创建一个空的属性列表。

基本的储存方法

public Object setProperty(String key, String value) : 保存一对属性。
public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。
public Set stringPropertyNames() :所有键的名称的集合。

void store(OutputStream out, String comments)
以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。

示例:

public static void main(String[] args) throws IOException {
    Properties properties = new Properties();
    properties.setProperty("admin","1234789");
    properties.setProperty("password","7890");
    System.out.println(properties);

    OutputStream os = new FileOutputStream("D:\\RootJavaProjectDir\\javaIndepthUnderstanding\\test1.properties");
    /**
     * 参数一:被保存数据的输出管道
     * 参数二:保存注释,对对象数据进行解释说明
     */
    properties.store(os,"happy ending");
}

生成的properties文件中就会存放数据

image-20210803224513854

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值