IO概述 & 字节流 & 字节缓冲流
1. IO流
1.1概述
- IO:顾名思义,I就是Input输入,O就是Output输出
- 流:流是一种抽象概念,是对数据传输的总称。其本质是数据传输
1.2 应用
- IO流是用来处理设备间数据传输问题的,常应用于:
- 文件复制
- 文件上传
- 文件下载
1.3 分类
按数据的流向 | 按数据类型 |
---|---|
输入流:读数据 | 字节流 |
输出流:写数据 | 字符流 |
- 一般来说,我们说IO流的分类是按照数据类型来分的
- 那么在现实情况中,我们该如何选择字符流和字节流呢?
- 如果数据通过Window自带的记事本软件打开,我们还可以读懂里面的内容,就用字符流
- 否则就用字节流,在不知道如何选择字符流和字节流时,就使用字节流
1.4 使用场景
- 操作的是纯文本文件 --> 字符流
- 操作的是图片、视频、音频等二进制文件 --> 字节流
- 不确定文件类型 -->优先字节流 <-- 万能的流
2. 字节流
2.1 抽象基类
类名 | 说明 |
---|---|
InputStream | 这个抽象类是表示字节输入流的所有类的超类 |
OutputStream | 这个抽象类是表示字节输出流的所有类的超类 |
- 子类名称都是以其父类名作为子类名的后缀
2.2 FileOutputStream
2.2.1 概述
- 字节输出流,用于将数据写入File
- 创建字节输出流对象:
FileOutputStream (String name) :创建文件输出流以指定的名称写入文件
FileOutputStream fos = new FileOutputStream("iodemo\\demo.txt");
/*
做了三件事:
调用系统功能创建了文件
创建了字节输出流对象
让字节输出流对象指向创建好的文件
*/
2.2.2 步骤
-
创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
-
调用字节输出流对象的写数据方法
-
释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
2.2.3 方法
方法名 | 说明 |
---|---|
void write(int b) | 将指定的字节写入此文件输出流 一次写一个字节数据 |
void write(byte[] b) | 将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据 |
void write(byte[] b, int off, int len) | 将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据 |
2.2.4 代码示例
- 一次写一个字节
import java.io.FileOutputStream;
import java.io.IOException;
//一次写一个字节
public class Demo01 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("iodemo\\demo.txt");
//将指定的字节写入此文件输出流
// void write(int b)
fos.write(99);
fos.write(98);
//最后都要释放资源
fos.close();
}
}
// 结果在文件中写入 cb
- 一次写一个字节数据数组
import java.io.FileOutputStream;
import java.io.IOException;
//一次写入一个字节数组数据
public class Demo02 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("iodemo\\demo.txt");
//方法1
//创建一个字节数组
byte[] bys = {97,98,99};
fos.write(bys);
//方法2
///byte[] getBytes():返回字符串对应的字节数组
byte[] bys1 = "abc".getBytes();
fos.write(bys1);
//方法3
fos.write("abc".getBytes());
fos.close();
}
}
- 一次写一个字节数组的部分数据
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("iodemo\\demo.txt");
///byte[] getBytes():返回字符串对应的字节数组
byte[] bys1 = "abcde".getBytes();
fos.write(bys1,0, bys1.length); //写入abcde
//1,3 --> 第二个字节开始,写入三个字节 即从 b 开始
fos.write(bys1,1, 3); //写入bcd
fos.close();
}
}
2.2.5 注意事项
- 实现换行
系统 | 换行符 |
---|---|
windows | \r\n |
linux | \n |
mac | \r |
- 每一次运行,写入内容都会从开头开始,如何实现追加写入
- public FileOutputStream (String name,boolean append)
- 创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
//第二个参数一定要为true
FileOutputStream fos = new FileOutputStream("iodemo\\demo.txt",true);
///byte[] getBytes():返回字符串对应的字节数组
byte[] bys1 = "abcde".getBytes();
fos.write(bys1,0, bys1.length);
fos.write(bys1,1, 3);
fos.close();
}
}
2.3 FileInputStream
2.3.1 概述
- 从文件系统中的文件获取输入字节
- 创建字节输入流
//FileInputStream (String name)
FileInputStream fis = new FileInputStream("iodemo\\demo.txt");
2.3.2 步骤
-
创建字节输入流对象
-
调用字节输入流对象的读数据方法
-
释放资源
2.3.3 方法
方法名 | 说明 |
---|---|
public int read() | 从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止 |
public int read(byte[] b) | 从该输入流读取最多b.length 个字节的数据为字节数组 |
public int read(byte[] b,int off,int len) | 从该输入流读取高达len 字节的数据到字节数组,可读部分数据 |
2.3.4 代码示例
- 一个读一个字节数据
import java.io.FileInputStream;
import java.io.IOException;
public class Demo01 {
public static void main(String[] args) throws IOException {
//FileInputStream (String name)
FileInputStream fis = new FileInputStream("iodemo\\demo.txt");
//一次读一个字节数据
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
//文本中只有数据abc
System.out.println(fis.read());//如果abc以及被读完,没数据了,便会输出-1
System.out.println(fis.read());//-1
//释放资源
fis.close();
}
}
- 一次读一个字节数组
public class Demo02 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("iodemo\\demo.txt");
//一次读取一个字节数组
byte[] bys = new byte[3];
int len;
while ((len = fis.read(bys)) != -1){
System.out.println(new String(bys));
//通常会这么写,使得更加严谨
//System.out.println(new String(bys,0,len));
}
}
}
- 一次都一个字节数组的部分数据
import java.io.FileInputStream;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("iodemo\\demo.txt");
//一次读取一个字节数组的部分数据
byte[] bys = new byte[3];
int len;
while ((len = fis.read(bys)) != -1){
System.out.println(new String(bys,1,2));
}
}
}
2.4 案例
2.4.1 复制文本文件
- 一次读写一个字节数据
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
//一次读写一个字节数据
public class Test02 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("iodemo\\demo.txt");
FileOutputStream fos = new FileOutputStream("iodemo\\copy.txt");
int by;
while ((by = fis.read())!= -1){
fos.write(by);
}
fos.close();
fis.close();
}
}
- 一次读写一个字节数组数据
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
//一次读写一个字节数组数据
public class Test01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("iodemo\\demo.txt");
FileOutputStream fos = new FileOutputStream("iodemo\\copy.txt");
byte[] bys = new byte[1024]; //一般为1024 及其倍数
int len;
//fis.read(bys) --> 括号中的bys一定不能忘了,这里是将读取到的数据存入bys数组
//判断其不等于-1 是因为如果没有数据 读取就会输出-1 以此作为结束循环的条件
while ((len = fis.read(bys)) != -1){
fos.write(bys,0,len);
}
fos.close();
fis.close();
}
}
2.4.2 复制图片
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
//复制图片
public class Test03 {
public static void main(String[] args) throws IOException {
//创建字节输入 输出流对象
FileInputStream fis = new FileInputStream("E:\\Java_test\\java\\qinqin.gif");
FileOutputStream fos = new FileOutputStream("iodemo\\qinqin.gif");
//读取数据源文件
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys))!=-1){
//将读取的字节数组写入目的文件
fos.write(bys,0,len);
}
fis.close();
fos.close();
}
}
3. 字节缓冲流
3.1 概述
类名 | 说明 |
---|---|
BufferOutputStream | 该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用 |
BufferedInputStream | 创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节 |
3.2 构造方法
方法名 | 说明 |
---|---|
BufferedOutputStream(OutputStream out) | 创建字节缓冲输出流对象 |
BufferedInputStream(InputStream in) | 创建字节缓冲输入流对象 |
- 为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?
- 字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
3.3 代码示例
3.3.1 字节缓冲输出流
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo02 {
public static void main(String[] args) throws IOException {
//创建字节缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("iodemo\\demo.txt"));
//写入数据
bos.write("hello\r\n".getBytes());
//public void flush():刷新缓冲输出流
//如果没有使用这个方法,数据不会写入文件
bos.flush();
bos.write("world\r\n".getBytes());
bos.flush();
//释放资源
//当尚未关闭时, close方法的FilterOutputStream调用其flush方法,然后调用其底层输出流的close方法
bos.close();
/*
区别flush 和 close
二者都会刷新缓冲输出流
但是flush刷新完后可以继续添加内容
close刷新完后就会释放资源,无法再进行添加内容
*/
}
3.3.2 字节缓冲输入流
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class Demo01 {
public static void main(String[] args) throws IOException {
/* FileInputStream fis = new FileInputStream("iodemo\\demo.txt");
BufferedInputStream bis = new BufferedInputStream(fis);*/
//终极二合一 ,以后直接这么写
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("iodemo\\demo.txt"));
/* //一次读取一个字节数据
int by;
while ((by = bis.read())!=-1){
System.out.print((char) by); //注意这里使用的是print
}*/
//一次读取一个字节数组
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys))!= -1){
System.out.println(new String(bys,0,len));
}
//释放资源
bis.close();
}
}
3.4 案例
3.4.1 复制视频
- 四种方法
- 使用基本字节流一次读写一个字节数据
- 使用基本字节流一次读写一个字节数组
- 使用字节缓冲流一次读写一个字节数据
- 使用字节缓冲流一次读写一个字节数组(效率最高)
import java.io.*;
//这里只写使用字节缓冲流一次读写一个字节数组
public class Test01 {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
//创建字节缓冲输入 输出流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Java_test\\keai.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("iodemo\\keai.mp4"));
//使用字节缓冲流一次读写一个字节数组
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys))!=-1){
bos.write(bys,0,len);
}
//释放资源
bis.close();
bos.close();
long end = System.currentTimeMillis();
//利用System类下的currentTimeMillis()方法测试运行时间 可以用来比较四种方法耗时长短
System.out.println("耗时:" + (end-start) + "ms");
}
}