File类
前提条件
IO流是什么?
- 可以将数据从本地文件中读取出来
- 可以将数据从内存保存到本地文件
File类是什么?
- 文件和目录可以通过File封装成对象
- File封装的对象下仅仅是一个路径名。它可以是存在的,也可以说不存在的。
| 方法名 | 说明 |
| —- | —- |
|
File(String pathname)
| 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 | |File(String parent, String child)
| 从父路径名字符串和子路径名字符串创建新的File实例 | |File(File parent,String child)
| 从父抽象路径名和子路径名字符串创建新的File实例 |
绝对路径和相对路径
新建文件和文件夹
public boolean createNewFile()
:创建一个新的空的文件夹
注意点
- 如果文件夹不存在,那么创建成功,返回true
- 如果文件夹存在,那么创建失败,返回false
- createNewFile方法不管调用者有没有后缀名,只能创建文件
public boolean mkdir()
:创建一个单级文件夹
注意点
- 只能创建单级文件夹,不能创建多级文件夹
- 不管调用者有没有后缀名,只能创建单级文件夹
public boolean mkdirs()
:创建一个多级文件夹
注意点
- 可以创建单级文件夹,也可以创建多级文件夹
-
删除文件和文件夹
public boolean delete()
:删除文件或文件夹
注意点 不走回收站
- 如果删除的是文件,那么直接删除,如果删除的是文件夹,那么能删除空文件夹
- 如果要删除一个有内容的文件夹,只能先进入到这个文件夹,把里面的内容全部删除完毕,才能再次删除这个文件夹
File类判断和获取功能
| 方法名 | 说明 | | —- | —- | |public boolean isDirectory()
| 测试此抽象路径名表示的File是否为目录 | |public boolean isFile()
| 测试此抽象路径名表示的File是否为文件 | |public boolean exists()
| 测试此抽象路径名表示的File是否存在 | |public String getName()
| 返回由此抽象路径名表示的文件或目录的名称 |
getName()
注意点:
- 如果调用者是文件,那么获取的是文件名和后缀名
- 如果调用者是一个文件夹,那么获取的是文件夹的名字
File类高级获取功能
| 方法名 | 说明 | | —- | —- | |public File[] listFiles()
| 返回此抽象路径名表示的目录中的文件和目录的File对象数组 |
listFile方法注意事项:
- 当调用者不存在时,返回null
- 当调用者是一个文件时,返回null
- 当调用者是一个空文件夹时,返回一个长度为0的数组
- 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
- 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
- 当调用者是一个需要权限才能进入的文件夹时,返回null
IO流
IO流概述
其中:I表示input,是数据从硬盘进内存的过程,称之为读。
O表示output,是数据从内存到硬盘的过程,称之为写。
IO的数据传输,可以看作是一种数据的流动,按照流动的方向,以内存为参照物,进行读写操作IO流的分类
一般来说,我们说IO流的分类是按照数据类型来分的字节流写数据
- 创建字节输出流对象—-告诉虚拟机我要往哪个文件中写数据了
注意事项:
如果文件不存在,就创建
如果文件存在就清空 - 写数据
注意事项:
写出的整数,实际写出的是整数在码表上对应的字母 - 释放资源
注意事项:
每次使用完流必须要释放资源
三种方法
方法名 | 说明 |
---|---|
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(); } } } } }
<a name="yuHw6"></a>
## 字节流读数据
1. 创建字节输入流对象<br />注意事项:<br />如果文件存在,那么就不会报错<br />如果文件不存在,那么就直接报错
1. 读取数据<br />注意事项:<br />一次读取一个字节,返回值,就是本次读到的那个字节数据<br />也就是字符在码表中对应的那个数字<br />如果我们想要看到的是字符数据,那么一定要强转成char
1. 释放资源
多个字节流的读取
```java
package com.heima.myiostream;
import java.io.FileInputStream;
import java.io.IOException;
public class MyIOInputStream2 {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("myIO/src/com/heima/testfile/a.txt");
int a;
while ((a = fileInputStream.read()) != -1){
System.out.println((char)a);
}
fileInputStream.close();
}
}
提高拷贝速度的解决方案
为了解决速度问题,字节流通过创建字节数组,可以一次读写多个数据
一次读一个字节数组的方法:
public int read(byte[] b)
:从输入流读取最多b.length个字节的数据-
字节流缓冲流
字节缓冲流:
BufferOutputStream:字节缓冲输出流
- BufferInputStream:字节缓冲输入流
构造方法:
- 字节缓冲输出流:
BufferedOutputStream(OutputStream out)
- 底层是创建一个字节数组
- 字节缓冲输入流:
BufferedInputStream(InputStream in)
- 底层是创建一个字节数组
为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?
字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
字节缓冲流原理
字节流小结
字节流:
可以操作(拷贝)所有类型的文件
字节缓冲流:
可以提高效率
不能直接操作文件,需要传递字节流
拷贝文件的四种方式:字节流一次读写一个字节
- 字节流一次读写一个字节数组
- 字节缓冲流一次操作一个字节
-
字符流
如果利用字节流,把文本文件中的中文,读取到内存中,有可能出现乱码
如果利用字节流,吧中文写到文本文件中,也有可能出现乱码编码表
重点:windows默认使用码表为:GBK,一个字符两个字节
idea和以后工作默认使用Unicode的UTF-8解码格式,一个中文三个字节字符串的编码和解码
编码:
byte[] getBytes()
:使用平台的默认字符集(UTF-8)将该String编码为一系列字节,将结果储存到新的字节数组中。byte[] getBytes(String charsetName)
:使用指定的字符集将该String编码为一系列字节,将结果存储到。
解码:
String(byte[] bytes)
:使用平台的默认字符集解码指定的字节数组来构造新的StringString(byte[] bytes,String charsetName)
:通过指定的字符集解码指定的字节数组来构造新的String
字节流读取中文出现乱码的原因:
因为字节流读中文,每次只能读一部分所以出现了乱码。
字符流读取中文的过程
- 字符流 = 字节流 + 编码表
小结
- 想要进行拷贝,一律使用字节流或者字节缓冲流
- 想要把文本文件中的数据读到内存中,请使用字符输入流
- 想要把内存中的数据写到文本文件中,请使用字符输出流
GBK码表一个中文两个字节,UTF-8编码格式一个中文三个字节
字符流写数据
创建字符流输出对象
FileWriter(File file)
:给一个File对象构造一个FileWriter对象FileWriter(String fileName)
:给一个文件路径构造一个FileWriter对象
写数据 | 方法名 | 说明 | | —- | —- | |
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)
| 写一个字符串的一部分 |-
flush和close方法
| 方法名 | 说明 | | —- | —- | |
flush()
| 刷新流,还可以继续写数据 | |close()
| 关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据 |
字符流读取数据
- 创建字符流读取对象
FileReader(File file)
FileReader(String fileName)
- 读取数据
int read()
:读一个字符int read(char[] cbuf)
:读一个字符数组
-
字符缓冲输入流
创建字符缓冲输入流对象
BufferedReader(Reader in)
- 读取数据
int read()
读一个字符int read(char[])
读一个字符数组- mac遇到中文+
\r
字符的时候,一整行会被略过,应该在包含中文的字符串中使用\n
作为换行
-
字符缓冲输出流
创建字符缓冲输出流对象
BufferedWriter(Writer out)
- 写入数据
- 释放资源
字符缓冲流特有功能
BufferedWriter:
void newLine()
:写一行行分隔符,行分隔符字符串由系统属性定义
BufferedReader:
public String readLine()
:读一行文字。结果包含行的内容的字符串,不包括任何终止字符,如果流的结尾已经到达,则为null
IO流小结
其他流
转换流
转换流就是来进行字节流和字符流之间转换的
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
:为一段注释