Java笔记 -File文件相关

编码表

  • ASCII码表: 包含大小写英文字母、标点符号、控制字符,一个字符占用 1 个字节
  • GBK: 中文简体操作系统默认的字符集码表,兼容 ASCII 字符集,包含2万多个汉字,以及一些日韩文字,一个字母占 1 个字节、一个汉字占 2 个字节
  • Unicode: 由国际组织 ISO 指定,是统一的万国码,包含常用的3种不同的编码方案(UTF-8、UTF-16、UTF-32),所以实际上是不存在 UTF-8表的,被市场认可的是 UTF-8,1个字母占用 1 个字节,1个汉字占用 3 个字节

在这里插入图片描述

编码解码

  • getBytes(): 使用平台默认的字符集将该字符串转换为字符集,也可以指定编码方案
  • String(byte[] bytes): 使用平台默认的字符集解码指定的字符集为字符串,也可以指定编码集
    例:
String str = "你好";

System.out.println(Arrays.toString(str.getBytes()));
System.out.println(Arrays.toString(str.getBytes("GBK")));

byte[] bytes1 = {-28, -67, -96, -27, -91, -67};
System.out.println(new String(bytes1));

byte[] bytes2 = {-60, -29, -70, -61};
System.out.println(new String(bytes2, "GBK"));

File

概述

  • 文件的目录可以通过 File 封装成对象
  • File 封装的对象仅仅是一个路径名,它可以是存在的,也可以是不存在的

路径

  • 相对路径: 从项目的根路径开始
  • 相对路径: 从系统的盘符开始 getAbsoluteFile() 获取绝对路径

File的基本方法

  • creatNewFile
    • 如果文件不存在,返回 true,创建成功
    • 如果文件存在,返回 false,创建失败
    • 只能创建文件,无论有没有后缀
  • mkdir
    • 只能创建单级文件夹,不能创建多级文件夹
    • 不管有没有后缀,只能创建单击文件夹
  • mkdirs
    • 可以创建单级文件夹,也能创建多级文件夹
    • 不管有没有后缀,只能创建文件夹
  • delete
    • 如果删除的是文件,可以直接删除
    • 如果删除的是文件夹,只能删除空文件夹,如果文件夹中有东西,必须进入文件夹中删除里面内容之后,才能删除该文件夹

常用判断和获取功能

  • isDirectory: 是否是目录
  • isFile: 是否是文件
  • exists: 是否存在
  • getName: 获取文件名
  • listFiles: 进入文件夹,并获取这个文件夹下所有的文件和文件夹的 File 对象,并把这些 File 对象保存在一个 List 对象中
    • 当调用者不存在时: 返回 null
    • 当调用者为一个文件时: 返回 null
    • 当调用者是一个空文件夹时: 返回一个长度为 0 的数组
    • 当调用者是一个有内容的文件夹时: 返回里面所有的文件和文件夹的路径放在 File 数组中返回
    • 当调用者是一个无权进入的文件夹时: 返回 null
    • 当调用者是一个有隐形文件的文件夹时: 将里面的所有文件和文件夹的路径放在 File 数组中返回,包含隐藏内容

IO流

IO流是用来读写数据的(可以是文件中的数据,也可以是网络中的数据)

IO流的分类

  • 按照数据的流向分类:
    • 输入流: 把数据从硬盘或网络读出
    • 输出流: 把数据从内存写入硬盘或网络
  • 按照读写的文件类型分类:
    • 字节流: 它可以读写任何类型的文件
    • 字符流: 它只能读写文本文件
  • 将上述的两种划分方式进行结合划分:
    • 字节输入流
    • 字节输出流
    • 字符输入流
    • 字符输出流

字节流

字节输出流 FileOutputStream

专门往文件中写字节数据

步骤
  1. 创建FileOutputStream对象,关联一个文件路径(如果文件不存在,会自动创建;如果存在,会覆盖掉,第二个参数为续写开关)
  2. 调用write方法写数据,只能写字节,不能写字符串(String.getBytes可以将字符串转换为字节数组)
  3. 调用close关闭流
    1. 如果不关闭流,则该文件一直被占用,其余程序不可使用该文件
    2. JDK7之后,Java会自己释放资源,格式是:
try (创建资源对象) {
  
} catch (异常类) {
  
} // 特点: 不需要手动释放资源

例:

try (FileOutputStream fos = new FileOutputStream("a.txt")) {
    for (int i = 0; i < 26; i++) {
        fos.write(97 + i);
    }
    fos.write("\r\n".getBytes());
} catch (IOException e) {
    e.getMessage();
}
注:
  • win换行符为: \r\n 先回车 再换行
  • unix换行符为: \n
  • mac换行符为: \r

字节流读入数据FileInputStream

步骤
  1. 创建字节读入流对象,如果文件存在,那么就不会报错,如果文件不存在,就会报错
  2. 调用read方法读数据 (一次读一个字节,读到末尾返回 -1,不能读中文,会乱码)
  3. 调用close方法关闭流

例:

try (FileInputStream fis = new FileInputStream("a.txt")) {
    int ch = fis.read();
    while (ch != -1) {
        System.out.print((char)ch);
        ch = fis.read();
    }
} catch (IOException e) {
    e.getMessage();
}

文件复制

方法1(不推荐)
try (FileInputStream fis = new FileInputStream("a.txt");
     FileOutputStream fos = new FileOutputStream("test\\a.txt")) {
    int ch = fis.read();
    while (ch != -1) {
        System.out.print((char)ch);
        fos.write(ch);
        ch = fis.read();
    }
} catch(IOException e) {
    e.printStackTrace();
}
方法2
try (FileInputStream fis = new FileInputStream("a.txt");
     FileOutputStream fos = new FileOutputStream("test\\a.txt")) {
    byte[] bytes = new byte[1024];  // 一次可以读取的最大字符数
    int len = fis.read(bytes);  // len是该次读取到的字符数
    while (len != -1) {
        System.out.println("此次读取到" + len + "个字符");
        fos.write(bytes, 0, len);
        len = fis.read(bytes);
    }
} catch(IOException e) {
    e.printStackTrace();
}

字节缓冲流

字节缓冲流仅提供缓冲区,真正读写的是基本的字节流,所以参数是基本字节流

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test/a2.txt"));
byte[] bytes = new byte[1024];

len = bis.read(bytes);
while (len != -1) {
    System.out.println("本次读出: " + len);
    bos.write(bytes, 0, len);
    len = bis.read(bytes);
}
  • 字节缓冲流关闭,原始流也关闭
  • 创建缓冲流之后生成一个长度为8192的缓冲数组

字符流

概述

  • 不同的编码方案对于同一个中文汉字底层用的字节数是不一样的,所以如果读取的时候读取到的字节,查询编码表,查不到对应的字符就会有乱码
  • 为了解决这个问题,所以 Java 提供了字符流,字符流的底层其实是字节流+编码表,字符流在读取数据时,会按照中文字符和英文字符底层编码的特征自动识别,那些字节是中文,哪些字节是英文
  • 所有的英文字符它底层的编码特征都是正数,所有的中文字符编码特征都是负数,字符流读取字母时,它就一个字节一个字节地读;字符流在读取汉字时(假设是 UTF-8 编码方案),它就3个字节 3 个字节的读

字符流写数据

步骤

  1. 创建一个字符输出流 FileWriter 对象
  2. 写入数据: write
  3. 释放资源: close

flush、close

  • flush: 刷新流,之后还可以继续写数据
  • close: 关闭流,之后不可继续写数据

注意事项

  • 如果 FileWriter 关联的文件不存在,会自动创建(父路径需存在)
  • 如果 FileWriter 关联的文件的父路径不存在,会报错
  • 如果 FileWriter 关联的文件存在,此时会将已有的文件覆盖掉
  • 调用 write 方法写数据,其实数据并没有直接到文件中去,而是在内存中有缓存,此时可以调用 flush 方法,将数据刷新到文件中
  • 当调用 close 方法时,即使前面没有调用 flush 方法,也会自动刷新到文件中,再关闭流

例:

try (FileWriter fw = new FileWriter("a.txt", true)) {
    char[] chars = {'你', '好', '世', '界'};
    fw.write(chars);
    fw.write("\r\n");
    fw.write(chars, 0,1);
    fw.write("\r\n");
    fw.write(chars, 0, 2);
} catch (IOException e) {
    e.printStackTrace();
}

字符流读数据

Java 中提供了一个类叫 Reader 类,这是所有字符输入流的父类,我们如果想要从文件中读取字符数据

步骤

  1. 创建 FileReader 输入流对象,关联一个文件路径(文件必须存在)
  2. 调用 read 方法读取文件中的字符
  3. 调用 close 关闭流

例:

try (FileReader fr = new FileReader("a.txt")) {
    int len;
    char[] chars = new char[1024];
    while ((len = fr.read(chars)) != -1) {
        System.out.println("本次读到: " + len + "个字符");
        System.out.println(new String(chars, 0, len));
    }
} catch (IOException e) {
    e.printStackTrace();
}

字符缓冲流

类似于字节缓冲流

特有方法

  • newLine(): 写一个行分隔符,分隔符字符由系统决定
  • readLine(): 读一整行数据

例:

try (BufferedReader br = new BufferedReader(new FileReader("a.txt"));
     BufferedWriter bw = new BufferedWriter(new FileWriter("test/a.txt"))) {
    char[] chars = new char[1024];
    int len = 0;
    while ((len = br.read(chars)) != -1) {
        System.out.println("本次复制: " + len + "个字符");
        bw.write(chars, 0, len);
    }
    } catch (IOException e) {
    e.printStackTrace();
}
// 对源文件数据进行排序,再写回
// 3 2 1 5 4 2 1 10 9 8 7 1 11 10
int[] nums = null;
try (BufferedReader br = new BufferedReader(new FileReader("a.txt"))) {
    String s = br.readLine();
    String[] numsStr = s.split(" ");
    nums = new int[numsStr.length];
    for (int i = 0; i < numsStr.length; i++) {
        nums[i] = Integer.parseInt(numsStr[i]);
    }
    Arrays.sort(nums);
} catch (IOException e) {
    e.printStackTrace();
}

try (BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"))) {
    for (int num : nums) {
        bw.write(num + " ");
        bw.flush();
    }
} catch (IOException e) {
    e.printStackTrace();
}

其他流

转换流 InputStreamReader/OutputStreamWriter

JDK11之前可以使用该方法指定字符集 JDK11之后使用FileReader/FileWriter的新构造方法
截图

在这里插入图片描述

  • 使用转换流可以针对不同的字符集进行读取
  • 当拿到一个流是 InputStream 或者 OutputStream 时,可以利用转换流转换成字符流

例:

try (InputStreamReader isr = new InputStreamReader(new FileInputStream("窗里窗外.txt"), "GBK")) {
    char[] chars = new char[1024];
    int len = 0;
    while ((len = isr.read(chars)) != -1) {
        System.out.println(new String(chars, 0, len));
    }
} catch (IOException e) {
    e.printStackTrace();
}

扩展

  • 不用转换流,也能指定编码读写数据
// JDK8不支持
FileReader fr = new FileReader("", Charset.forName("UTF-8"));
FileWriter fw = new FileWriter("", Charset.forName("UTF-8"));
  • 既想指定字符集又想用 BufferedReader/Writer 进行操作
InputStreamReader isr = new InputStreamReader(new FileInputStream(), "GBK");
BufferedReader br = new BufferedReader(isr);

对象操作流

可以把对象以字节的形式写入文件中,将对象从文件中读入到内存中,该对象需实现 Serializable

对象操作输入流(对象序列化流)ObjectInputStream

方法
对象.readObject();

对象操作输出流(对象反序列化流)ObjectOutputStream

方法
对象.writeObect();

例:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
Student student = new Student("test1", 1);

oos.writeObject(student);

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
        
Student student = (Student) ois.readObject();
System.out.println(student);

  • 被序列化或者反序列化的类,需实现 Serializable 接口
  • 序列化和反序列化,它们的序列号必须保持一致
    1. 如果我们自己没有定义,那么虚拟机会根据类中的信息自动计算出来一个序列号
    2. 如果我们修改了类中的信息,那么虚拟机会再次计算出一个序列号
    3. 两次对比序列号不一致,就会抛出异常
    4. 所以我们可以手动给出一个序列号: private static final long serialVersionUID = 42L; // 数值可以随意写
  • 如果对象的一个成员变量不想被序列化,可以加上 transent 关键字修饰,该关键字标记的成员变量不参与序列化过程
  • 如果想要往文件中写多个对象,建议把多个对象先存入一个集合中,然后把集合当作一个整体存入文件中去

Properties

概述

  • 是一个 Map 体系的集合类
  • Properties 中有跟 IO 有关的方法
  • 只存字符串

方法

  • put: 增,没有泛型,所以可以存储任意类型,不过只存储字符串
  • remove: 删,根据键删除
  • put: 改
  • get: 查

特有方法

  • setProperty: 类似于 put
  • getProperty: 类似于 get
  • stringPropertyName: 从该属性列表返回一个键值集合

与IO集合相结合

  • load: 从本地文件的键值对数据读取
  • store: 将集合中的数据以键值对形式保存在本地

注意事项

  • 本质上是 HashTable 的一个子类,和 HashMap 基本使用相同
  • Properties 中的 putget 方法的参数、返回类型都是 obj
  • Properties 类一般只会存储字符串
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值