1、Java IO

1、File

File 类:定位文件,获取文件本身的信息、删除文件、创建文件(文件夹)等功能

1.1、创建 File 对象

File file = new File("文件 / 文件夹 / 绝对路径 / 相对路径");

File file = new File("D:\\itheima\\a.txt"); // 绝对路径
File file = new File("a.txt");              // 相对路径

File 对象可以定位文件和文件夹,File 封装的对象仅仅是一个路径名,这个路径可以是存在的,也可以是不存在的

  • 绝对路径:从盘符开始
  • 相对路径:不带盘符,默认直接到当前工程下的目录寻找文件
分隔符: \\, /, File.separator
方法名 说明
public File(String pathname) 根据文件路径创建文件对象
public File(String parent, String child) 从父路径名字符串和子路径名字符串创建文件对象
public File(File parent, String child) 根据父路径对应文件对象和子路径名字符串创建文件对象

1.2、常用 API

1.2.1、判断文件类型、获取文件信息

方法名 说明
public boolean isDirectory() 判断 File 是否为文件夹
public boolean isFile() 判断 File 是否为文件
public boolean exists() 判断 File 是否存在
public String getAbsolutePath() 获取绝对路径
public String getPath() 获取 File 定义时使用的路径
public String getName() 获取文件或文件夹的名称
public String getParent() 获取文件或文件夹的父绝对名称
public long lastModified() 获取文件最后修改的时间毫秒值
public long length() 获取文件的大小,不能获取目录的大小,单位:B
boolean renameTo(File dest) 对文件重命名(不同路径会剪切)

1.2.2、创建文件、删除文件

返回创建 / 删除文件是否成功
delete() :即使文件被占用,也会删除,不走回收站,方法默认只能删除文件和空文件夹

方法名 说明
public boolean createNewFile() 创建一个新的空的文件
public boolean mkdir() 只能创建一级文件夹
public boolean mkdirs() 可以创建多级文件夹
public boolean delete() 删除由此 File 所表示的文件或空文件夹,不走 windows 回收站

1.2.3、遍历文件夹

方法名 说明
public String[] list() 获取当前目录下所有的 "一级文件名称"
public File[] listFiles() 获取当前目录下所有的 "一级文件对象"(重点)

listFiles() 注意事项
调用者需要:判断数组是否为空、判断数组长度是否为 0、判断数组元素是否为文件夹

  • 当调用者是一个文件时,返回 null
  • 当调用者不存在时(目录不存在),返回 null
  • 当调用者是一个需要权限才能进入的文件夹时,返回 null
  • 当调用者是一个空文件夹时,返回一个长度为 0 的数组

正常情况

  • 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在 File 数组中返回
  • 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在 File 数组中返回,包含隐藏内容

1.3、文件搜索

public static void searchFile(File dir, String filename) {
    if (dir.isDirectory()) {
        File[] files = dir.listFiles();
        if (files != null && files.length != 0) {
            for (File file : files) {
                if (file.isFile()) {
                    if (file.getName().equals(filename)) {
                        System.out.println(file.getAbsoluteFile());
                        // 启动软件(.exe)
                        // Runtime r = Runtime.getRuntime();
                        // r.exec(file.getAbsolutePath());
                    }
                } else {
                    searchFile(file, filename);
                }
            }
        }
    } else {
        System.out.println("参数不是文件夹");
    }
}

public static void main(String[] args) {
    File file = new File("D:\\BaiduNetdiskDownload");
    searchFile(file, "day24、XML、解析、设计模式等.rar");
}

2、字符集

2.1、常见字符集介绍

计算机底层可以表示十进制编号,计算机可以给人类字符进行编号存储,这套编号规则就是字符集

  • ASCII 使用 1 个字节存储一个字符,一个字节是 8 位,总共可以表示 128 个字符信息,对于英文,数字来说是够用的
  • GBK 是 windows 系统默认的码表,是中国的码表,一个中文以 2 个字节的形式存储,包含了几万个汉字,兼容 ASCII 码表
  • Unicode 是万国码,以 UTF-8 编码后一个中文一般以 3 个字节的形式存储,UTF-8 也要兼容 ASCII 编码表
  • 技术人员都应该使用 UTF-8 的字符集编码,编码前和编码后的字符集需要一致,否则会出现中文乱码

字符串常见的字符底层组成是什么样的?

  • 英文和数字等在任何国家的字符集中都占 1 个字节
  • GBK 字符中一个中文字符占 2 个字节
  • UTF-8 编码中一个中文一般占 3 个字节

编码前的字符集和编码好的字符集有什么要求?

  • 必须一致,否则会出现中文字符乱码
  • 英文和数字在任何国家的编码中都不会乱码

image

2.2、字符集的编码、解码操作

String 编码

方法名 说明
byte[] getBytes() 使用平台的默认字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charsetName) 使用指定的字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中
public char[] toCharArray() 将当前字符串转换成字符数组返回

String 解码

构造器 说明
String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数组来构造新的 String
String(byte[] bytes, String charsetName) 通过指定的字符集解码指定的字节数组来构造新的 String
String(byte[] bytes, int offset, int length) 读多少数据,倒多少数据
String(byte[] bytes, int offset, int length, String charsetName) 读多少数据,倒多少数据,指定编码

2.3、字符集的代码表示

Charset.forName("GBK")
StandardCharsets.UTF_8

3、IO 体系

IO 流也称为输入、输出流,就是用来读写数据的,IO 默认不可以拷贝文件夹

  • 字节流适合做一切文件数据的拷贝(音视频,文本)
  • 字节流不适合读取中文内容输出
  • 字符流适合做文本文件的操作(读,写)

关于乱码

  • 字节流读取后,byte[] 转 string 的时候可以指定编码
  • 字符流读取的时候,就需要指定编码,也就是在构造器部分就需要指定编码,char[] 转 string 不能指定编码
  • 缓冲流是对子节流和字符流的进一步封装,不能指定编码
  • 转换流可以指定编码

image
image

4、字节流

不能指定编码

  • FileInputStream
    • read()
    • read(byte[] buffer)
    • readAllBytes()
  • FileOutputStream
    • write(int a)
    • write(byte[] buffer)
    • write(byte[] buffer, int pos, int len)

4.1、FileInputStream

文件字节输入流:FileInputStream,读取中文字符无法避免乱码问题

方法名 说明
public FileInputStream(File file) 创建字节输入流管道与源文件对象接通
public FileInputStream(String pathname) 创建字节输入流管道与源文件路径接通
public int read() 每次读取一个字节返回,如果字节已经没有可读的返回 -1
public int read(byte[] buffer) 每次读取一个字节数组返回,如果字节已经没有可读的返回 -1(返回读取字节数)
public byte[] readAllBytes() throws IOException 直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回
InputStream is = new FileInputStream("src/ab.txt");

int len;
byte[] buffer = new byte[3];

while ((len = is.read(buffer)) != -1) {
    System.out.println(new String(buffer, 0, len)); // 读多少数据, 倒多少数据
}

byte[] bytes = is.readAllBytes(); // 一次性读取所有的数据

4.2、FileOutputStream

文件字节输出流:FileOutputStream,文件可以不存在,会自动创建文件
换行:"\r\n".getBytes()
会出错:os.write('你')

方法名 说明
public FileOutputStream(File file) 创建字节输出流管道与源文件对象接通(自动清空原有数据)
public FileOutputStream(File file,boolean append) 创建字节输出流管道与源文件对象接通,可追加数据
public FileOutputStream(String filepath) 创建字节输出流管道与源文件路径接通(自动清空原有数据)
public FileOutputStream(String filepath,boolean append) 创建字节输出流管道与源文件路径接通,可追加数据
public void write(int a) 写一个字节出去
public void write(byte[] buffer) 写一个字节数组出去
public void write(byte[] buffer, int pos, int len) 写一个字节数组的一部分出去
InputStream is  = new FileInputStream("file-io-app/src/out04.txt");
OutputStream os = new FileOutputStream("file-io-app/src/out05.txt");

int len;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
    os.write(buffer, 0, len);
}
System.out.println("复制完成了!");

os.close();
is.close();

5、释放资源

方法名 说明
flush() 刷新流,还可以继续写数据
close() 关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据

try - catch - finally
try - with - resource
JDK 7 改进方案

try(定义流对象) {
    // 可能出现异常的代码;
} catch(异常类名 变量名) {
    // 异常的处理代码;
}

JDK 9 改进方案

// 定义输入流对象;
// 定义输出流对象;
try(输入流对象; 输出流对象) {
    // 可能出现异常的代码;
} catch(异常类名 变量名) {
    // 异常的处理代码;
}

注意
JDK 7 以及 JDK 9 的 () 中只能放置资源对象,否则报错,那么什么是资源呢?
资源都是实现了 Closeable / AutoCloseable 接口的类对象

public abstract class InputStream implements Closeable {}
public abstract class OutputStream implements Closeable, Flushable{}

6、字符流

JDK 8 不可以指定编码(JDK 16 可以)

  • FileReader
    • read()
    • read(char[] buffer)
  • FileWriter
    • write(int c)
    • write(char[] cbuf)
    • write(char[] cbuf, int off, int len)
    • write(String str)
    • write(String str, int off, int len)

6.1、FileReader

方法名 说明
public FileReader(File file) 创建字符输入流管道与源文件对象接通
public FileReader(String pathname) 创建字符输入流管道与源文件路径接通
FileReader(File file, Charset charset) FileReader(String fileName, Charset charset)
public int read() 每次读取一个字符返回,如果字符已经没有可读的返回 -1
public int read(char[] buffer) 每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回 -1
Reader fr = new FileReader("src\\ab.txt");

int len;
char[] buffer = new char[10];

while ((len = fr.read(buffer)) != -1) {
    System.out.print(new String(buffer, 0, len));
}

6.2、FileWriter

换行:"\r\n"
不会出错:fw.write('你')

方法名 说明
public FileWriter(File file) 创建字符输出流管道与源文件对象接通(自动清空原有数据)
public FileWriter(File file,boolean append) 创建字符输出流管道与源文件对象接通,可追加数据
public FileWriter(String filepath) 创建字符输出流管道与源文件路径接通(自动清空原有数据)
public FileWriter(String filepath,boolean append) 创建字符输出流管道与源文件路径接通,可追加数据
FileWriter(File file, Charset charset, boolean append) FileWriter(String fileName, Charset charset, boolean append)
void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组
void write(char[] cbuf, int off, int len) 写入字符数组的一部分
void write(String str) 写一个字符串
void write(String str, int off, int len) 写一个字符串的一部分
Reader fr = new FileReader("src\\ab.txt");
Writer fw = new FileWriter("src\\bc.txt", true);

int len;
char[] chars = new char[10];
while ((len = fr.read(chars)) != -1) {
    fw.write(chars, 0, len);
}
System.out.println("复制完成了!");

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

7、缓冲流

BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter
缓冲流也称为高效流、或者高级流,之前学习的字节流可以称为原始流
作用:缓冲流自带缓冲区、可以提高原始字节流、字符流读写数据的性能

  • 缓冲输入流自带了 8 KB 缓冲池,以后我们直接从缓冲池读取数据,所以性能较好
  • 缓冲输出流自带了 8 KB 缓冲池,数据就直接写入到缓冲池中去,写数据性能极高了
  • 桶用 1 kb 就行了
构造器 说明
public BufferedInputStream(InputStream is) 可以把低级的字节输入流包装成一个高级的缓冲字节输入流,从而提高读数据的性能
public BufferedOutputStream(OutputStream os) 可以把低级的字节输出流包装成一个高级的缓冲字节输出流,从而提高写数据的性能

方法名 说明
public BufferedReader(Reader r) 可以把低级的字符输入流包装成一个高级的缓冲字符输入流管道,从而提高字符输入流读数据的性能
public String readLine() 读取一行数据返回,如果读取没有完毕,无行可读返回 null

方法名 说明
public BufferedWriter(Writer w) 可以把低级的字符输出流包装成一个高级的缓冲字符输出流管道,从而提高字符输出流写数据的性能
public void newLine() 换行操作

8、转换流

将字节流转换为字符流:InputStreamReader、OutputStreamWriter

  • 可以提取文件(GBK)的原始字节流,原始字节不会存在问题
  • 然后把字节流以指定编码转换成字符输入流,这样字符输入流中的字符就不乱码了
构造器 说明
public InputStreamReader(InputStream is) 把原始的字节流按照代码默认编码转换成字符输入流,几乎不用
public InputStreamReader(InputStream is,String charset) 把原始的字节流按照指定编码转换成字符输入流(重点)

构造器 说明
public OutputStreamWriter(OutputStream os) 把原始的字节输出流按照代码默认编码转换成字符输出流,几乎不用
public OutputStreamWriter(OutputStream os,String charset) 把原始的字节输出流按照指定编码转换成字符输出流(重点)
public static void main(String[] args) throws Exception {
    // 代码 UTF-8   文件 GBK "D:\\resources\\data.txt"
    InputStream in = new FileInputStream("D:\\resources\\data.txt"); // 提取 GBK 文件的原始字节流
    Reader r = new InputStreamReader(in, "GBK");                     // 把原始字节流转换成字符输入流

    BufferedReader br = new BufferedReader(r);

    String line;
    while ((line = br.readLine()) != null){
        System.out.println(line);
    }
}
public static void main(String[] args) throws Exception {
    OutputStream out = new FileOutputStream("io-app2/src/out03.txt"); // 定义一个字节输出流
    Writer w = new OutputStreamWriter(out, "GBK");                    // 把原始的字节输出流转换成字符输出流

    BufferedWriter bw = new BufferedWriter(w);

    bw.write("我爱中国1~~");
    bw.newLine();
    bw.write("我爱中国2~~");
    bw.newLine();
    bw.write("我爱中国3~~");
    bw.newLine();

    bw.close();
}

9、序列化和反序列化

需要实现序列化接口:implements Serializable
序列化版本号:private static final long serialVersionUID = 1L;
不想被序列化的信息:transient,转瞬即逝的,而且静态属性不会被序列化

9.1、序列化

以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化,对象字节输出流:ObjectOutputStream

  • 不建议在一个文件中序列化多个对象,可以将这些对象存储到一个 "集合" 中,然后将集合对象序列化到一个文件中
  • 注意:要求被序列化的集合对象、和元素都要实现 Serializable 接口
  • 不加泛型 obj instanceof ArrayList
方法名 说明
public ObjectOutputStream(OutputStream out) 把低级字节输出流包装成高级的对象字节输出流
public final void writeObject(Object obj) 把对象写出去到对象序列化流的文件中去

9.2、反序列化

以内存为基准,把存储到磁盘文件中去的对象数据恢复成内存中的对象,称为对象反序列化,对象字节输入流:ObjectInputStream

  • 反序列化时,项目中必须要有 "被序列化" 的 "包 + 类"
  • 反序列化时,类中的结构可以和文件中之前序列化的结构不同
方法名 说明
public ObjectInputStream(InputStream in) 把低级字节输如流包装成高级的对象字节输入流
public Object readObject() 把存储到磁盘文件中去的对象数据恢复成内存中的对象返回
readObject 的工作流程
1、读取文件                 object.txt
2、获取文件中的全类名        "com.zzw.student"
3、到当前项目中, "全类名" 所标识的 "包" 下去找相应的类
4、加载这个类
5、将本地 "类中的序列号" 和 "文件中的序列号" 做一次匹配
	     如果匹配成功                                          继续
	     如果匹配失败且没有显式的声明 serialVersionUID           抛出异常
6、创建对象(不调用任何构造方法)
7、将 "堆中属性名" 和 "文件中的属性名" 进行匹配
	     如果匹配上, 就将文件中的值赋给堆中属性的值

10、打印流

作用:打印流可以实现方便、高效的打印数据到文件中去,打印流一般是指:PrintStream、PrintWriter 两个类
PrintStream 和 PrintWriter 的区别

  • 打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)
  • 两者都不能追加(append),需要通过低级流来实现追加
  • PrintStream 继承自字节输出流 OutputStream,支持写字节数据的方法(write)
  • PrintWriter 继承自字符输出流 Writer,支持写字符数据出去(write)

PrintStream

构造器 说明
public PrintStream(OutputStream os) 打印流直接通向字节输出流管道
public PrintStream(File f) 打印流直接通向文件对象
public PrintStream(File f, Charset charset) 打印流直接通向文件对象,并指定编码
public PrintStream(String filepath) 打印流直接通向文件路径
public void print(Xxx xx) 打印任意类型的数据出去

PrintWriter

构造器 说明
public PrintWriter(OutputStream os) 打印流直接通向字节输出流管道
public PrintWriter (Writer w) 打印流直接通向字符输出流管道
public PrintWriter (File f) 打印流直接通向文件对象
PrintWriter(File file, Charset charset) 打印流直接通向文件对象,并指定编码
public PrintWriter (String filepath) 打印流直接通向文件路径
public void print(Xxx xx) 打印任意类型的数据出去

输出语句重定向
image

PrintStream ps = new PrintStream(new FileOutputStream("src\\ab.txt", true));
System.setOut(ps);
System.out.println("你好");

11、数据流

用来操作基本数据类型和字符串的(8 + String)
DataInputStream:将文件中存储的基本数据类型和字符串写入内存的变量中
DataOutputStream:将内存中的基本数据类型和字符串的变量写出文件中

// 输出
DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("F:\\我的文件\\data1.txt")));

dos.writeUTF("你好");
dos.writeBoolean(false);
dos.writeDouble(9.71);
dos.writeInt(82);

dos.close();
// 输入
DataInputStream dis = new DataInputStream(new FileInputStream(new File("F:\\我的文件\\data1.txt")));

System.out.println(dis.readUTF());
System.out.println(dis.readBoolean());
System.out.println(dis.readDouble());
System.out.println(dis.readInt());

dis.close();

12、RandomAccessFile

java.io.RandomAccessFile 类主要支持对随机访问文件的读写操作

  • r:以只读方式打开
  • rw:打开以便读取和写入
  • rwd:打开以便读取和写入,同步文件内容的更新
  • rws:打开以便读取和写入,同步文件内容和元数据的更新
方法名 说明
RandomAccessFile(String name, String mode) 根据参数指定的名称和模式构造对象
int read() 读取单个字节的数据
void seek(long pos) 用于设置从此文件的开头开始测量的文件指针偏移量
void write(int b) 将参数指定的单个字节写入
void close() 用于关闭流并释放有关的资源

13、commons-io

commons-io 是 apache 开源基金组织提供的一组有关 IO 操作的类库,可以提高 IO 功能开发的效率
commons-io 工具包提供了很多有关 IO 操作的类,有两个主要的类 FileUtils、IOUtils
将 commons-io-2.11.0.jar 文件复制到 lib 文件夹就可以使用了

FileUtils

方法名 说明
String readFileToString(File file, String encoding) 读取文件中的数据,返回字符串
void copyFile(File srcFile, File destFile) 复制文件
void copyDirectoryToDirectory(File srcDir, File destDir) 复制文件夹
Files.copy(Path.of("D:\\resources\\hu.jpg"), Path.of("D:\\resources\\hu2.jpg")); // java 自己的
posted @ 2023-06-08 17:53  lidongdongdong~  阅读(37)  评论(0编辑  收藏  举报