1.java.io.File类的使用
1.1 File类的理解
- File 类及本章下的各种流,都定义在 java.io 包下。
- 一个 File 对象代表硬盘或网络中可能存在的一个文件或者文件目录(俗称文件夹),与平台无关。(体会万事万物皆对象)。
- File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
- File 对象可以作为参数传递给流的构造器。
- 想要在 Java 程序中表示一个真实存在的文件或目录,那么必须有一个 File 对象,但是Java 程序中的一个 File 对象,可能没有一个真实存在的文件或目录。
1.2 构造器
- public File(String pathname) :以 pathname 为路径创建 File 对象,可以是绝对路径或者相对路径,如果 pathname 是相对路径,则默认的当前路径在系统属性user.dir 中存储。
- 绝对路径:包括盘符在内的文件或文件目录的完整路径。
- 相对路径:相对于某一个文件目录来讲的相对位置。
- 在IDEA中,如果使用main方法,相对于当前的project来说。
- 如果使用单元测试方法,相对于当前的module来讲。
- public File(String parent, String child) :以 parent 为父路径,child 为子路径创建 File 对象。
- 参数1:一定是文件目录。
- 参数2:可以是文件或文件目录。
- public File(File parent, String child) :根据一个父 File 对象和子文件路径创建 File 对象。
- 参数1:一定是文件目录。
- 参数2:可以是文件或文件目录。
1.3 常用方法
1.3.1 获取文件和目录基本信息
- public String getName() :获取名称。
- public String getPath() :获取路径。
- public String getAbsolutePath():获取绝对路径。
- public File getAbsoluteFile():获取绝对路径表示的文件。
- public String getParent():获取上层文件目录路径。若无,返回 null。
- public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
- public long lastModified() :获取最后一次的修改时间,毫秒值。
- 如果 File 对象代表的文件或目录存在,则 File 对象实例初始化时,就会用硬盘中对应文件或目录的属性信息(例如,时间、类型等)为File 对象的属性赋值,否则除了路径和名称,File 对象的其他属性将会保留默认值。
1.3.2 列出目录的下一级
- public String[] list() :返回一个 String 数组,表示该 File 目录中的所有子文件或目录。
- public File[] listFiles() :返回一个 File 数组,表示该 File 目录中的所有的子文件或目录。
1.3.3 File类的重命名功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径。
1.3.4 判断功能的方法
- public boolean exists() :此 File 表示的文件或目录是否实际存在。
- public boolean isDirectory() :此 File 表示的是否为目录。
- public boolean isFile() :此 File 表示的是否为文件。
- public boolean canRead() :判断是否可读。
- public boolean canWrite() :判断是否可写。
- public boolean isHidden() :判断是否隐藏。
1.3.5 创建、删除功能
- public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false。
- public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
- public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建。
- public boolean delete() :删除文件或者文件夹 删除注意事项:
- Java 中的删除不经过回收站。
- 要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。
/*** 创建一个与hello.txt在相同文件目录下的另一个名为abc.txt的文件*/
public class Exer1 {public static void main(String[] args) {File file1 = new File("hello.txt");System.out.println(file1.getAbsolutePath());File file2 = new File(file1.getAbsoluteFile().getParent(), "abc.txt");System.out.println(file2.getAbsolutePath());}
}
2.IO流原理及流的分类
2.1 IO原理
I/O 流中的 I/O 是 Input/Output 的缩写, I/O 技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
- 输入 input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
- 输出 output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
2.2 流的分类
java.io 包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
- 按数据的流向不同分为:输入流和输出流。
- 输入流 :把数据从其他设备上读取到内存中的流。以 InputStream、Reader 结尾。
- 输出流 :把数据从内存中写出到其他设备上的流。以 OutputStream、Writer 结尾。
- 按操作数据单位的不同分为:字节流(8bit)和字符流(16bit)。
- 字节流 :以字节为单位,读写数据的流。以InputStream、OutputStream 结尾。
- 字符流 :以字符为单位,读写数据的流。以 Reader、Writer 结尾。
- 根据 IO 流的角色不同分为:节点流和处理流。
- 节点流:直接从数据源或目的地读写数据。
- 处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
3.流的API
Java 的 IO 流共涉及 40 多个类,实际上非常规则,都是从如下 4 个抽象基类派生的。
- 输入流:
- 字节流:InputStream。
- 字符流:Reader。
- 输出流:
- 字节流:OutputStream。
- 字符流:Writer。
3.1 常用的节点流
- 文件流: FileInputStream、FileOutputStrean、FileReader、FileWriter 。
- 字节/字符数组流: ByteArrayInputStream、ByteArrayOutputStream、CharArrayReader、CharArrayWriter。
- 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
3.2 常用的处理流
- 缓冲流:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter。
- 作用:增加缓冲功能,避免频繁读写硬盘,进而提升读写效率。
- 转换流:InputStreamReader、OutputStreamReader。
- 作用:实现字节流和字符流之间的转换。
- 对象流:ObjectInputStream、ObjectOutputStream。
- 作用:提供直接读写 Java 对象功能。
4.FileReader\FileWriter的使用
4.1 执行步骤
- 第1步:创建读取或写出File类的对象。
- 第2步:创建输入流或输出流。
- 第3步:具体的读入或写出的过程。
- 读入:read(char[] cbuffer)
- 写出:write(String str)/write(char[] cbuffer,0,len)
- 第4步:关闭流,避免内存泄漏。
@Testpublic void test2() {FileReader reader = null;try {//1.创建File对象,对应hello.txt文件File file = new File("C:\\Users\\22923\\Desktop\\Java\\Java SE\\src\\p177\\hello.txt");//2.创建输入的字符流,用于读取数据reader = new FileReader(file);//3.读取数据并显示到控制台上char[] cbuffer = new char[5];int len;while ((len = reader.read(cbuffer)) != -1) {for (int i = 0; i < len; i++) {System.out.print(cbuffer[i]);}}} catch (IOException e) {e.printStackTrace();} finally {//4.关闭流资源try {if (reader != null) {reader.close();}} catch (IOException e) {e.printStackTrace();}}}
@Testpublic void test3(){FileWriter fileWriter = null;try {//1.创建File对象,指明要写出的文件名称File file = new File("C:\\Users\\22923\\Desktop\\Java\\Java SE\\src\\p177\\info.txt");//2.创建输出流//覆盖文件使用的构造器fileWriter = new FileWriter(file);//在现有的文件基础上追加内容使用的构造器fileWriter = new FileWriter(file, false);//3.写出的具体过程fileWriter.write("hellowoeld123");} catch (IOException e) {e.printStackTrace();} finally {try {if (fileWriter != null)//4.流的关闭fileWriter.close();} catch (IOException e) {e.printStackTrace();}}}
4.2 注意点
- 涉及到流资源的关闭操作,所以出现异常时,需要使用try-catch-finally方式来处理异常。
- 对于输入流来说,要求File类的对象对应的物理磁盘上的文件必须存在,否则会报FileNotFoundException。
- 对于输出流来说,File类的对象对应物理磁盘上的文件可以不存在。
- 如果此文件不存在,则在输出的过程中自动创建此文件,并写出数据到此文件中。
- 如果此文件存在:
- 使用FileWriter(File file)或FileWriter(File file,false):在输出数据过程中,会新建同名的文件对现有的文件进行覆盖。
- 使用FileWriter(File file,true):在输出数据过程中,会在现有的文件的末尾追加写出的内容。
5.FileInputStream\FileOutputStream的使用
5.1 执行步骤
- 第1步:创建读取或写出File类的对象。
- 第2步:创建输入流或输出流。
- 第3步:具体的读入或写出的过程。
- 读入:read(byte[] buffer)
- 写出:write(byte[] buffer,0,len)
- 第4步:关闭流,避免内存泄漏。
/*** 需求:复制图片*/@Testpublic void test1() {FileInputStream inputStream = null;FileOutputStream outputStream = null;try {//1.创建相关的File类的对象File srcFile = new File("C:\\Users\\22923\\Desktop\\Java\\Java SE\\src\\p178\\2391e3248003e6ec91f355117ac020c.jpg");File destFile = new File("C:\\Users\\22923\\Desktop\\Java\\Java SE\\src\\p178\\1.jpg");//2.创建相关的字节流inputStream = new FileInputStream(srcFile);outputStream = new FileOutputStream(destFile);//3.数据的读入和写出byte[] buffer = new byte[1024];int len; //记录每次读入到buffer中字节的个数while ((len = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {try {//4.关闭流资源if (outputStream != null)outputStream.close();} catch (IOException e) {e.printStackTrace();}try {//4.关闭流资源if (inputStream != null)inputStream.close();} catch (IOException e) {e.printStackTrace();}}}
5.2 注意点
- 涉及到流资源的关闭操作,所以出现异常时,需要使用try-catch-finally方式来处理异常。
- 对于输入流来说,要求File类的对象对应的物理磁盘上的文件必须存在,否则会报FileNotFoundException。
- 对于输出流来说,File类的对象对应物理磁盘上的文件可以不存在。
- 如果此文件不存在,则在输出的过程中自动创建此文件,并写出数据到此文件中。
- 如果此文件存在:
- 使用FileWriter(File file)或FileWriter(File file,false):在输出数据过程中,会新建同名的文件对现有的文件进行覆盖。
- 使用FileWriter(File file,true):在输出数据过程中,会在现有的文件的末尾追加写出的内容。
- 字符流只能用来操作文本文件,不能用来处理非文本文件。
- 字节流通常用来处理非文本文件。但涉及到文本文件的复制操作也可以使用字节流。
5.3 说明
- 文本文件:txt、.java、.c 、.cpp、.py等
- 非文本文件:.doc、.xls、.jpg、.pdf、.mp3等
6.缓冲流
6.1 介绍
- BufferedInputStream
- BufferedOuputStream
- BufferedReader
- BufferedWriter
6.2 缓冲流的作用
提升文件读写的效率。
6.3 使用方法
6.3.1 处理非文本文件的字节流
- BufferedInputStream:read(byte[] buffer)
- BufferedOuputStream:write(byte[] buffer,0,len)
6.3.2 处理文本文件的字符流
- BufferedReader:read(char[] cBuffer)/readLine()
- BufferedWriter:write(char[] cBuffer,0,len)
6.4 执行步骤
- 创建File对象、流的对象(包括文件流、缓冲流)。
- 使用缓冲流实现读取数据或写出数据的过程:
- 读取:int read(char[] cbuf/byte[] buffer):每次将数据读入到cbuf/buffer数组中,并返回读入到数组中。
- 写出:
- void write(String str)/write(char[] cbuf):将str或cbuf写出到文件中。
- void write(byte[] buffer):将byte[]写出到文件中。
- 关闭资源。
/*** 使用BufferedInputStream\BufferedOutputStream复制文件*/@Testpublic void test1() {BufferedInputStream bufferedInputStream = null;BufferedOutputStream bufferedOutputStream = null;try {//1.创建相关的File类的对象File srcFile = new File("C:\\Users\\22923\\Desktop\\Java\\Java SE\\src\\p178\\2391e3248003e6ec91f355117ac020c.jpg");File destFile = new File("C:\\Users\\22923\\Desktop\\Java\\Java SE\\src\\p178\\1.jpg");//2.创建相关的字节流、缓冲流FileInputStream inputStream = new FileInputStream(srcFile);FileOutputStream outputStream = new FileOutputStream(destFile);bufferedInputStream = new BufferedInputStream(inputStream);bufferedOutputStream = new BufferedOutputStream(outputStream);//3.数据的读入和写出byte[] buffer = new byte[1024];int len; //记录每次读入到buffer中字节的个数while ((len = bufferedInputStream.read(buffer)) != -1) {bufferedOutputStream.write(buffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {//4.关闭外层缓冲流资源。//由于关闭外层流时会自动对内层流执行关闭操作,所以可以省略关闭内层流的操作try {if (bufferedOutputStream != null)bufferedOutputStream.close();} catch (IOException e) {e.printStackTrace();}try {if (bufferedInputStream != null)bufferedInputStream.close();} catch (IOException e) {e.printStackTrace();}}}
/*** 使用BufferedReader和BufferedWriter完成文本文件的复制*/@Testpublic void test2() {BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;try {File file1 = new File("hello.txt");File file2 = new File("hello——copy.txt");bufferedReader = new BufferedReader(new FileReader(file1));bufferedWriter = new BufferedWriter(new FileWriter(file2));String data;while ((data = bufferedReader.readLine()) != null){bufferedWriter.write(data);bufferedWriter.newLine(); //换行操作bufferedWriter.flush(); //刷新方法,每当调用此方法时,会主动将内存中数据写出到磁盘文件中}} catch (IOException e) {e.printStackTrace();} finally {try {if (bufferedReader != null)bufferedReader.close();} catch (IOException e) {e.printStackTrace();}try {if (bufferedWriter != null)bufferedWriter.close();} catch (IOException e) {e.printStackTrace();}}}
7.转换流
其作用是实现字节与字符之间的转换。
7.1 InputStreamReader与OutputStreamWriter
- InputStreamReader:将一个输入型的字节流转换为输入型的字符流。
- OutputStreamWriter:将一个输出型的字符流转换为输出型的字节流。
@Testpublic void test2() {FileOutputStream fos = null;OutputStreamWriter oos = null;try {File file1 = new File("hello.txt");File file2 = new File("hello_utf8.txt");FileInputStream fis = new FileInputStream(file1);InputStreamReader isr = new InputStreamReader(fis, "GBK");fos = new FileOutputStream(file2);oos = new OutputStreamWriter(fos, "utf8");char[] cBuffer = new char[1024];int len;while ((len = isr.read()) != -1) {oos.write(cBuffer, 0, len);}} catch (IOException e) {e.printStackTrace();} finally {try {if (oos != null) {oos.close();}} catch (IOException e) {e.printStackTrace();}try {if (fos != null) {fos.close();}} catch (IOException e) {e.printStackTrace();}}}
7.2 字符集
7.2.1 在存储文件中的字符
- ASCII:主要用来存储a、b、c等英文字符和1、2、3、常用的标点符号。
- iso-8859-1:了解,每个字符占用1个字节。向下兼容ascii。
- GBK:用来存储中文简体繁体、a、b、c等英文字符和1、2、3、常用的标点符号等字符。
- UTF-8:可以用来存储世界范围内主要的语言的所有的字符。使用1-4个不等的字节表示一个字符。中文字符使用3个字节存储的。向下兼容ascii,意味着英文字符、1、2、3、标点符号仍使用1个字节。
7.2.2 在内存中的字符
一个字符(char)占用2个字节。在内存中使用的字符集称为Unicode字符集。
8.数据流和对象流
8.1 数据流
- DataOutputstream:可以将内存中的基本数据类型的变量、String类型的变量写出到具体的文行中。
- DataInputStream:将文件中保存的数据还原为内存中的基本数据类型的变量、String类型的变量。
8.2 对象流
8.2.1 API
- ObjectInputStream
- ObjectOutputStream
8.2.2 作用
可以读写基本数据类型的变量和引用数据类型的变量。
8.3 对象的序列化机制
对象序列化机制允许把内存中的 Java 对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
8.3.1 序列化的意义
8.3.2 序列化过程
使用ObjectOutputStream实现,将内存中的Java对象保存在文件中或通过网络传输出去。
/*** 序列化过程** @throws IOException*/@Testpublic void test1() throws IOException {File file = new File("hello.txt");ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));oos.writeUTF("hello");oos.close();}
8.3.3 反序列化过程
使用ObjectInputStream实现,将文件中的数据或网络传输过来的数据还原为内存的Java对象。
/*** 反序列化过程** @throws IOException*/@Testpublic void test2() throws IOException {File file = new File("hello.txt");ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));String str1 = ois.readUTF();System.out.println(str1);ois.close();}
8.3.4 自定义类实现序列化机制的要求
- 自定义类需要实现接口:Serializable。
- 要求自定义类声明一个全局常量:static final long serialVersionUID=42234234L;用来唯一标识当前类。
- 如果不声明全局常量serialVersionUID,系统会自动声明一个针对于当前类的serialVersionUID。但是修改此类时,会导致serialVersionUID变化,进而导致反序列化时,出现InvaliedClassException异常。
- 要求自定义类的各个属性也必须可序列化:
- 对于基本数据类型的属性,默认可以序列化。
- 对于引用数据类型的属性,要求实现Serializable接口。
- 类中的属性如果声明为transient或static,则不会实现序列化。
9.其他流
9.1 标准输入、输出流
- System.in:标准的输入流,默认从键盘输入。
- System.out:标准的输出流,默认从显示器(控制台)输出。
- 通过调用如下方法,修改输入流和输出流的位置:
- setIn(InputStream is)
- setOut(PrintStream ps)
9.2 打印流
- 实现将基本数据类型的数据格式转化为字符串输出。
- 打印流:PrintStream 和 PrintWriter。
9.3 apache-common包的使用
IO 技术开发中,代码量很大,而且代码的重复率较高,为此 Apache 软件基金会,开发了 IO 技术的工具类 commonsIO,大大简化了 IO 开发。