目录
- 1、IO流介绍
- 2、IO流体系结构
- 2.1 FileOutputStream 字节输出流
- (1)字节输出流操作方法:
- (2) 标准的关流代码:
- 2.2 FileInputStream 字节输入流
- (1)字节输入流操作方法:
- 2.3 练习
- 3、字节缓冲流
- 3.1 字节缓冲流的使用:
- 3.2 字节缓冲流的读写过程:
- 3.3 案例:
- 第一种:
- 第二种:
- 第三种:
- 第四种:
1、IO流介绍
I
就是input
,即输入:从数据源读取数据。
O
就是output
,即输出:向数据目标写入数据。
2、IO流体系结构
2.1 FileOutputStream 字节输出流
(1)字节输出流操作方法:
package com.itheima.stream.output;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class StreamOutputDemo1 {
/**
* 字节流写出数据:
* 构造方法:
* 1、public FileOutputStream(String name): 输出流关联文件,文件路径以字符串形式给出
* 2、public FileOutputStream(File file): 输出流关联文件,文件路径以File形式给出
*
* 成员方法:
* 1、public void write(int i): 写出一个字节
* 2、public void write(byte[] bys): 写出一个字节数组
* 细节:
* 输出流关联文件,文件如果不存在:会自动创建出来
* 如果文件存在:会清空现有的内容,然后再进行写入操作
* 如果就想要追加,那再FileOutputStream构造方法里的第二个参数传true即可
*/
public static void main(String[] args) throws IOException {
//1、创建字节输出流对象,关联文件,第二个参数传true,表示文件内容追加写入,而非清空再写入
FileOutputStream fos = new FileOutputStream("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\A.txt", true);
//2、写出数据
fos.write(97);
fos.write(98);
fos.write(99);
byte[] bytes = {97, 98, 99};
//2.1 输出一个字节数组
fos.write(bytes);
//2.2 写出字节数组的一部分根据索引写入,如从1索引开始,到2索引结束
fos.write(bytes, 1, 2);
//2.3 如果要写出字符串,只需要调用字符串中的bytes方法即可,如下:
fos.write("我想要变富裕".getBytes());
//3、流对象使用完毕后需关闭
fos.close();
}
}
(2) 标准的关流代码:
上述代码中,我们将字节输出流的异常抛到上层调用方法里了,但一般我们需要使用
try-catch
来处理,下面来介绍:
package com.itheima.stream.output;
import java.io.FileOutputStream;
import java.io.IOException;
public class StreamOutputDemo2 {
/**
* IO流的异常处理方式:jdk7版本之前
*/
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("D:\\A.txt");
fos.write("xxx".getBytes());
System.out.println(10/0);//在关闭流之前如果有其他异常,那当前的try-catch就捕获不到了,因此关闭流放在finally里
}catch (IOException e){
e.printStackTrace();
}finally {
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
上面是jdk7之前的写法,写法很繁琐,所以后续的jdk7、jdk8使用了新的写法,如下:
package com.itheima.stream.output;
import java.io.FileOutputStream;
import java.io.IOException;
public class StreamOutputDemo3 {
/**
* IO流的异常处理方式:jdk7版本之后
*/
public static void main(String[] args) {
//只需要将需要关闭文件流的代码放入try的括号中即可,在运行过程中会自动调用close方法
try (FileOutputStream fos = new FileOutputStream("D:\\A.txt")) {
fos.write("xxx".getBytes());
}catch (IOException e){
throw new RuntimeException("我报错了。。。");
}
}
}
2.2 FileInputStream 字节输入流
(1)字节输入流操作方法:
package com.itheima.stream.input;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class StreamInputDemo1 {
/**
* 字节流读取数据
* 1、public int read():读取单个字节
* - 如果的读取完了,那么就会返回 -1
*
* 2、public int read(byte[] bys):读取一个字节数组
* - 将读取到的字节,存入数组容器,返回读取到的有效字节个数
*/
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\A.txt")) {//try()会自动调用fis.close()方法,切记切记
//1、fis.read()方法每次读取一个字节,如果的读取完了,那么就会返回-1,因此我们可以使用-1来判断是不是读取完了
int i;
while ((i = fis.read()) != -1){
System.out.println(i);
}
//2、fis.read(byte[] bys)方法将读取到的字节,存入数组容器,返回读取到的有效字节个数
//2.1 准备一个数组,用于装字节
byte[] bys = new byte[2];
//2.2 读取数据,并返回有效字节数
int len = fis.read(bys);
System.out.println(Arrays.toString(bys));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
如果定义的数组长单不够,继续读取的话,会出现如下效果:
可发现,最后两次有残留数据,如倒数第二行
[101,100]
中的100
,倒数第一行的[101,100]
。如何解决这个问题呢?
答:将读取出来的数据转换为字符串,使用下面的方法做转换:
因此,改造上述代码如下:
package com.itheima.stream.input;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class StreamInputDemo1 {
/**
* 字节流读取数据
* 1、public int read():读取单个字节
* - 如果的读取完了,那么就会返回 -1
*
* 2、public int read(byte[] bys):读取一个字节数组
* - 将读取到的字节,存入数组容器,返回读取到的有效字节个数
*/
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\A.txt")) {//try()会自动调用fis.close()方法,切记切记
//1、fis.read()方法每次读取一个字节,如果的读取完了,那么就会返回-1,因此我们可以使用-1来判断是不是读取完了
// int i;
// while ((i = fis.read()) != -1){
// System.out.println(i);
// }
//2、fis.read(byte[] bys)方法将读取到的字节,存入数组容器,返回读取到的有效字节个数
//2.1 准备一个数组,用于装字节
byte[] bys = new byte[2];
//2.2 循环读取数据,并转换成字符串
int len;
while ((len = fis.read(bys)) != -1){
System.out.print(new String(bys, 0, len));//每次将有效长度的数组转换为字符串
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
2.3 练习
package com.itheima.stream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileStreamTest1 {
public static void main(String[] args) {
try(FileInputStream fis = new FileInputStream("D:\\嘿嘿.png");
FileOutputStream fos = new FileOutputStream("E:\\嘿嘿.png")){//会自动调用close方法的
//1、读入字节流
int len;//每次读取的长度
byte[] bys = new byte[1024];//每次读取的字节放在此数组
while ((len = fis.read(bys)) != -1){
//2、将每次读取的,写入字节流
fos.write(bys, 0, len);
}
}catch (IOException e){
throw new RuntimeException("读取或输出字节流报错" + e.getMessage());
}
}
}
3、字节缓冲流
上面我们为了提高读取效率,定义了一个数组,其实java中已经帮我们实现了这个功能,这就是字节缓冲流存在的意义,下面看怎么用的。
3.1 字节缓冲流的使用:
package com.itheima.stream;
import java.io.*;
public class BufferedStreamDemo1 {
/**
* 字节缓冲流在源代码中内置了字节数组,可以提高读写效率
* 字节缓冲输入流: public BufferedInputStream(InputStream in)
* 字节缓冲输出流: public BufferedOutputStream(OutputStream out)
*/
public static void main(String[] args) throws IOException {
mothed1();//抛出异常写法
mothed2();//捕获异常写法
}
/**
* 将异常传给调用他的地方
*/
private static void mothed1() throws IOException {
//1、创建字节缓冲区输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\嘿嘿.png"));
//2、创建字节缓冲区输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\嘿嘿.png"));
//3、读取并写入
int len;
while ((len = bis.read()) != -1) {
bos.write(len);//写入到bos指定的地方
}
//4、关闭流,注意:只需要关闭缓冲输入输出流即可
bis.close();
bos.close();
}
/**
* try-catch捕获异常
*/
private static void mothed2() {
//关闭流操作,自动在try()里已经实现了
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\嘿嘿.png"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\嘿嘿.png"))) {
int len;
while ((len = bis.read()) != -1){
bos.write(len);//写入到bos指定的地方
}
} catch (IOException e) {
throw new RuntimeException("报错了" + e.getMessage());
}
}
}
3.2 字节缓冲流的读写过程:
3.3 案例:
package com.itheima.stream;
import java.io.*;
public class BufferedStreamDemo {
/**
* 四种拷贝方法:
* 1、普通流单个字节拷贝
* 2、普通流 + 自定义数组拷贝
* 3、缓冲流单个字节拷贝
* 4、缓冲流 + 自定义数组拷贝
*/
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
// method1(); //24386000
// method2(); //4208
// method3(); //24386
method4(); //3293
long end = System.currentTimeMillis();
System.out.println(end - start);
}
/**
* 1、普通流单个字节拷贝
*/
public static void method1() throws IOException {
//1、创建字节输入流
FileInputStream fis = new FileInputStream("D:\\英雄联盟.mp4");
//2、创建字节输出流
FileOutputStream fos = new FileOutputStream("E:\\英雄联盟.mp4");
//3、读取:每次读一个并写入一个
int len;
while ((len = fis.read()) != -1){
fos.write(len);
}
//4、关闭流
fis.close();
fos.close();
}
/**
* 2、普通流 + 自定义数组拷贝
*/
public static void method2() throws IOException {
//1、创建字节输入流
FileInputStream fis = new FileInputStream("D:\\英雄联盟.mp4");
//2、创建字节输出流
FileOutputStream fos = new FileOutputStream("E:\\英雄联盟.mp4");
//3、读取:每次读一个数组的内容,并写入一个数组的内容
byte[] bys = new byte[4096];
int len;
while ((len = fis.read(bys)) != -1){
fos.write(bys, 0, len);
}
//4、关闭流
fis.close();
fos.close();
}
/**
* 3、缓冲流单个字节拷贝
*/
public static void method3() throws IOException {
//1、创建缓冲字节输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\英雄联盟.mp4"));
//2、创建缓冲字节输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\英雄联盟.mp4"));
//3、读取:
int len;
while ((len = bis.read()) != -1){
bos.write(len);
}
//4、关闭流
bis.close();
bos.close();
}
/**
* 4、缓冲流 + 自定义数组拷贝
*/
public static void method4() throws IOException {
//1、创建缓冲字节输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\英雄联盟.mp4"));
//2、创建缓冲字节输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\英雄联盟.mp4"));
//3、读取:每次读一个数组的内容到缓冲内存中,并写入一个数组的内容到硬盘
byte[] bys = new byte[4096];
int len;
while ((len = bis.read(bys)) != -1){
bos.write(bys, 0, len);
}
//4、关闭流
bis.close();
bos.close();
}
}
第一种:
第二种:
第三种:
上述解释:
先从硬盘先直接读取了8192个字节,放入缓冲输入流的数组内存中,然后再一个一个地取出放入缓冲输出流的数组内存中,最后一次性写出8192个字节到硬盘。那这样为啥比一个一个的快呢?
答:因为一个一个的取是在内存中完成的,因此比方法一要快的多。
第四种:
那这四种方法在实际使用时怎么选择呢?
答:一般选择二或者四,因为这两种效率差不多,并且二代码更简洁,所以更推荐二。