IO流之 File 类和字节流
文章目录
- 一、File 类
- 1. 概述
- 2. 创建功能
- 3. 删除功能
- 4. 判断和获取功能
- 5. 递归策略
- 5.1 递归求阶乘
- 5.2 遍历目录
- 二、字节流
- 1. IO 流概述
- 2. 字节流写数据
- 2.1 三种方式
- 2.2 换行及追加
- 2.3 加异常处理
- 3. 字节流读数据
- 3.1 一次读一个字节
- 3.2 一次读一个字节数组
- 3.3 复制文本文件
- 3.4 复制图片
- 3.5 字节缓冲流
一、File 类
1. 概述
File:它是文件和目录路径名的抽象表示。
文件和目录是可以通过 File 封装成对象的。对于 File 而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已,它是可以存在的,也可以是不存在的,将来是要通过具体的操作把这个路径的内容转换为具体存在的。
//Test.java
package com.zxe;
import java.io.File;
public class Test {
public static void main(String[] args) {
//1.方式一
File f1 = new File("F:\\tyut\\java.txt");
System.out.println(f1);
//2.方式二
File f2 = new File("F:\\tyut", "java.txt");
System.out.println(f2);
//3.方式三
File f3 = new File("F:\\tyut");
File f4 = new File(f3, "java.txt");
System.out.println(f4);
}
}
这三个构造方法做的是同样的事情吗,File 起指引路径的作用!
2. 创建功能
//Test.java
package com.zxe;
import java.io.File;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
File f1 = new File("F:\\tyut");
System.out.println(f1.mkdir());
File f2 = new File("F:\\tyut\\java.txt");
System.out.println(f2.createNewFile());
}
}
注意:
① 创建文件or目录时,如果该文件or目录已经存在,就不再创建,并返回 false;
② 不能根据 File 里面的路径名来判断创建的是文件还是目录,应该根据调用的方法来判断。
3. 删除功能
在此之前,先看一下绝对路径和相对路径吧!
绝对路径和相对路径的区别:
① 绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件,例如 F:\tyut\java.txt;
② 相对路径:必须使用取自其他路径名的信息进行解释,例如 myFile\java.txt。
//1.在当前模块目录下创建文件
File f1 = new File("idea_test\\zxe.txt");
System.out.println(f1.createNewFile());
//删除当前模块目录下的某文件
File f1 = new File("idea_test\\zxe.txt");
System.out.println(f1.delete());
要想删除一个目录,就必须先删除该目录下的所有内容!
4. 判断和获取功能
//Test.java
package com.zxe;
import java.io.File;
public class Test {
public static void main(String[] args) {
File f1 = new File("idea_test//play");
String[] strArray = f1.list();
for (String str : strArray) {
System.out.println(str);
}
System.out.println("----------------");
File[] fileArray = f1.listFiles();
for (File file : fileArray) {
if (file.isFile()) {
System.out.println(file.getName());
}
}
}
}
5. 递归策略
递归概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象。
(1)递归解决问题的思路:
① 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解;
② 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算。
(2)递归解决问题要找到两个内容:
① 递归出口,否则会出现内存溢出;
② 递归规则,与原问题相似的规模较小的问题。
5.1 递归求阶乘
需求:用递归求 5 的阶乘,并把结果输出在控制台。
//Test.java
package com.zxe;
public class Test {
public static void main(String[] args) {
int result = jc(5);
System.out.println(result);
}
public static int jc(int n) {
if (n == 1) {
return 1;
} else {
return n * jc(n - 1);
}
}
}
5.2 遍历目录
需求:给定一个路径,请通过递归的方法来遍历该目录下的所有内容,并把所有文件的绝对路径输出在控制台。
思路:
① 根据给定的路径创建一个 File 对象;
② 定义一个方法,用于获取给定目录下的所有内容,参数为第一步创建的 File 对象;
③ 获取给定的 File 目录下所有的文件或者目录的 File 数组;
④ 遍历该 File 数组,得到每一个 File 对象;
⑤ 判断该 File 对象是否是目录,如果是目录就递归调用,不是目录就获取绝对路径输出在控制台;
⑥ 调用方法。
//Test.java
package com.zxe;
import java.io.File;
public class Test {
public static void main(String[] args) {
File srcFile = new File("F:\\tyut");
getAllFilePath(srcFile);
}
public static void getAllFilePath(File srcFile) {
File[] fileArray = srcFile.listFiles();
if (fileArray != null) {
for (File file : fileArray) {
if (file.isDirectory()) {
getAllFilePath(file);
} else {
System.out.println(file.getAbsolutePath());
}
}
}
}
}
二、字节流
1. IO 流概述
IO 指的就是输入 / 输出。
流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质就是数据传输。
IO 流就是用来处理设备间数据传输问题的。
常见的应用:文件复制、文件上传、文件下载。
IO 流按照数据类型可以分为字节流和字符流。那么这两种流都在什么情况下使用呢?
如果数据通过 Window 自带的记事本软件打开,我们还可以读懂里面的内容,就使用字符流,否则使用字节流。如果你不知道该使用哪种类型的流,就使用字节流,因为字节流是万能的流。
2. 字节流写数据
InputStream:这个抽象类是表示字节输入流的所有类的超类;
OutputStream:这个抽象类是表示字节输出流的所有类的超类。
子类名都是以其父类名作为后缀的!
FileOutputStream:文件输出流用于将数据写入 File。
//Test.java
package com.zxe;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("idea_test\\myByteStream");
fos.write(97);
fos.close();
}
}
(1)创建字节输出流对象,做了三件事情:
① 调用系统功能创建了文件;
② 创建了字节输出流对象;
③ 让字节输出流对象指向创建好的文件。
(2)最后都要释放资源,使用 close() 方法关闭此文件输出流并释放与此流相关联的任何系统资源。
如果没有该文件,则系统会自动创建文件,所有和 IO 操作相关的内容,最后都要释放资源!
2.1 三种方式
//Test.java
package com.zxe;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("idea_test\\myByteStream");
byte[] by = {97, 98, 99, 100};
fos.write(by);
byte[] by2 = "abcde".getBytes();
fos.write(by2);
fos.close();
}
}
write() 方法不能直接写入字符串,我们可以通过 String 类中的 getBytes() 方法,根据字符串得到它的字节数组,从而实现字符串的写入!
2.2 换行及追加
(1)字节流写数据如何实现换行?
不同系统对换行符号的识别是不同的:
① window:\r\n
② Linux:\n
③ mac:\r
(2)字节流写数据如何实现追加?
FileOutputStream(String name, boolean append)
创建文件输出流以指定的名称写入文件,如果第二个参数为 true,则字节将写入文件的末尾而不是开头。
//Test.java
package com.zxe;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("idea_test\\myByteStream", true);
byte[] by = "你好哇!\r\n".getBytes();
fos.write(by);
fos.close();
}
}
第二个参数不写的时候,默认用新数据替换旧数据,如果只是追加不替换,让第二个参数为 true 即可!
2.3 加异常处理
finally:在异常处理时提供 finally 块来执行所有的清除操作。比如 IO 流中的资源释放。
特点:被 finally 控制的语句一定会执行,除非 JVM 退出。
try {
//可能出现的异常
} catch(IOException e) {
//异常的处理代码
} finally {
//执行所有清除操作
}
//Test.java
package com.zxe;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
new FileOutputStream("idea_test\\myByteStream", true);
byte[] by = "你好哇!\r\n".getBytes();
fos.write(by);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3. 字节流读数据
3.1 一次读一个字节
FileInputStream:从文件系统中的文件获取输入字节。
FileInputStream fis = new FileInputStream("idea_test\\myByteStream");
int by;
while ((by = fis.read()) != -1) {
System.out.print((char) by);
}
如果文件读到末尾,返回值为 -1!
3.2 一次读一个字节数组
//Test.java
package com.zxe;
import java.io.FileInputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("idea_test\\myByteStream.txt");
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
String result = new String(bys, 0, len);
System.out.println(result);
}
fis.close();
}
}
① \r\n 换行占两个字节;
② 字节数组的长度我们一般定为 1024 及其整数倍;
③ len 返回的并不是字节数组的长度,而是实际读取的数据的个数,当读到文本末尾的时候,len 可能就会发生变化;
④ new String(bys, 0, len) 读几个字节转几个字符串,没有读到的不转,文本末尾没有数据就没必要再转了,保证效率。
String 类中提供了一个构造方法 new String(),它可以将一个字节数组直接变成一个字符串!
3.3 复制文本文件
复制文本文件,其实就是把文本文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)。
//Test.java
package com.zxe;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//将 F:\tyut\head.txt 文件的内容复制到 idea_test\myByteStream.txt
FileInputStream fos = new FileInputStream("F:\\tyut\\head.txt");
FileOutputStream fis = new FileOutputStream("idea_test\\myByteStream.txt");
int byread;
while ((byread = fos.read()) != -1) {
fis.write(byread);
}
fos.close();
fis.close();
}
}
从文件中直接读取出来的内容是数字形式,写入文件时参数的内容也是数字形式,但写进去之后会变成相应的字符形式 abcd!
3.4 复制图片
FileInputStream fis = new FileInputStream("F:\\tyut\\xn.jpg");
FileOutputStream fos = new FileOutputStream("idea_test\\xiaoyang.jpg");
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
fos.close();
fis.close();
3.5 字节缓冲流
① BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用;
② BufferedInputStream:将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。
字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作!
//Test.java
package com.zxe;
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("idea_test//myBufferedStream.txt"));
bos.write("hello\r\n".getBytes());
bos.write("world".getBytes());
bos.close();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("idea_test//myBufferedStream.txt"));
//一次读取一个字节数据
int by;
while ((by = bis.read()) != -1) {
System.out.print((char) by);
}
//一次读取一个字节数组数据
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys)) != -1) {
System.out.println(new String(bys, 0, len));
}
bis.close();
}
}
字节缓冲流使得读写速度加快!