文件与路径

File 类

  • 用于文件本身属性和操作(增删改查)

Java 7 新包

java.nio.file https://blog.csdn.net/qq877728715/article/details/104499687/

Files 类

  • 文件复制,linux 属性 rwx 等高级功能

Path 类

  • 新工具,用来取代 java.io.file.File 类

相对路径

https://stackoverflow.com/questions/204784/how-to-construct-a-relative-path-in-java-from-two-absolute-paths-or-urls

  • 使用 Path.relativize()

    • your_base.relativize(your_want_to_compare)
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
      import java.nio.file.Path;
      import java.nio.file.Paths;
    
      public class Test {
    
    public static void main(String[] args) {
       Path pathAbsolute = Paths.get("/var/data/stuff/xyz.dat");
       Path pathBase = Paths.get("/var/data");
       Path pathRelative = pathBase.relativize(pathAbsolute);
       System.out.println(pathRelative);
    }
    
      }

路径的 join

1
2
  Path path = Paths.get("/home", "your_dir", "your_file");
  // path: /home/your_dir/your_file

序列化 <<序列化概念>>

  • 概念

    • 所谓的序列化就是将对象流化,就是将对象变成字节

相关类

  • 前提

    • 必须实现 java.io.Serializable 接口
  • ObjectInputStream
  • ObjectOutputStream

    • 注意

      • 存在安全隐患,因为不需要构造函数创建对象(ObjectInputStream)
      • 更推荐使用 json 序列化

增删改查

  • 注意

    • 除掉 查询,其它都发生了数据的改变

字节流

https://www.w3cschool.cn/minicourse/play/java_io_my?cp=4790

  • 按 byte 类型读写
  • 类的命名特点

    • 一般以 InputStream 或 OutputStream 结尾,

      • eg: FileOutputStream
  • 用途

    • 复制文件

      • 因为是以字节为单位读写,相当于没有发生转码的原始数据
      • 读写只是数据本身的复刻
  • 特点

    • 相当于 python: open("your_file", "rb")

文件流

FileOutputStream

  • 文件字节输出流

    1
    
    fout.write(String.getBytes());
  • bool write(byte[] arr)

    • 返回值
  • 表示是否写入成功

FileInputStream

  • 文件字节输入流
  • 方法

    • int read();
  • 一次只读取一个字节 byte
  • 文件结束,返回 -1
  • 导致的问题

    • 双字节字符(如:中文),对返回值 (char) ret_val 导致乱码

BufferedOutputStream

  • 继承了 FileOutputStream
  • 使用

    • 对 FileOutputStream 进行包装
    • 在构造函数中传入 FileOutputStream 对象
1
2
  FileOutputStream fout = new FileOutputStream("your_file");
  BufferedOutputStream bout = new BufferedOutputStream(fout);
  • bool write(byte [] arr, int start_pos, int to_write_len)

    • 对输入数据 arr, 写入一段
  • 关闭问题

    • 先关闭
  • BufferedOutputStream

    • 后关闭
  • FileOutputStream

    • 穿脱原理
  • 类似 C++ 析构过程

BufferedInputStream

1
2
  byte [] arr = new byte[1024];
  int len = bis.read(arr);
  • int read(byte[] array)

    • 返回值
  • 实际接收大小
  • 特殊值:-1

    • 表示到文件结尾

      • 作用
  • 使用 byte [] array 批量接收内容

对象流

  • 注意

    • 被读写对象

      • 需要实现 Serializable 接口
  • Serializable 其实是一个空接口,只是用来标记而已

    • 辅助唯一化工具:final 属性 serialVersionUID
  • 可以使用 IDE 自动生成
1
  private static final long serialVersionUID = -2342342342342342343344545L
  • 作用机理

    • static 属性 是 类属性,它又是 final 属性

      • 这样就 决定了, serialVersionUID 和 类是 一一对应关系
    • 特点

      • 一个文件只能对应一个对象(个人见解)
      • 一个文件保存多个对象

        • 实现方法
  • 把多个对象保存到容器中,如: HashMap
  • 把这个容器,序列化到文件中

ObjectOutputStream

  • 使用

    • 需要包装 FileOutputStream

ObjectInputStream

字符流

  • 命名惯例

    • 以 Reader 或 Writer 结尾

      • eg: FileReader, FileWriter

FileWriter

  • 类似 FileOutputStream

    • 只不过,处理的对象,换成了单个“字符”
  • 方法

    • void write(int c)
    • void write(String str)
    • void write(String str, int offset, int len)

FileReader

  • 方法

    • int len = fileReader.read()

      • 读取单个字符
      • 返回 -1, 表示终止
    • int len = fileReader.read(char[] arr)

      • 向 字符数组 arr 读取
      • len:
  • 表示有效读取数量
  • 返回 -1: 表示终止

    1
    2
    3
    4
    5
    6
    7
    
      FileReader fr2 = new FileReader("FileWrite_test.txt");
      char[] buf = new char[6];
      int len;
      while((len=fr2.read(buf)) != -1){
    String str = new String(buf,0,len);
    System.out.print(str);
      }

BufferedWriter

  • 继承了 FileWriter
  • 类似 BufferedOutputStream
  • 方法

    • bufferedWriter.write("your_words")
    • bufferedWriter.newLine()

      • 跨平台换行符
  • linxu –> "\n"
  • windows –> "\r\n"
  • macos –> "\r"

BufferedReader

  • 方法

    • String str = bufferedReader.readLine()

      • 终止判断
  • null –> 终止
  • "" –> 空串

字节流 输入输出乱码问题

视频教程 https://www.w3cschool.cn/minicourse/play/java_io_my?cp=4797&gid=0

  • 乱码根源

    • 没有设置好编码
    • 默认编码在做怪

      • 而,一般的 输入输出流,不能指定编码

解决办法

写入时

  • 方法一

    • 编码写入数据源
    • buffferOutputStream.write("你好,写入".getBytes("utf-8"))
  • 方法二

    • 创建指定了编码的类
  • 好处: 这样不用每次都对数据源进行编码
  • OutputStreamWriter(fileOutputStream, "UTF-8")
  • outputStreamWriter.write("你好,写入")

    • 多级包裹,实现编码

      • BufferedWriter(OutputStream(FileOutputStream("your_file"), "utf-8"))

读取时

https://stackoverflow.com/questions/14918188/reading-text-file-with-utf-8-encoding-using-java

  • bufferedInputStream.read(char [] arr)

    • arr.
  • 多级包裹,实现编码

    • BufferedReader(InputStream(FileInputStream("your_file"), "utf-8"))

PrintStream 和 InputStrean

PrintStream

特殊实例

  • System.out
  • System.err

InputStream

  • 基类

特殊实例

  • System.in

异常出现问题

  • 读取文件

    1. new FileInputStream("/our/file")

      • FileNotFoundException
    2. input.read()

      • IOException

读取完成

  • read() == -1

关闭流

  • 手动法

    1
    2
    3
    4
    5
    6
    7
    8
    
      try{
    
      }
      finally {
    if (input != null)
       input.close()
    
      }
  • 自动法

    • 注:需要实现 java.lang.AutoClosable 接口

      1
      2
      3
      
      try( InputStream input = new FileInputStream("/my/file.txt"))
      {
      }

阻塞

  • strea.read() 会发生阻塞

独写

  • 以 byte[] 快速成批独写

数据转换

  • 获取的是地址

    • 直接输出 outBytes
  • 输出的是地址

输入输出字节流

  • InputStream

    • FileInputStream

      • read()
    • ByteArrayInputStream

      • 构造
  • new ByteArrayInputStream(byte[] outBytes)

    • OutputStream

      • FileOutputStream

        • write()
        • flush
        • close()
      • ByteArrayOutputStream

        • 方法
  • output.toByteArray()

衍生输入流 方式

  • 解说

    • Filter 模式,或者说装饰器模式:Decorator

      • 作用:在运行期,增加功能
    • 注:可以自己写一个 FilterInputStream 衍生类
  • 再衍生

    • BufferedInputStream
    • DataInputStream
    • CheckedInputStream

读取文件作为 byte[]

  • 传统方法

    1
    2
    3
    4
    5
    6
    7
    8
    
      InputStream input = new FileInputStream("myfile.txt");
      ByteArrayOutputStream buffer = new ByteArrayOutputStream();
      int n;
      while ((n = input.read()) != -1){
    buffer.write(n)
      }
    
      return buffer.toByteArray()
    • 注意

      • 为什么使用 ByteArrayOutputStream
  • 这里 ByteArrayOutputStream 大小可变
  • 防止文件在打开后大小改变(其它程序修改文件)

    • 以免起初创建的 byte[] buffer 被挤爆

      1
      
        byte[] buffer = new byte[ourFile.getLength()]
      • 错误:预先设定 buffer 大小
  • 新方法 nio

    1
    
      byte[] buffer = Files.readAllBytes(Paths.get("myFile.txt"));
    • 注意

      • 陷阱:文件太大,会发生内存溢栈

读取 classpath 中文件

字符流

  • 字节流,读写 byte

文件读写

  • FileReader

    • 构造:—> 可以指定编码

      1
      
        Reader = new FileReader("/my/file.txt", "utf-8")
      • 注意
  • 指定 编码 的 重载构造函数,在 jdk 11 之后才有
  • 早期 jdk8, 使用 new InputStreamReader(input, "utf-8") 指定

    • 方法

      • int read()
  • 结束,返回 -1

    • int read(byte[] buffer)
    • FileWriter

字符数组 char[] 读写

  • CharArrayReader
  • CharArrayWriter

String 读写

  • StringReader
  • StringWriter

转换 字节流 —> 字符流

  • InputStreamReader

    • 作用:

      • 包裹 InputStream 变成 Reader 字符流
1
2
  InputStream input = new FileInputStream("/my/file.txt")
  Reader reader = new InputStreamReader(input, "utf-8");
  • OutputStreamWriter

高阶输出工具

  • 一种 Filter 工具

PrintStream

  • 输出字节流 byte
  • 方法

    • print(int)
    • print(boolean)
    • print(String)
    • print(Object)
    • println(…)
  • 比较 OutputStream

    • 只有 write(byte) 和 write(byte[])
  • 实例

    • System.out
  • 特点

    • 不抛出 IOException

PrintWriter

  • 输出字符流

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
      public class Main {
    public static void main(String[] args)     {
       StringWriter buffer = new StringWriter();
       try (PrintWriter pw = new PrintWriter(buffer)) {
    pw.println("Hello");
    pw.println(12345);
    pw.println(true);
       }
       System.out.println(buffer.toString());
    }
      }
  • 特点

    • 类似 PrintStream
    • 但是,输出字符流
  • 一个 Filter 工具