IO + File 详细基础知识

这篇具有很好参考价值的文章主要介绍了IO + File 详细基础知识。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

IO + File

全面解析Java-IO流

一、 File

File: 表示系统中的文件或者文件夹的路径。

利用File我们可以获取文件信息(大小,文件名,修改时间)、判断文件的类型、创建文件/文件夹、删除文件/文件夹等

File类只能对文件本身进行操作,不能读写文件里面存储的数据。

二、IO流

2.0 IO流介绍

存储和读取数据的解决方案

用于读写文件中的数据(可以读写文件,或网络中的数据…)

​ 写 - output

​ 读 - input

这个读和写的参照物是以“程序”为参照物,或者说以“内存”

作用:

​ 用于读写数据(本地文件,网络)

IO流按照流向可以分类哪两种流?

​ 输出流: 程序 - > 文件

​ 输入流: 文件 -》 程序

IO流按照操作文件的类型可以分类哪两种流?

​ 字节流:可以操作所有类型的文件

​ 字符流: 只能操作纯文本文件

IO + File 详细基础知识

纯文本文件: Windows自带的记事本打开能正常显示(不是乱码)

IO + File 详细基础知识

2.1 字节流

2.1.1 字节输出流 - FileOutputStream

2.1.1.1 write方法
方法名称 说明
void write(int b) 一次写一个字节数据
void write(byte[ ] b) 一次写一个字节数组数据
void write(byte[ ] b , int off , int len ) 一次写一个字节数组的部分数据
2.1.1.2 字节输出流细节

① 创建字节输出流对象

  • 创建FileOutputStream对象时,参数可以使字符串表示的路径,也可以是File类型文件。

​ 如果我们传入的参数是字符串表示的路径,底层也会帮我们new一个File类型的文件。

  • 如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的

  • 如果文件已经存在,则会清空文件内容,若不想清空,则在创建对象时添加“true”参数

② 写数据

  • write方法的参数是整数,但是实际写到本地文件中的是整数在ASCII上对应 的字符

    如 91 -> a , 100 ->d

③ 释放资源

关闭流,释放资源。

如果我们不关闭流,我们删除文件的时候会有一个提示,“操作无法完成,因为文件在…中打开,请重新尝试…”

IO + File 详细基础知识

2.1.1.3代码实现
public class FileOutputStreamTest {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            /*为什么会加true? 在原文件的基础上追加内容,不加true的话,会将原文件清空然后再追加内容*/
            /*在此路径下,如果文件不存在,会自己创建一个*/
             fos = new FileOutputStream("E:\\IDEA\\Java\\StudentTwo\\src\\IOTest\\JavaTest.txt",true);
             byte[] bytes ={97,98,99,10};
             /*fos.write(bytes); 将bytes数组整组的写入*/
            /*下面这段代码是将数组中的部分内容写入*/
            fos.write(bytes,0,3);
 
            String s = "我是中国人!";
            /*将字符串转换成byte数组的形式,然后写入*/
            bytes = s.getBytes();
            fos.write(bytes);
            /*写完之后,一定记得刷新!*/
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.1.1.4 换行与续写
  • 换行写:

写出一个换行符即可

​ **Windows: \r\n ** 意思就是先回车再换行,这是之前系统的问题,然后Windows就延续下来了(之前回车是将光标放到这一行的前面,换行是将光标移动到下一行)

​ Linux: \n

​ Mac: \r

​ 在Windows操作系统当中,java对回车换行进行了优化。虽然完整的是\r\n,但是我们写其中一个\r或者\n,java也可以实现换行,因为java在底层会补全,当然也建议不要省略,尽量写全。

    String wrap = "\r\n";
    byte[] bytes = wrap.getBytes();
    fos.write(bytes);
  • 续写

在创建对象时将续写开关打开

fos = new FileOutputStream("文件路径",true);

2.1.2 字节输入流 - FileInputStream

2.1.2.1 read()方法
方法名称 说明
public int read() 一次读取一个字节数据
public int read(byte[] buffer) 一次读一个字节数组数据
2.1.2.2 字节输入流细节

① 创建字节输入流对象

​ 文件不存在,直接报错

② 读数据

  • fis.read() 方法一次读一个字节,读出来的数据是ASCII上对应的数字

  • 读到文件末尾了,read方法返回-1

    ​ 比如我们文件中的数据是“abcde”,刚开始fis.read()默认指向第一个数据"a",调用方法后将"a"读取,并且指针移动到"b",再调用fis.read()方法后读取"b",并且指针移动到"c",…最终fis.read()方法执行“e”之后,什么也没有了,此时数据为“-1”,表示文件末尾,没有数据了

​ 但是每次读取一个字节,速度会非常的慢!!!

  • 一次读一个字节数组的数据,每次读取会尽可能把数组填满

​ public int read(byte[] buffer)此方法即可。

​ 虽然数组长度越大读取速度越快,但是不要忘了数组会占用内存空间。

​ 我们在创建byte数组的时候一般会创建1024的整数倍,比如1024×1024×5,即每次读取大小为5M的数据。

1024个字节就是1Kb,1024个1Kb就是1M,再×5,就是5M

  • ”把数组填满“,这句话挺重要

    假如文件中有数据"abcde"五个字符,我们byte数组的长度是2,则每次读取两个字符

    第一次读取的时候,len=2,读取到"ab",并且byte数组中存储的是“ab”对应的字节,此时read指针指向"c"

    第二次读取的时候,len=2,读取到"cd",并且byte数组中存储的是"cd"对应的字节,将之前存储的“ab”所对应的字节给覆盖掉,此时read指针执行“e”

    第三次读取的时候,只剩下“e”这么一个字符了,len=1,读取到"e",并存储到数组当中,将上一次读取“cd”中的“c"给覆盖掉,即现在获取的是"ed"

    第四次读取的时候,文件中已经没有内容了,就读取到"-1",代表文件读取完成

IO + File 详细基础知识

所以我们在读取的时候应该按照下面

IO + File 详细基础知识

③ 释放资源

同上

2.1.2.3 代码实现

操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
 
/*FileInputStreamTest 文件字节输入流 任何文件都可以采用这个流读取*/
/*字节输入流,是从硬盘向内存中读入*/
public class FileInputStreamTest {
    public static void main(String[] args) {
        /*为什么在这个地方声明? 为了方便将流关闭*/
        FileInputStream fis =null;
        try {
            fis =  new FileInputStream("E:\\IDEA\\Java\\StudentTwo\\src\\IOTest\\JavaTest.txt");
            /*用字节数组,减少了内存和硬盘的交互,提高了运行效率
               一次最多读取bytes.length个字节*/
            byte[] bytes = new byte[4];
            int readCount=0;
            /*readCount是-1时,说明已经读完了*/
            /* fis.read(bytes)的返回值是读取到的字节的数量,而且返回的是字节的ascll码*/
            while(  (readCount= fis.read(bytes)) !=-1){
                /*读到多少个,就转换输出多少个,不会出现重复读取的问题*/
                System.out.println( new String(bytes,0,readCount));
                /*String(byte[] bytes, int offset, int length)
                 构建了一种新的 String通过解码指定的字节数组使用平台的默认字符集。*/
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fis !=null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.2 字节流 - 拷贝文件

注意:先开的流,最后再关闭

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
 
/*利用字节输入输出流完成文件的拷贝*/
public class CopyTest01 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
 
        try {
            fis = new FileInputStream("E:\\IDEA\\Java\\StudentTwo\\src\\IOTest\\JavaTest.txt");
            /*这个地方是将文件复制到的目的地*/
            fos = new FileOutputStream("D:\\JavaTest.txt");
            /*1024是1kb  1024*1024是1M   这里的意思是,一次性读取1M的内容*/
             byte[] bytes = new byte[1024*1024];
            
             int readCount=0;
            
             while ( (readCount = fis.read(bytes)) !=-1){
                 /*读多少,写多少 */
                 fos.write(bytes,0,readCount);
             }
            fos.flush();//*因为可能有一些数据还在管道里面33*/
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fis!=null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.3 字符流

字符流底层其实就是字节流

字符流 = 字节流 + 字符集

对于纯文本文件进行读写操作

特点

输入流Reader: 一次读一个字节,遇到中文时,一次读多个字节(具体读取多个和字符集有关)

输出流Writer: 底层会把数据按照指定的编码方式进行编码,编程字节再写到文件中

2.3.1 字符输入流 - FileReader

2.3.1.1 细节

① 创建字符输入流对象

构造方法 说明
public FileReader(File file) 创建字符输入流关联本地文件
public FileReader(String pathname) 创建字符输入流关联本地文件

如果文件不存在便报错

②读取数据

成员方法 说明
public int read() 读取数据,读到末尾返回-1
public int read(char[] buffer) 读取多个数据,读到末尾返回-1

按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个整数

读到文件末尾了,read方法返回-1

read()方法

在读取之后,方法的底层还会进行解码并转成十进制,最终把这个十进制的数据作为返回值,这个十进制的数据也表示在字符集上的数字。

比如文件中一个英文字符的二进制数据“0110 0001”,read方法进行读取,解码并转成十进制97。

比如文件中一个中文字读的二进制数据"11100110 10110001 10001001",read方法进行读取,解码转成十进制“27721”。

所以我们不能将char,我们应该new String进行转化

read(char[] buffer)方法

char[] chars = new char[4];
 
fr.read(chars);
 
for(char c: chars){
 System.out.println(c);
 
}

IO + File 详细基础知识

然后我们发现如果read方法是无参的话,读出来的数据如果不强转就是int类型数字,强转为char后才是对应的字符,但是read方法是有参,却能把数据完完全全输出,并不需要强转。

说明:

空参read方法: 一次读取一个字节,遇到中文一次读多个字节,把字节码并转成十进制返回

有参read方法: 把读取字节,解码,强转三步合并了,强转之后的字符放到数组中

③ 释放资源

2.3.1.2 代码实现
/*文件字符输入流  只能读取普通文本
*  读取文本内容的时候,比较方便和便捷*/
public class FileReaderTest {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            /*读入的文件的目录,这个文件只能是普通的文本文件*/
            fr = new FileReader("E:\\IDEA\\Java\\StudentTwo\\src\\IOTest\\JavaTest.txt");
            /*一次读入4个字符*/
            char[] chars = new char[4];
            
            int readCount =0;
 
            while(  (readCount = fr.read(chars)) !=-1){
                System.out.println( new String(chars,0,readCount));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fr!=null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.3.1.3 底层原理

在我们创建对象从数据源(UTF-8)中读取内容到内存时,内存中会有一个长度为8192的字节数组作为缓冲区

**read()方法先从缓冲区中读取,如果缓冲区中没有就从文件中读取内容并尽可能的填满缓冲区,这样效率更高,减少了频繁从硬盘中读取数据的过程。**下面的例子“a我”是四个字节,所以缓冲区中此时只有四个字节。

但是第一次以read()方法是读取的第一个字节。

第二次read()方法依然是遵照这样,先从缓冲区读取,发现缓冲区中存在数据,便直接从缓冲区中读取。注意,第二次读取时中文,一次性读取三个字节,并按照中文的形式进行解码。

第三次read()方法从缓存区中读取,发现缓存区已经读完了,再读取文件,发现文件中的内容也读完了,便返回-1

说明:

空参read方法: 一次读取一个字节,遇到中文一次读多个字节,把字节码并转成十进制返回

有参read方法: 把读取字节,解码,强转三步合并了,强转之后的字符放到数组中

IO + File 详细基础知识

另外说明: 字节流是没有缓冲区的!!!!!

2.3.2 字符输出流 - FileWriter

2.3.2.1 细节

① 创建对象

构造方法 说明
public FileWriter(File file) 创建字符输出流关联本地文件
public FileWriter(String pathname) 创建字符输出流关联本地文件
public FileWriter(File file,boolean append) 创建字符输出流关联本地文件,续写
public FileWriter(String pathname,boolean append) 创建字符输出流关联本地文件,续写

② write方法

IO + File 详细基础知识

如果write方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符

③关闭流

2.3.2.2 代码实现
import java.io.FileWriter;
import java.io.IOException;
/*利用字符输出流向文件中输入某些文本内容   只能输出普通的文本内容*/
public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter fw =null;
        try {
            /*如果这个构造方法上加上true的话,就表示在原文件的基础上再追加内容*/
            fw = new FileWriter("E:\\IDEA\\Java\\StudentTwo\\src\\IOTest\\JavaTest.txt");
            char[] chars=  {'我','是','一','个','大','帅','哥'};
            fw.write(chars);
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fw!=null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
2.3.2.3 底层原理

在创建对象的时候,底层也创建了一个8192的字节数组,也就是缓冲区。

也就是说我们调用write方法后并没有直接将内容写入到文件中,而是写入了字节数组(缓冲区)

那什么时候才会写入到文件?

① 缓冲区满了

② 手动调用flush方法,将缓冲区中的数据刷新到文件中

③ 调用close()方法,在断开连接之前,会检查缓冲区中是否有数据,有的话就刷新到本地文件中

成员方法 说明
public void flush() 将缓冲区中的数据,刷新到本地文件中
public void close() 释放资源/关流

flush:刷新之后,还可以继续往文件中写出数据

close关流:断开通道,无法再往文件中写出数据

2.4 缓冲流

字符流已经有缓冲区了,字符缓冲流提高的效率不是很明显

但是字节流没有缓冲区,字节缓冲流提高的效率很明显

IO + File 详细基础知识

2.4.1 字节缓冲流

字节缓冲流:

原理: 底层自带了长度8192的缓冲器提高性能(与字符流一样)

缓冲流是对基本流做的包装

方法名称 说明
public BufferedInputStream(InputStream is) 把基本流包装成高级流,提高读取数据的性能
public BufferedOutputStream(OutputStream os) 把基本流包装成高级流,提高读取数据的性能
2.4.1.1 拷贝文件
public class BufferedStreamDemo1 {
    public static void main(String[] args) throws IOException {
//      TODO 创建缓冲流对象   BufferedInputStream 第二个参数可以指定缓冲区大小
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/杂/test/test.txt"));
//      BufferedOutputStream 的第二个参数可以指定缓冲区大小
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:/杂/test/testDemo.txt"));

//      TODO 循环读取并写到目的地
//       一次读取一个字节        
//        int b=0;
//        while ( (b=bis.read()) !=-1){
//            bos.write(b);
//        }
//      TODO 一次读写多个字节
        byte[] bytes = new byte[1024 * 1024]; //1M
        int len ;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes,0,len);
        }

//      TODO 不需要关闭基本流,底层帮我们关了
        bos.close();
        bis.close();
    }
}
2.4.1.2 读写原理

**读取:**基本流读取数据源中的数据,然后交给缓冲输入流,准确的来说是将数据放入到缓冲区(默认8192个字节,一次性读取8192个字节)

​ 之后read() 方法 以及 read(byte[]) 方法都是从缓冲区读取,缓冲区没有之后再从文件中读取,直到-1为止

**写出:**由缓冲输出流(缓冲区默认大小也是8192)交给基本流,最终还是由基本流写入文件

注意: 缓冲输入流和缓冲输出流都有一个缓存区,但是不是一个东西!!!!

IO + File 详细基础知识

速度是快在哪个地方?

减少了与硬盘的交互次数

下面蓝色的框框是在内存中读取的,倒手的时间非常快。节省的时间是读和写与硬盘交互的时间。如果将下面int b 换成字节数组,倒手的速度会更快

IO + File 详细基础知识

2.4.2 字符缓冲流

2.4.2.0 字符缓冲流细节

底层自带长度8192的缓冲区提高性能,和字符流缓冲区是相同的。(这个地方的字符缓冲区是8192大小的字符数组不是字节,我们之前缓冲区都是字节

方法名称 说明
public BufferedReader(Reader r) 把基本流变成高级流
public BufferedWriter(Writer r) 把基本流变成高级流

但是字符缓冲流提供了两个方法,我们会经常使用

字符缓冲输入流特有方法 说明
public String readLine() 读取一行数据,如果没有数据可读,会返回null

readLine()方法在读取的时候一次读取一整行,遇到回车换行结束,但是他不会把回车换行读到内存当中

字符缓冲输出流特有方法 说明
public void newLine() 跨平台的换行

缓冲流有几种?

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

缓冲流为什么能提高性能?

  • 字符缓冲流底层会创建大小为8192的字符数组,一个字符在java中占用两个字节,那这样就是一个16K的一个缓冲区
  • 显著提高字节流的读写性能
  • 对于字符流提升不明显,对于服务缓冲流而言关键点是两个特有的方法
2.4.2.1 字符缓冲输入流
//      TODO 创建字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("D:/test.txt"));

//      TODO 读取数据
        String line ;
        while ( (line = br.readLine()) !=null){
            System.out.println(line);
        }
//      TODO 释放资源
        br.close();
2.4.2.2 字符缓冲输出流
//      TODO 创建对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("D:/test.txt",true));

//      TODO 写出数据
        bw.newLine();
        bw.write("你长得很漂亮");
        bw.newLine();  // 跨平台换行
        bw.write("精神小伙!");

//      TODO 关闭流
        bw.flush();
        bw.close();

2.5 转换流

2.5.0 介绍

转换流属于字符流,是字符流与字节流之间的桥梁。

InputStreamReader 读取数据我们需要一个数据源,把数据源中的数据读取到内存当中,当我们创建转换流对象的时候,我们需要创建一个字节输入流,在我们包装之后,字节流就变成字符流了。

​ 此时也具有了字符流的特性: 读取数据不会乱码了、根据字符集一次读取多个字节

OutputStreamWriter 写出数据需要一个目的地,将字符流转换成字节流,与读取数据相反。在我们的目的地当中就是一个又一个的字节

IO + File 详细基础知识

2.5.1 案例 - 利用转换流按照指定字符编码读取

​ 需求1 : 手动创建GBK(ANSI)文件,把文件中的中文读取到内存中,不能出现乱码

​ 需求2: 把一段中文按照GBK的方式写到本地文件

​ 需求3: 将本地文件中的GBK文件,转成UTF-8

2.5.1.1 按照指定编码读取数据

这个方案被淘汰了,了解一下

//      TODO 创建对象并指定字符编码     第二个参数就是指定字符编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:/testANSI.txt"), "GBK");

//      TODO 读取数据  完全可以按照字符流的形式读取
        int ch;
        while( (ch = isr.read()) !=-1){
            System.out.print( (char) ch);
        }
        isr.close();

JDK11后有更好的方案, FileReader的父类是InputStreamReader(转换流),InputStreamReader的父类是Reader。

有了这层关系后新增加了一个构造方法: public FileReader (File file,Charset charset),在这个构造方法里面后调用父类的构造方法创建对象 super(new FileInputStream(file) , charset),其实就是我们上面淘汰代码的写法

IO + File 详细基础知识

      FileReader fr = new FileReader( fileName: "myiollgbkfile.txt",    Charset.forName("GBK"));//2.读取数据
     int ch;
     while ((ch = fr.read()) != -1)(System.out.print((char)ch);
//    3.释放资源
     fr.close();
2.5.1.2 按照指定字符编码写出

这种方式同样是被淘汰了,与 2.5.1.1类似

//      TODO
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/testANSI.txt"),"GBK");
//      TODO 写出数据
        osw.write("八嘎呀路");
//      TODO 释放资源
        osw.close();

新的代码:

      FileWriter fw  = new FileWriter("D:/testANSI.txt",Charset.forName("GBK"));
     
      fw.write("八嘎呀路");
      fw.close();
2.5.1.3 将本地文件中的GBK文件转成UTF-8

JDK 11 之前: 转换流

    InputStreamReader isr = new InputStreamReader(new FileInputStream("D:/testANSI.txt"), "GBK");
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/testANSI.txt"),"UTF-8");  //默认UTF-8,不指定也可以
    
     int b;
     while( (b=isr.read())!=-1){
         osw.write(b);
     }
     osw.close();
     isr.close();
     
       

JDK 11

      FileReader fr = new FileReader( fileName: "myiollgbkfile.txt",    Charset.forName("GBK"));

      FileWriter fw  = new FileWriter("D:/testANSI.txt",Charset.forName("UTF-8")); //不指定也行,默认UTF-8

     int b;
     while( (b=fr.read())!=-1){
         fw.write(b);
     }
     osw.close();
     isr.close();
2.5.1.4 读取文件中的数据,每次读取一整行不能出现乱码

①字节流在读取中文 的时候是会出现乱码的,但是字符流可以

②字节流里面是没有读取一整行的方法的,但是字符缓冲流可以

2.6 序列化流 与 反序列化流

2.6.0 介绍

属于字节流的一种

IO + File 详细基础知识

小细节

​ 使用对象输出流将对象保存到文件时会出现NotSerializableException异常

​ 解决方案: 需要让JavaBean类实现Serializable接口

Serializable接口接口中没有抽象方法,标记型接口。表示此类可以被序列化

序列化流: 也叫做对象操作输出流,可以把java中的对象写到本地文件中

构造方法 说明
public ObjectOutputStream(OutputStream out) 把基本流包装成高级流
成员方法 说明
public final void writeObject(Object obj) 把对象序列化(写出)到文件中

**反序列化流:**对象操作输入流,可以把序列化到本地文件中的对象读取到程序中

构造方法 说明
public ObjectInputStream(InputStream out) 把基本流变成高级流
成员方法 说明
public Object readObject() 把序列化到本地文件中的对象,读取到程序中

使用场景:

​ 游戏存档,将数据存起来,但是用户看不懂无法修改

2.6.1 序列化流

//      TODO 创建对象
        Student student = new Student("张三",23);

//      TODO 创建序列化流对象/对象操作输出
        ObjectOutputStream  oops = new ObjectOutputStream(new FileOutputStream("D:/test.txt"));

//      TODO 写出数据
        oops.writeObject(student);

//      TODO 关闭流
        oops.close();
@Data
public class Student implements Serializable {
    private String name;
    private int age;
    
    public Student(String name, int age) {
       this.name = name;
       this.age = age;
    }
}

2.6.2 反序列化流

//      TODO  创建发序列化流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/test.txt"));

//      TODO 读取数据
        Object o = ois.readObject();

//       打印
        System.out.println(o);

        ois.close();

2.6.3 使用细节

​ 当我们实现了Serializable接口后,会根据我们类中的变量、方法生成一个Long类型的序列号(版本号)

比如我们将代码运行后Student类序列号为1,写入本地文件

此后我们又修改了Student类,然后利用反序列化流读取本地文件就会出错,这是为什么呢?

​ 因为我们反序列读取本地文件的时候序列号为1,但是我们Student类因为修改了文件序列号变成了2,两个版本号不一样,报错。即文件中的版本号与JavaBean中的版本号不匹配。

IO + File 详细基础知识

解决方案:

将版本号固定,并且版本号的名称只能叫“serialVersionUID”

IO + File 详细基础知识

但是手动添加太麻烦,我们可以借助IDEA工具,如下所示。当我们勾选上之后,如果bean实现了序列化接口但是没写序列化号会给我们提示。

IO + File 详细基础知识

某个字段不想序列化到本地文件怎么办?

​ transient: 瞬态关键字

  private  transient  String  address;

总结:

① 使用序列化流将对象写到文件时,需要让JavaBean类实现Serivlizable接口,否则会出现NotSerivlizableException

② 序列化流写到文件中的数据是不能修改的,一旦修改就无法再读回来

③ 序列化对象后,修改了Javabean类,再次反序列化,会不会有问题?

​ 会有问题,会抛出InvalidClassException异常。

​ 解决方案: 给JavaBean类添加serialVersionUID(序列号、版本号)

④ 如果一个对象中的某个成员变量的值不想被序列化,可以使用transient关键字

2.7 打印流

打印流不能读,只能写

PrintStream、PrintWriter两个类

特点

  • 打印流只操作目的地,不操作数据源

  • 特有的写出方法可以实现,数据原样写出

​ 打印“97” , 文件中“97”

​ 打印“true” 文件中“true”

  • 特有的写出方法,可以实现自动刷新,自动换行

​ 打印一次数据 = 写出 + 换行 + 刷新

IO + File 详细基础知识

2.7.1 字节打印流 - PrintStream

构造方法 说明
public PrintStream(OutputStream/File/String) 关联字节输出流/文件/文件路径
public PrintStream(String fileName,Charset charset) 指定字符编码
public PrintStream(OutputStream out , boolean autoFlush) 自动刷新(字节流底层没有缓冲区,开不开一个样)
public PrintStream(OutputStream out , boolean autoFlush ,String encoding) 指定字符编码且自动刷新
成员方法 说明
public void write(int b) 常规方法: 规则和之前相同,将指定字节写出
public void println(Xxx xx) 特有方法: 打印任意数据,自动刷新,自动换行
public void print(Xxx xx) 特有方法: 打印任意数据,不换行
public void printf (String format,Object… args) 特有方法: 带有占位符的打印语句,不换行
//      TODO 打印流
//         第一个参数  关联字节输出流   第二个参数 是否自动刷新   第三个参数 指定编码 或者也能用Charset.forName("UTF-8")
        PrintStream ps =new PrintStream(new FileOutputStream("D:/test.txt"),true,"UTF-8");

//      TODO 写出数据1
        ps.println(97);  // 包括三个功能: 写出+自动刷新+自动换行

        ps.print(true);

        ps.printf("%s 爱上了 %s","阿珍","阿强");

//      TODO 释放资源
        ps.close();

占位符:

占位符 含义
%n 换行
%s 字符串
%c 把字符换成大写
%b 布尔类型
%d 小数的占位符

2.7.2 字符打印流 - PrintWriter

字符打印流底层有缓冲区,想要自动刷新需要开启

构造方法 说明
public PrintWriter(Write/File/String) 关联字节输出流/文件/文件路径
public PrintWriter(String fileName,Charset charset) 指定字符编码
public PrintWriter(Write w,boolean autoFlush) 自动刷新
public PrintWriter(OutputStream out,boolean autoFlush,Charset charset) 指定字符编码且自动刷新
成员方法 说明
public void write(…) 常规方法: 规则和之前相同,将指定字节写出
public void println(Xxx xx) 特有方法: 打印任意数据,自动刷新,自动换行
public void print(Xxx xx) 特有方法: 打印任意数据,不换行
public void printf (String format,Object… args) 特有方法: 带有占位符的打印语句,不换行
        PrintWriter pw = new PrintWriter(new FileWriter("D:/test.txt"),true);

        pw.println("今天我很帅");
        pw.print("您好");
        pw.printf("%s 爱上了 %s","阿珍","阿强");
//      开启自动刷新后,这个地方不刷新也行
//      TODO 释放资源
        pw.close();

2.7.3 输出 - System.out.println

System是final修饰,是最终类,不能有子类

public final class System

out是System的一个静态变量,而且是一个流

public final static PrintStream out = null;

拆分出来是下面这个样子。

​ 获取打印流对象,此打印流在虚拟机启动的时候,由虚拟机创建,默认只想控制台

特殊的打印流,系统中的标准输出流,不能关闭,因为在系统中是唯一的

PrintStream ps = System.out;

ps.println(123); //123

调用打印流中的方法 println,写出数据,自动换行,自动刷新

System.out.println(123);

2.8 解压缩流 与 压缩流

注意!在Java文件中只能识别“zip”结尾的压缩文件

2.8.1 解压缩流

解压本质: 压缩包中的把每一个文件在Java中是一个ZipEntry对象,按照层级拷贝到本地另一个文件夹中

//      解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中
//      TODO 创建一个解压缩流来读取压缩包中的数据
        ZipInputStream zip =new ZipInputStream(new FileInputStream(src));
//      TODO 获取到压缩包里面每一个zipEntry对象
        ZipEntry entry = zip.getNextEntry();
        System.out.println(entry);  //test2/java.txt

        ZipEntry entry2 = zip.getNextEntry();
        System.out.println(entry2);  // test2/test03/

        ZipEntry entry3 = zip.getNextEntry();
        System.out.println(entry3);  //  test2/test03/tttttt.txt

        ZipEntry entry4 = zip.getNextEntry();
        System.out.println(entry4);   // null

//      TODO 经过我们上面尝试,getNextEntry可以获取到压缩包中的文件、文件夹以及子文件中的文件与文件夹

//      但是我们不用上面那个写法,用这个
        ZipEntry zipEntry ;

        while( (zipEntry = zip.getNextEntry()) !=null){
            System.out.println(zipEntry);
        }


        zip.close();

下面可以正式编写代码:

public class ZipStreamDemo2 {
    public static void main(String[] args) throws IOException {
//      TODO 创建一个File表示要解压的压缩包
        File src = new File("E:/test2.zip");

//      TODO 创建一个File表示解压的目的地
        File dest = new File("D:/");

//
        unZip(src, dest);
    }

    /**
     * @param src  要解压的压缩包
     * @param dest 解压的目的地
     */
    public static void unZip(File src, File dest) throws IOException {
//      解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中
//      TODO 创建一个解压缩流来读取压缩包中的数据
        ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
//      TODO 获取到压缩包里面每一个zipEntry对象
//            表示当前在压缩包中获取到的文件或者文件夹
        ZipEntry entry;

        while ((entry = zip.getNextEntry()) != null) {
            System.out.println(entry);

            if (entry.isDirectory()) {
                //文件夹: 需要在目的地dest处创建一个同样的文件夹
                // 第一个参数: 父级路径   第二个参数: 子级路径
                File file = new File(dest,entry.toString()); // 比如 D:/test2/java.txt
                file.mkdirs();
            } else {
                //文件: 读取压缩包中的文件,并且按照层级目录存放到目的地dest文件夹中

                int b; // 一个字节一个字节的读
                FileOutputStream fos = new FileOutputStream( new File(dest,entry.toString()));
                while ( (b= zip.read()) != -1){
                    fos.write(b);
                }
                fos.close();

//              TODO 表示在压缩包中的一个文件处理完毕
                zip.closeEntry();
            }
        }

        zip.close();
    }
}

2.8.2 压缩流

压缩包里面的每一个文件或者文件夹都是ZipExtry对象

**压缩本质:**把每一个(文件/文件夹)看成ZipEntry对象放到压缩包中

2.8.2.1 压缩单个文件
public class ZipStreamDemo3 {
    public static void main(String[] args) throws IOException {
//      TODO 创建File对象表示要压缩的文件
        File src = new File("E:/java.txt");

//      TODO 创建File对象表示压缩包的位置
        File dest = new File("D:/");

//      TODO 调用方法压缩
        toZip(src,dest);
    }

    /**
     * @param src  要压缩的文件
     * @param dest 要压缩的目的地
     */
    public static void toZip(File src,  File dest) throws IOException {
//      TODO 压缩流关联压缩包
//      new File(dest,"a.zip") , 父级路径dest, 子级路径a.zip,相当于在磁盘中创建了一个D:/a.zip 压缩文件
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));

//      TODO 创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
        ZipEntry entry = new ZipEntry("a.txt");

//      TODO 把ZipEntry对象放到压缩包当中
        zos.putNextEntry(entry);

//      TODO 把src文件中的数据写到压缩包当中
        FileInputStream fis = new FileInputStream(src);

        int b;
        while ( (b=fis.read()) !=-1){
            zos.write(b);
        }

//      TODO 关闭
        zos.closeEntry();
        zos.close();
    }
}
2.8.2.2 压缩文件夹

ZipEntry里面的参数表示在压缩文件中的路径

public class ZipStreamDemo4 {
    public static void main(String[] args) throws IOException {
//      TODO 要压缩的文件夹
        File src = new File("E:/test2");

//      TODO 创建File对象表示压缩包的路径(压缩包的父级路径)
        File destParent = src.getParentFile(); // destParent = E:\

//       src.getName() =test2
//      TODO 创建File对象表示压缩包的路径
        File dest = new File(destParent, src.getName() + ".zip"); //dest = E:\test2.zip

//     TODO 创建压缩流关联压缩包
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));

//     TODO 获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
        toZip(src,zos,src.getName() );
//     TODO 释放资源
        zos.close();
    }

    /**
     * 作用:
     * 获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
     *
     * @param src  数据源
     * @param zos  压缩流,已经关联好了压缩文件
     * @param name 在压缩包内部的路径
     */
    public static void toZip(File src, ZipOutputStream zos, String name) throws IOException {
//      TODO 进入src
        File[] listFiles = src.listFiles();

//      TODO 遍历数组
        for (File file : listFiles) {
            if (file.isFile()) {
//             文件,编程ZipEntry对象,放入到压缩包当中
//               这个地方参数不能直接填入file,因为file是一个完整的路径(绝对路径),并不一定压缩包中的路径
                ZipEntry zipEntry = new ZipEntry(name+"/"+file.getName());

                zos.putNextEntry(zipEntry);

//              TODO 读取文件中的数据到压缩包
                FileInputStream fis = new FileInputStream(file);
                int b;
                while ( (b=fis.read()) !=-1){
                    zos.write(b);
                }

                fis.close();
                zos.closeEntry();

            }else {
//             文件夹,递归
                toZip(file,zos,name+"/"+file.getName());
            }
        }
        zos.close();
    }
}

三、 综合练习

字节流拷贝任意类型的文件

字符流: 读取纯文本文件中的数据、往纯文本文件中写出数据

3.1 拷贝文件夹

需要考虑子文件夹

我们现在有两个文件夹test1(里面还存在其他文件夹)、test2,我们需要将test1文件夹中的内容拷贝到test2文件夹之下

public class Test01 {
    public static void main(String[] args) throws IOException {
//      TODO  数据源 test1文件夹
        File src = new File("D:\\test1");
//      TODO 目标文件夹
        File dest = new File("D:/test2");
//      TODO 调用方法开始拷贝
        copyDir(src,dest);
    }

    /**
     * 拷贝文件夹
     * @param src  数据源
     * @param dest  目的地
     */
    private static void copyDir(File src, File dest) throws IOException {
//      文件夹有可能不存在,我们创建出来
        dest.mkdirs();  //如果已经存在那么久创建失败,但是不会报错

//      TODO 进入数据源
        File[] files = src.listFiles(); // 文件夹及文件以数组的方式返回

//      TODO 遍历数组(数组中文件夹及文件以数组的方式返回)
        for(File file: files){
            if(file.isFile()){
//              TODO 判断文件 - 拷贝
                FileInputStream fis = new FileInputStream(file);
//              TODO  文件开始,文件结束  new File(dest,file.getName()) 表示父级名用dest,文件名用file.getName()
                FileOutputStream fos = new FileOutputStream(new File(dest,file.getName()));

                byte[] bytes = new byte[1024];

                int len;
                while ( (len = fis.read(bytes)) !=-1){
                    fos.write(bytes,0,len);
                }

                fos.close();
                fis.close();

            }else {
//                TODO 判断文件夹 - 递归
                copyDir(file,new File(dest,file.getName()));
            }
        }
    }
}

3.2 文件加密/解密

为了保证文件安全性,需要对原始文件进行加密存储,再使用的时候再对其进行解密处理

加密原理: 对原始文件中的每一个字节数据进行修改,然后将改正以后的数据存储到新的文件中

**解密原理:**读取加密文件之后,按照加密的规则反向操作,变成原始文件。

^: 异或

​ 两边相同: false

​ 两边不同: true

System.out.println(true ^ true);   // false
System.out.println(true ^ false);  // true
System.out.println(100 ^ 10 );     // 110

为什么 “100 ^ 10” 结果是 “110”?

“100”二进制 “1100100”, “10” 二进制 “1010”

1100100 ^ 1010 将两串数字右边对齐(没有数字的地方用0补齐)。0代表false,1代表true

​ 1 1 0 0 1 0 0

​ 1 0 1 0

————————

​ 1 1 0 1 1 1 0 --> 十进制就是110

**那“ 110 ^ 10” 的结果是多少? **

​ 答案是 “100” ,将结果又还原回来了

我们就可以利用这个特性进行加密和解密

3.2.1 加密

//      TODO 创建对象关联原始文件
        FileInputStream fis = new FileInputStream("D:/杂/hello.jpg");
//      TODO 创建对象关联加密文件
        FileOutputStream fos = new FileOutputStream("D:/杂/helloTest.jpg");

//      TODO 加密处理
        int b ;
        while ((b = fis.read()) !=-1){
            fos.write(b^2);
        }

        fos.close();
        fis.close();

3.2.2 解密

//      TODO 创建对象关联原始文件(加密之后的文件)
        FileInputStream fis = new FileInputStream("D:/杂/helloTest.jpg");
//      TODO 创建对象关联解密文件
        FileOutputStream fos = new FileOutputStream("D:/杂/helloTestJIeMi.jpg");

//      TODO 加密处理
        int b ;
        while ((b = fis.read()) !=-1){
            fos.write(b^2);
        }

        fos.close();
        fis.close();
    }

3.3 修改文件中数据

文本文件中有以下数据: 2-1-9-4-7-8

将文件中的数据进行排序,变成以下的数据: 1-2-4-7-8-9

如果文件数据有换行后就不能下面这样方式,因为数据后面会有"/r/n"

public class Test03 {
    public static void main(String[] args) throws IOException {
//      TODO 读取数据
        FileReader fr = new FileReader("D:/杂/test/test.txt");
        StringBuilder stringBuilder = new StringBuilder();

        int ch;
        while ((ch = fr.read()) != -1) {
            stringBuilder.append((char) ch);
        }
        fr.close();
        System.out.println(stringBuilder); //2-1-9-4-7-8

//      TODO 排序
        String str = stringBuilder.toString();
        String[] split = str.split("-");

        ArrayList<Integer> list = new ArrayList<>();

        for (String s : split){
            int i = Integer.parseInt(s);
            list.add(i);
        }
        System.out.println(list);  //[2, 1, 9, 4, 7, 8]

        Collections.sort(list);

//      TODO 写出
        FileWriter fw = new FileWriter("D:/杂/test/test.txt");
        for(int i=0 ; i<list.size() ; i++){
            if( i == list.size() -1){
                fw.write(list.get(i).toString());  //一定要toString , 如果不写String类型,会写出整数型数字对应的字符
            }else {
//              不是最后一个,需要补充“-”
                fw.write(list.get(i).toString()+"-");
            }
        }
        fw.flush();
        fw.close();
    }
}

3.4 读写多个对象

​ 将多个自定义对象序列化到文件中,但是由于对象个数不确定,反序列化流如何读取?

3.4.1 序列化多个对象

Student s1 = new Student("zhangsan",23);
Student s2 = new Student("lisi",23);
Student s3 = new Student("wangwu",23);
Student s4 = new Student("zhaoliu",23);

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/test.txt"));
oos.writeObject(s1);
oos.writeObject(s2);
oos.writeObject(s3);
oos.writeObject(s4);
oos.close();

但是我们一般不这样写,因为我们在读取的时候会很麻烦。

如果我们读到文件的末尾了,会返回一个异常并不是-1, 异常:EOFException,表示读到文件末尾,但是我们不能在出现异常的时候停止,所以要修改一下代码。

ArrayList类本身实现了序列化接口,所以可以这样做

Student s1 = new Student("zhangsan",23);
Student s2 = new Student("lisi",23);
Student s3 = new Student("wangwu",23);
Student s4 = new Student("zhaoliu",23);

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/test.txt"));

ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);

oos.writeObject(list);

oos.close();

3.4.2 反序列化多个对象

//      TODO 创建反序列化流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/test.txt"));
//      TODO 读取数据
        ArrayList<Student> list =(ArrayList<Student>) ois.readObject();
        System.out.println(list); //[Student{name='zhangsan', age=23}, Student{name='lisi', age=23}, Student{name='wangwu', age=23}, Student{name='zhaoliu', age=23}]

        ois.close();

四、 字符集详解

4.1 计算机的存储规则

  • ASCII 字符集

在计算机中,任意数据都是以二进制的形式存储的

8bit -> 如 0 0 1 1 1 0 0 0 -> 1K , 即可以存储2^8,256个数据。

1K,也就是一个字节。字节是计算机最小的存储单元

存储英文,一个字节就可以,这是为什么呢? 这就和字符集相关了

可以阅读一下下面的文章

计算机基础——二进制、八进制、十六进制以及相互转换_我爱布朗熊的博客-CSDN博客

  • GBK字符集

​ 这三个字符意思是"国标扩展"。

​ 收录21003个汉字包含国家标准GB13000-1中的全部中日韩汉字,和BIG5编码中的所有汉字。

​ windows系统默认使用的就是GBK。系统显示 ANSI。

  • Unicode字符集

​ Unicode字符集:国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换。

4.2 ASCII 字符集

也叫做编码表,一共有128个数据(字符),对应[0-127]。

1个字节最多能表示256个数据,那这就能得出一个结论,存储英文,一个字节即可。

比如我们要存储英文字母"a",查询ASCII,对应97(110 0001),我们不能存储这个二进制数字,因为计算机最小的存储单位是字节,“110 0001”不足一个字节,所以我们要补充为"0110 0001",即补齐8位。

解码就是将上面的顺序反过来,“0110 0001”解码为97,然后查询ASCII表为"a",进而读取到

IO + File 详细基础知识

4.3 GBK 字符集

4.3.1 英文字母存储

和ASCII没有什么区别

其中:英文用一个字节存储,完全兼容ASCII

依然是 “a”字符,查询GBK,获取对应的数据"97",转成二进制"110 0001",补充为一个字节"0110 0001"(不足8位,前面补零)

4.3.2 中文汉字存储

比如"汉",查询GBK为”47802“,转换成二进制数字为"10111010 10111010",发现为两个字节,此时二进制数据不需要任何的改动,直接存储到硬盘当中就可以了。

因为一个字节只能记录256个数据,这几个数据对中文来说实在太少了,所以采用两个字节来记录汉字,完全够用。

IO + File 详细基础知识

对于两个字节,前面的一个字节是高位字节,后面的字节叫做低位字节。

对于高位字节二进制一定是以1开头,转成十进制之后是一个负数。

为什么要是一个负数呢?

​ 因为我们要和英文区分开,当我们存储英文的时候,位数不够前面是补0

IO + File 详细基础知识

4.4 Unicode 字符集 - 万国码

这个"万国码"是一个虚词

在UTF-8字符编码下,英文占1个字符,中文占三个字符

UTF-8不是字符集,他是Unicode的一种编码方式

IO + File 详细基础知识

IO + File 详细基础知识

IO + File 详细基础知识

IO + File 详细基础知识

4.5 乱码

4.5.1 乱码产生原因

  • 读取数据时未读完整个汉字

比如字节流,一次只能读取一个字节,读取英文的时候是没什么问题的。

但是当读取utf-8形式文件的时候,中文占三个字节,那我们用字节流读取文件很显然后产生乱码,因为没有读取完整个汉字

  • 编码和解码时的方式不同意统一

    如下所示,编码和解码方式是统一的,所以能正常展示,如果换成GBK或者其他方式解码,就会带来错误。

IO + File 详细基础知识

4.5.2 如何不产生乱码?

不要用字节流读取文本文件,使用字符流

编码和解码使用同一个码表,我们现在一般采用UTF-8

4.5.3 扩展

字节流读取中文会乱码,但是为什么拷贝不会乱码呢?

因为拷贝的时候,字节码该怎么排序就怎么排序,还是正常的。但是我们读取的时候却是按照某个定长读取,这个定长可能正好在某个中文的三个字节中的某一个字节位置,从而导致乱码。

IO + File 详细基础知识

4.6 Java中编码

String类方法 说明
public byte[] getBytes() 使用默认方式进行编码
public byte[] getBytes(String charsetName) 会用指定当时进行编码
//      TODO 编码1  使用默认编码
        String str = "ai你呦";  // 采用默认编码方式,即右下角显示的“UTF-8”,一个中文三个字节,一个英文一个字节
        byte[] bytes1 = str.getBytes();
        System.out.println(Arrays.toString(bytes1));//[97, 105, -28, -67, -96, -27, -111, -90]  8个字节

//      TODO 编码2  指定编码
        byte[] bytes2 = str.getBytes("GBK");//大写小写都可以
        System.out.println(Arrays.toString(bytes2));//[97, 105, -60, -29, -33, -49]

4.7 Java中解码

String类方法 说明
String(byte[] bytes) 使用默认方式进行解码
String(byte[] bytes,String charsetName) 使用指定方式进行解码
//     TODO 解码1  默认解码
        String str2 = new String(bytes1);
        System.out.println(str2);  //ai你呦

//     TODO 解码2  指定解码
        String str3 = new String(bytes2,"GBK");
        System.out.println(str3);  //ai你呦

五、Commons-io 工具包

Commons-io是apache开源基金组织提供的一组有关IO操作的开源工具包

作用: 提高IO流的开发效率

IO + File 详细基础知识

5.2 Maven坐标

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

5.3 Commons-io 常见方法

5.3.1 与文件夹/文件相关的方法

IO + File 详细基础知识

拷贝文件

File src = new File("E:/java.txt");
File dest = new File("D:/java.txt");
FileUtils.copyFile(src,dest);

拷贝目录

直接拷贝,就是我们理解的拷贝

File src = new File("E:/test2");
File dest = new File("D:/test2");

FileUtils.copyDirectory(src,dest);

这个与上面拷贝文件夹的不同时,现在D:/test2的文件夹中创建一一个test2目录,然后在这个test2目录中添加文件

File src = new File("E:/test2");
File dest = new File("D:/test2");

FileUtils.copyDirectoryToDirectory(src,dest);

5.3.2 与IO流相关

IO + File 详细基础知识

六、 hutool

http://hutool.cn/docs/#/ 官方网站

https://apidoc.gitee.com/dromara/hutool/ 帮助文档

IO + File 详细基础知识

相关类 说明
IoUtil 流操作工具类
FileUtil 文件读写和操作的工具类
FileTypeUtil 文件类型判断工具类
WatchMonitor 目录、文件监听
ClassPathResource 针对ClassPath中资源的访问封装
FileReader 封装文件读取
FileWriter 封装文件写入

6.1 Maven 坐标

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.12</version>
</dependency>

6.2 FileUtil 类常用静态方法

  • file : 根据参数创建一个file对象
//      file() 根据参数创建一个file对象,和我们之前说的File对象一模一样,而且多了几个构造方法
//      下面这个构造方式是之前没有的
        File file = FileUtil.file("D:/", "aaa", "bb", "test.txt");//D:/aaa/bb/test.txt 文件
        System.out.println(file); //D:\aaa\bb\test.txt

IO + File 详细基础知识

  • touch: 根据参数创建文件,如果父级路径不存在会一块创建

    FileUtil.touch 语句运行完成之后文件直接创建文章来源地址https://www.toymoban.com/news/detail-443760.html

File touch = FileUtil.touch("D:/aaa/bb/test.txt");
System.out.println(touch);  //D:\aaa\bb\test.txt
  • writeLines: 把集合中的数据写出到文件中,覆盖模式
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("aaa");
        list.add("aaa");
        FileUtil.writeLines(list,"E:/java.txt","UTF-8",true);
//写入文件的内容
//aaa
//aaa
//aaa
  • addpendLines: 把集合中的数据写出到文件中,续写模式
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa");
list.add("aaa");
File file = FileUtil.appendLines(list, "E:/java.txt", "UTF-8");
System.out.println(file); //E:\java.txt
  • readLines: 指定字符编码,把文件中的数据读到集合中
        ArrayList<String> strings = FileUtil.readLines("E:/java.txt", "UTF-8", new ArrayList<String>());

//      这个方法的底层会帮我们创建
        List<String> stringList = FileUtil.readLines("E:/java.txt", "UTF-8");
//      一行数据,就是集合中的一条元素 
        System.out.println(stringList);  //[张靖奇你长得很帅, aaa, aaa, aaa, aaa, aaa, aaa]
  • readUtf8Lines: 按照UTF-8的形式,把文件中的数据,读到集合中
  • copy: 拷贝文件或者文件夹

ol.cn/docs/#/ 官方网站

https://apidoc.gitee.com/dromara/hutool/ 帮助文档

[外链图片转存中…(img-xZGw2eCE-1683983268483)]

相关类 说明
IoUtil 流操作工具类
FileUtil 文件读写和操作的工具类
FileTypeUtil 文件类型判断工具类
WatchMonitor 目录、文件监听
ClassPathResource 针对ClassPath中资源的访问封装
FileReader 封装文件读取
FileWriter 封装文件写入

6.1 Maven 坐标

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.12</version>
</dependency>

6.2 FileUtil 类常用静态方法

  • file : 根据参数创建一个file对象
//      file() 根据参数创建一个file对象,和我们之前说的File对象一模一样,而且多了几个构造方法
//      下面这个构造方式是之前没有的
        File file = FileUtil.file("D:/", "aaa", "bb", "test.txt");//D:/aaa/bb/test.txt 文件
        System.out.println(file); //D:\aaa\bb\test.txt

[外链图片转存中…(img-EGRp3z38-1683983268483)]

  • touch: 根据参数创建文件,如果父级路径不存在会一块创建

    FileUtil.touch 语句运行完成之后文件直接创建

File touch = FileUtil.touch("D:/aaa/bb/test.txt");
System.out.println(touch);  //D:\aaa\bb\test.txt
  • writeLines: 把集合中的数据写出到文件中,覆盖模式
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("aaa");
        list.add("aaa");
        FileUtil.writeLines(list,"E:/java.txt","UTF-8",true);
//写入文件的内容
//aaa
//aaa
//aaa
  • addpendLines: 把集合中的数据写出到文件中,续写模式
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa");
list.add("aaa");
File file = FileUtil.appendLines(list, "E:/java.txt", "UTF-8");
System.out.println(file); //E:\java.txt
  • readLines: 指定字符编码,把文件中的数据读到集合中
        ArrayList<String> strings = FileUtil.readLines("E:/java.txt", "UTF-8", new ArrayList<String>());

//      这个方法的底层会帮我们创建
        List<String> stringList = FileUtil.readLines("E:/java.txt", "UTF-8");
//      一行数据,就是集合中的一条元素 
        System.out.println(stringList);  //[张靖奇你长得很帅, aaa, aaa, aaa, aaa, aaa, aaa]
  • readUtf8Lines: 按照UTF-8的形式,把文件中的数据,读到集合中
  • copy: 拷贝文件或者文件夹

到了这里,关于IO + File 详细基础知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux知识点 -- 基础IO(二)

    在上面的代码中,fprintf本来是向stdout中打印的,但是stdout关闭了,实际上fprintf事项fd是1的文件中打印,这里log.txt的fd就是1; 运行结果为: 这就叫做 输出重定向 ; 上面的代码将stdout关闭了,并打开log.txt文件,则log.txt文件的fd就是1; 在系统中,stdout就代表着fd为1,所以默

    2024年02月15日
    浏览(25)
  • 全面了解Java连接MySQL的基础知识,快速实现数据交互

    当今互联网时代,大量的应用程序都需要使用MySQL数据库来存储和处理数据。Java作为一种广泛使用的编程语言之一,在开发Web应用程序时经常需要连接MySQL数据库进行数据操作。 因此,了解如何使用Java连接MySQL数据库是非常重要的。在本文中,我们将介绍Java JDBC API以及如何使

    2024年02月06日
    浏览(31)
  • Rust 全面指南:从基础到高级,一网打尽 Rust 的编程知识

    因为在学习Rust过程中,因为代码量不是太多,所以有一些学完就忘了,特此记录一些Rust知识点 Rust是什么? Rust是一种现代的、强类型的、系统级编程语言。它被设计用于编写高性能、并发、安全的系统,并且可以避免常见的内存安全问题,如空指针和数据竞争。Rust的特点包

    2024年02月08日
    浏览(39)
  • 服务器硬件基础知识解析

    导言 在当今信息化时代,服务器扮演着至关重要的角色,它们是存储、处理和传输数据的关键设备。本文将介绍服务器硬件的基础知识,包括服务器的组成部分、硬件选型和性能评估等内容,旨在帮助读者更好地理解和应用服务器技术。 服务器硬件组成 1. 中央处理器(CPU)

    2024年04月09日
    浏览(46)
  • 快速指南:原型图的基础知识解析

    一般来说,原型图是指用于呈现软件产品功能界面、交互设计和逻辑过程的设计项目。您还可以将原型图理解为软件的草图,可以通过原型图清楚地说明软件的功能、几个界面、每个功能的功能以及每个界面的流通关系。 原型图中的组成内容不是固定的,它可以相当完美和复

    2024年02月03日
    浏览(31)
  • ECharts基础知识详细介绍

    ECharts 实例 series 与 dataset ECharts 基础配置 用 option 描述图表 坐标系 一个网页中可以创建多个 ECharts 实例。每个 ECharts 实例中可以创建多个图表和坐标系等等(用 option 来描述)。准备一个 DOM 节点(作为 ECharts 的渲染容器),就可以在上面创建一个 ECharts 实例。每个 ECharts 实

    2024年02月03日
    浏览(35)
  • MySQL数据库基础知识,基础操作详细整理

    引入: 淘宝网,京东、微信,抖音等都有各自的功能,那么当我们退出系统的时候,下次再访问时,为什么信息还存在? 数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。 每个数据库都有一个或多个不同的 API 用于创建,访问,管理,搜索和复制所保存的数

    2024年04月17日
    浏览(42)
  • Stable Diffusion之核心基础知识和网络结构解析

    1. 文生图(txt2img) 文生图任务是指将一段文本输入到SD模型中,经过一定的迭代次数,SD模型输出一张符合输入文本描述的图片。 步骤一: 使用 CLIP Text Encode 模型将输入的人类文本信息进行编码,生成与文本信息对应的Text Embeddings特征矩阵; 步骤二: 输入文本信息,再用ran

    2024年04月15日
    浏览(33)
  • 深入浅出解析LoRA完整核心基础知识 | 【算法兵器谱】

    Rocky Ding 公众号:WeThinkIn 【算法兵器谱】栏目专注分享AI行业中的前沿/经典/必备的模型论文,并对具备划时代意义的模型论文进行全方位系统的解析,比如Rocky之前出品的爆款文章Make YOLO Great Again系列。也欢迎大家提出宝贵的优化建议,一起交流学习💪 大家好,我是Rocky。

    2024年02月11日
    浏览(32)
  • 计算机网络基础知识(非常详细)

    文末有惊喜哦 👇👇👇 七层模型,亦称 OSI(Open System Interconnection)参考模型,即开放式系统互联,是网络通信的 标准模型 。一般称为 OSI 参考模型或七层模型。 它是一个七层的、抽象的模型体,不仅包括一系列抽象的术语或概念,也包括具体的协议。 物理层:负责传输原

    2024年02月09日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包