一、IO流结构
IO流,大的分类分为字节流和字符流。字节流,传输的最小单位是字节,可以传输所有类型的文件;字符流,传输的最小单位是字符,在传输文本文件的场景中可以避免乱码问题。
使用IO中的任何一种实现类时,都是“三步走”,即
(1)创建流对象,关联文件
(2)读取/写入数据
(3)关闭流,释放资源
二、字节流使用
1、读取/写入:单个字节的读写
// 1.创建流对象,关联文件
FileInputStream fis = new FileInputStream("javaFile.txt");
FileOutputStream fos = new FileOutputStream("javaFileOut.txt");
// 2.1读取/写入一个字节,这里的read是可代表数据的码值,读取失败返回-1
int read = fis.read();
fos.write(read);
// 3.关闭流,释放资源
fis.close();
fos.close();
2、使用循环,读取文件的所有内容
// 1.创建流对象,关联文件
FileInputStream fis = new FileInputStream("javaFile.txt");
FileOutputStream fos = new FileOutputStream("javaFileOut.txt");
// 2.2 使用循环,读取文件的所有内容,read = -1则说明数据读完了
int read;
while ((read = fis.read()) != -1){
fos.write(read);
}
// 3.关闭流,释放资源
fis.close();
fos.close();
3、设计一个字节数组,指定一次读取的大小,一般是1024Byte
需要注意的是,如果写入时没有设置限定范围,表示每次写入都是1024Byte,但如果最后一次读取不足于1024Byte,则会把上一次bytes数组中超出本次读取内容的部分,再写入到文件中。 这会导致写入的数据在末尾会有一小部分内容重复
// 1.创建流对象,关联文件
FileInputStream fis = new FileInputStream("javaFile.txt");
FileOutputStream fos = new FileOutputStream("javaFileOut.txt");
// 2.3 使用循环,读取文件的所有内容
byte[] bytes = new byte[1024];
int len;
// 这里注意,fis.read()读取时需要加上字节数组;len返回的是fis.read()读取有效内容的字节数
while ((len = fis.read(bytes)) != -1) {
// for.wirte()的三个参数,第一个是读取出来的字节数组,里面存储的是可代表数据内容的码值;后面两个是指写入bytes中的范围,指bytes[0-len)
fos.write(bytes, 0, len);
}
// 3.关闭流,释放资源
fis.close();
fos.close();
4、另外
(1)在创建输出流对象时,需要注意路径要写到“文件名”,不能写到目录级,否则会报“拒绝访问”的错误
// 输出流对象的文件路径,要写到文件名级,不能写到目录级,会报错
FileOutputStream fos = new FileOutputStream("superDir");
(2)输出流对象路径,没有文件会先创建一个新的空文件,如果已有文件,会清空文件内容。如果是追加操作,需要在创建对象时设置true
//参数2,表示是否追加内容
FileOutputStream fos = new FileOutputStream("javaFileOut.txt", true);
(3)在JDK1.7以后,凡实现了AutoCloseable接口的类,可以在try()小括号内创建流对象。这样程序结束后,会自动关闭流,不需要再手动关闭
try (
// 1.创建流对象,关联文件(将流对象创建放在try()小括号内)
FileInputStream fis = new FileInputStream("javaFile.txt");
FileOutputStream fos = new FileOutputStream("javaFileOut.txt", true)
) {
// 2.3 使用循环,读取文件的所有内容
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
// 3.不需要手动关闭流,这两行代码可去掉
//fis.close();
//fos.close();
} catch (IOException e) {
e.printStackTrace();
}
三、字符流使用
1、获取字符的码值
因为字节流传输的最小单位是字节,所以如果在读取/写入不全(3个字节表示一个汉字),或者读取和写入的字符集不同时(不统字符集表示字符的字节数不同),字符就会乱码。这时字符流的价值就体现出来了。
String s = "我爱中国";
// 使用getBytes()获取字符串的码值,这里使用的是UTF-8编码,三个码值表示一个字符,故输出9个码值
byte[] bytes = s.getBytes();
System.out.println(Arrays.toString(bytes));
2、使用字符流读取/写入数据
值得一说的是,字符流也可以像字节流那样读取/写入单个字符
try (
// 1.创建流对象,关联文件
FileReader fr = new FileReader("javaFile.txt");
FileWriter fw = new FileWriter("javaFileOut.txt")
) {
// 2.读取/写入
// 注意这里创建的是字符数组
char[] chars = new char[1024];
int len;
while (((len = fr.read(chars)) != -1)) {
// 用传入字符数组的方式创建字符串,注意需要限定有效的字符长度
String s = new String(chars, 0, len);
fw.write(s);
}
// 3.关闭流,释放资源,自动释放
} catch (IOException e) {
e.printStackTrace();
}
四、Buffered流
Buffered是一种自带缓存(8K)的高级流,IO的四种基本实现流,均有各自的Buffered流,在创建对应的Buffered时,需要传入基本实现流为参数。这里以字节流的Buffered为例,复制一个视频,测试Buffered流的效率
1.Buffered流使用,以字节流为例
// 1.创建流对象,关联文件(Buffered流需要以基础流实现类对象为参数)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("javaFile.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("javaFileOut.txt"));
// 2.读取/写入
byte[] bytes = new byte[1024];
int len;
while (((len = bis.read(bytes)) != -1)) {
bos.write(bytes, 0, len);
}
// 3.关闭流,释放资源,手动关闭
bis.close();
bos.close();
2.用基础字节流和高速缓存流拷贝视频,对比效率
import java.io.*;
public class EssayTest3 {
public static void main(String[] args) throws IOException {
String inputPath = "C:\\Users\\10765\\Desktop\\Test\\video.mp4";
String outBasicPath = "C:\\Users\\10765\\Desktop\\Test\\basic\\video.mp4";
String outBufferedPath = "C:\\Users\\10765\\Desktop\\Test\\buffered\\video.mp4";
System.out.println("基础字节流拷贝时长:" + basic(inputPath,outBasicPath) + "ms");
System.out.println("高速缓存字节流拷贝时长:" + buffered(inputPath,outBufferedPath) + "ms");
}
public static long basic(String inputPath, String outPath) throws IOException {
FileInputStream fis = new FileInputStream(inputPath);
FileOutputStream fos = new FileOutputStream(outPath);
long start = System.currentTimeMillis();
byte[] bytes = new byte[1024];
int len;
while (((len = fis.read(bytes)) != -1)) {
fos.write(bytes, 0, len);
}
fis.close();
fos.close();
long end = System.currentTimeMillis();
return end - start;
}
public static long buffered(String inputPath, String outPath) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputPath));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outPath));
long start = System.currentTimeMillis();
byte[] bytes = new byte[1024];
int len;
while (((len = bis.read(bytes)) != -1)) {
bos.write(bytes, 0, len);
}
bis.close();
bos.close();
long end = System.currentTimeMillis();
return end - start;
}
}