File类

前提条件

IO流是什么?

  1. 可以将数据从本地文件中读取出来
  2. 可以将数据从内存保存到本地文件

File类是什么?

  1. 在读写数据时告诉虚拟机要操作的(文件/文件夹)在哪
  2. 对(文件/文件夹)本身进行操作。包括创建,删除

    File类概述和构造方法

    File:它是文件和目录路径名的抽象表示
  • 文件和目录可以通过File封装成对象
  • File封装的对象下仅仅是一个路径名。它可以是存在的,也可以说不存在的。 | 方法名 | 说明 | | —- | —- | | File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 | | File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的File实例 | | File(File parent,String child) | 从父抽象路径名和子路径名字符串创建新的File实例 |

绝对路径和相对路径

绝对路径:从盘符开始
相对路径:相对当前项目下的路径

新建文件和文件夹

public boolean createNewFile():创建一个新的空的文件夹
注意点

  1. 如果文件夹不存在,那么创建成功,返回true
  2. 如果文件夹存在,那么创建失败,返回false
  3. createNewFile方法不管调用者有没有后缀名,只能创建文件

public boolean mkdir():创建一个单级文件夹
注意点

  1. 只能创建单级文件夹,不能创建多级文件夹
  2. 不管调用者有没有后缀名,只能创建单级文件夹

public boolean mkdirs():创建一个多级文件夹
注意点

  1. 可以创建单级文件夹,也可以创建多级文件夹
  2. 不管调用者有没有后缀名,只能创建文件夹

    删除文件和文件夹

    public boolean delete():删除文件或文件夹
    注意点

  3. 不走回收站

  4. 如果删除的是文件,那么直接删除,如果删除的是文件夹,那么能删除空文件夹
  5. 如果要删除一个有内容的文件夹,只能先进入到这个文件夹,把里面的内容全部删除完毕,才能再次删除这个文件夹

    File类判断和获取功能

    | 方法名 | 说明 | | —- | —- | | public boolean isDirectory() | 测试此抽象路径名表示的File是否为目录 | | public boolean isFile() | 测试此抽象路径名表示的File是否为文件 | | public boolean exists() | 测试此抽象路径名表示的File是否存在 | | public String getName() | 返回由此抽象路径名表示的文件或目录的名称 |

getName()注意点:

  1. 如果调用者是文件,那么获取的是文件名和后缀名
  2. 如果调用者是一个文件夹,那么获取的是文件夹的名字

    File类高级获取功能

    | 方法名 | 说明 | | —- | —- | | public File[] listFiles() | 返回此抽象路径名表示的目录中的文件和目录的File对象数组 |

listFile方法注意事项:

  • 当调用者不存在时,返回null
  • 当调用者是一个文件时,返回null
  • 当调用者是一个空文件夹时,返回一个长度为0的数组
  • 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
  • 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
  • 当调用者是一个需要权限才能进入的文件夹时,返回null

    IO流

    IO流概述

    其中:I表示input,是数据从硬盘进内存的过程,称之为读。
    O表示output,是数据从内存到硬盘的过程,称之为写。
    IO的数据传输,可以看作是一种数据的流动,按照流动的方向,以内存为参照物,进行读写操作

    IO流的分类

    IO流的分类.png
    一般来说,我们说IO流的分类是按照数据类型来分的

    字节流写数据

  1. 创建字节输出流对象—-告诉虚拟机我要往哪个文件中写数据了
    注意事项:
    如果文件不存在,就创建
    如果文件存在就清空
  2. 写数据
    注意事项:
    写出的整数,实际写出的是整数在码表上对应的字母
  3. 释放资源
    注意事项:
    每次使用完流必须要释放资源

三种方法

方法名 说明
void write(int b) 一次写一个字节数据
void write(byte[] b) 一次写一个字节数组数据
void write(byte[] b, int off, int len) 一次写一个字节数组的部分数据从off开始长度为len

字节流写数据如何实现换行?
写完数据后,加换行符
windows:\r\n
linux:\n
mac:\r
换行符ASCII是10
也可以"/r".getbyte获得换行符的字符
字节流写数据如何实现追加写入?

  • public FileOutputStream(String name, boolean append)
  • 创建文件输出流以指定的名称写入文件,如果第二个参数为true,不会清空文件里面的内容

    字节流写数据加try…catch异常处理

    ```java package com.heima.myiostream;

import java.io.FileOutputStream; import java.io.IOException;

public class MyIOStream1 { public static void main(String[] args) { FileOutputStream fos = null; try{ fos = new FileOutputStream(“/Users/huangbentai/Documents/JAVA/AdvancedCode/myIO/src/com/heima/testfile/a.txt”); fos.write(97); }catch (IOException e){ e.printStackTrace(); }finally { if (fos != null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }

  1. <a name="yuHw6"></a>
  2. ## 字节流读数据
  3. 1. 创建字节输入流对象<br />注意事项:<br />如果文件存在,那么就不会报错<br />如果文件不存在,那么就直接报错
  4. 1. 读取数据<br />注意事项:<br />一次读取一个字节,返回值,就是本次读到的那个字节数据<br />也就是字符在码表中对应的那个数字<br />如果我们想要看到的是字符数据,那么一定要强转成char
  5. 1. 释放资源
  6. 多个字节流的读取
  7. ```java
  8. package com.heima.myiostream;
  9. import java.io.FileInputStream;
  10. import java.io.IOException;
  11. public class MyIOInputStream2 {
  12. public static void main(String[] args) throws IOException {
  13. FileInputStream fileInputStream = new FileInputStream("myIO/src/com/heima/testfile/a.txt");
  14. int a;
  15. while ((a = fileInputStream.read()) != -1){
  16. System.out.println((char)a);
  17. }
  18. fileInputStream.close();
  19. }
  20. }

提高拷贝速度的解决方案

为了解决速度问题,字节流通过创建字节数组,可以一次读写多个数据
一次读一个字节数组的方法:

  • public int read(byte[] b):从输入流读取最多b.length个字节的数据
  • 返回的是读入缓冲区的总字节数,也就是实际的读取字节个数

    字节流缓冲流

    字节缓冲流:

  • BufferOutputStream:字节缓冲输出流

  • BufferInputStream:字节缓冲输入流

构造方法:

  • 字节缓冲输出流:BufferedOutputStream(OutputStream out)
    • 底层是创建一个字节数组
  • 字节缓冲输入流:BufferedInputStream(InputStream in)
    • 底层是创建一个字节数组

为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?

  • 字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作

    字节缓冲流原理

    单字节
    缓冲流原理.png
    字节数组
    缓冲流原理字节数组.png

    字节流小结

    字节流:
    可以操作(拷贝)所有类型的文件
    字节缓冲流:
    可以提高效率
    不能直接操作文件,需要传递字节流
    拷贝文件的四种方式:

  • 字节流一次读写一个字节

  • 字节流一次读写一个字节数组
  • 字节缓冲流一次操作一个字节
  • 字节缓冲流一个操作一个字节数组

    字符流

    如果利用字节流,把文本文件中的中文,读取到内存中,有可能出现乱码
    如果利用字节流,吧中文写到文本文件中,也有可能出现乱码

    编码表

    重点:windows默认使用码表为:GBK,一个字符两个字节
    idea和以后工作默认使用Unicode的UTF-8解码格式,一个中文三个字节

    字符串的编码和解码

    编码:

  • byte[] getBytes():使用平台的默认字符集(UTF-8)将该String编码为一系列字节,将结果储存到新的字节数组中。

  • byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到。

解码:

  • String(byte[] bytes):使用平台的默认字符集解码指定的字节数组来构造新的String
  • String(byte[] bytes,String charsetName):通过指定的字符集解码指定的字节数组来构造新的String

字节流读取中文出现乱码的原因:
因为字节流读中文,每次只能读一部分所以出现了乱码。

字符流读取中文的过程

  • 字符流 = 字节流 + 编码表

基础知识:不管是在哪张码表中,中文的第一个字节一定是负数

小结

  1. 想要进行拷贝,一律使用字节流或者字节缓冲流
  2. 想要把文本文件中的数据读到内存中,请使用字符输入流
  3. 想要把内存中的数据写到文本文件中,请使用字符输出流
  4. GBK码表一个中文两个字节,UTF-8编码格式一个中文三个字节

    字符流写数据

  5. 创建字符流输出对象

    • FileWriter(File file):给一个File对象构造一个FileWriter对象
    • FileWriter(String fileName):给一个文件路径构造一个FileWriter对象
  6. 写数据 | 方法名 | 说明 | | —- | —- | | 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) | 写一个字符串的一部分 |

  7. 释放资源

    flush和close方法

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

字符流读取数据

  1. 创建字符流读取对象
    • FileReader(File file)
    • FileReader(String fileName)
  2. 读取数据
    • int read():读一个字符
    • int read(char[] cbuf):读一个字符数组
  3. 释放资源

    字符缓冲输入流

  4. 创建字符缓冲输入流对象

    • BufferedReader(Reader in)
  5. 读取数据
    • int read()读一个字符
    • int read(char[])读一个字符数组
    • mac遇到中文+\r字符的时候,一整行会被略过,应该在包含中文的字符串中使用\n作为换行
  6. 释放资源

    字符缓冲输出流

  7. 创建字符缓冲输出流对象

    • BufferedWriter(Writer out)
  8. 写入数据
  9. 释放资源

    字符缓冲流特有功能

    BufferedWriter:
  • void newLine():写一行行分隔符,行分隔符字符串由系统属性定义

BufferedReader:

  • public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何终止字符,如果流的结尾已经到达,则为null

输出流对象创建不能直接写在输入流下面

IO流小结

IO流小结.png

其他流

转换流

转换流.png
转换流就是来进行字节流和字符流之间转换的
InputStreamReader是从字节流到字符流的桥梁
OutputStreamWriter是从字符流到字节流的桥梁
在JDK11之前,使用转换流来指定编码表

InputStreamReader isr = new InputStreamReader(new FileInputStream("/Users/huangbentai/Documents/JAVA/AdvancedCode/myIO/src/com/heima/testfile/c.txt"),"gbk");

在JDK11之后,使用字符流的新构造来指定编码表

FileReader fr = new FileReader("/Users/huangbentai/Documents/JAVA/AdvancedCode/myIO/src/com/heima/testfile/c.txt", Charset.forName("gbk"));

对象操作流

对象操作流特点

可以把对象以字节的形式写到本地文件,直接打开文件,是无法读懂的,需要再次用对象操作流读到内存中。
对象操作流分为两类:对象操作输入流和对象操作输出流
对象操作输出流(对象序列化流):就是将对象写到本地文件中,或者在网络中传输对象
对象操作输入流(对象反序列化流):把写到本地文件中的对象读到内存中,或者接收网络中传输的对象

对象操作流写出

ObjectOutputStream(OutputStream out):构造方法
void writeObject(Object obj):写入方法,其中obj需要实现Serializable接口
Serializable接口的意义
是一个标记性接口,里面没有任何的抽象方法
只要一个类实现了这个Serializable接口,那就表示这个类的对象可以被序列化

对象操作流输入

ObjectInputStream(InputStream in):构造方法
Object readObject():读取方法

对象操作流注意点

用对象序列化流序列化一个对象后,假如我们修改了对象所属的Javabean类,读取数据会不会出问题呢?
答:会出问题,会抛出InvalidClassException异常
如果出问题了,如何解决呢?
答:给对象所属的类加一个serialVersionUID
private static final long serialVersionUID = 1L;
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
答:给该成员变量家transient关键字修饰,该关键字标记的成员变量不参与序列化过程

Properties

Properties概述

  • 是一个Map体系的集合类
  • Properties中有跟IO相关的方法
  • 键值对的数据类型基本都定义为字符串

    Properties作为集合的特有方法:

    | 方法名 | 说明 | | —- | —- | | Object setProperty(String key, String value) | 设置集合的键和值,都是String类型,底层调用Hashtable方法put | | String getProperty(String key) | 使用此属性列表中指定的键搜索属性 | | Set<String> stringPropertyNames() | 从该属性列表中返回一个不可修改的键集,其中键及其对象的值是字符串 |

Properties读取

void load (Reader reader):将本地文件中的键值对数据读取到集合当中
本地文件需要以.properties作为文件名后缀
本地文件内容:

key=value
.
.
.

需要构造一个FileReader对象,并且在调用完毕之后关闭
调用玩load方法之后,文件中的键值对数据已经在集合中了

Properties储存

void store (Writer writer, String comments):将集合中的数据以键值对形式保存在本地
comments:为一段注释