JavaIO流之字节流
IO的概述、分类、使用场景
IO流介绍
IO:输入/输出(Input/Output)
流:是一种抽象概念,是对数据传输的总称.也就是说数据在设备间的传输称为流,流的本质是数据传输
IO流就是用来处理设备间数据传输问题的.常见的应用: 文件复制; 文件上传; 文件下载
IO的数据传输可以看作是一种数据流动,以内存为参照物,进行数据读写。

IO流的分类
按照数据的流向
- 输入流:读数据
- 输出流:写数据
按照数据类型来分
字节流
- 字节输入流
- 字节输出流
字符流
- 字符输入流
- 字符输出流

IO流的使用场景
如果操作的是纯文本文件,优先使用字符流
如果操作的是图片、视频、音频等二进制文件,优先使用字节流
如果不确定文件类型,优先使用字节流。字节流是万能的流。
字节流
写入数据
字节流抽象基类
InputStream:这个抽象类是表示字节输入流的所有类的超类
OutputStream:这个抽象类是表示字节输出流的所有类的超类
子类名特点:子类名称都是以其父类名作为子类名的后缀
字节输出流
FileOutputStream(String name):创建文件输出流以指定的名称写入文件
使用字节输出流写数据的步骤
1. 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
2. 调用字节输出流对象的写数据方法
3. 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)

我们常用的是第一个和第四个构造,但其实他们的意思是一样的,都是将路径地址传递给FileOutputStream。
源码如下
public FileOutputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null, false);
}
如果传入的是字符串类型的,在代码底层也是会给他转换成File类型的对象。
实例代码
public class Demo01 {
public static void main(String[] args) throws IOException {
//1.创建字节输出流对象
/**
1.如果文件不存在,会帮我们创建
2.如果文件存在,会把文件清空
*/
//2种最常用的构造方式
FileOutputStream fos01 = new FileOutputStream("a.txt");
FileOutputStream fos02 = new FileOutputStream(new File("a.txt"));
//2.写数据
fos01.write(98);
//3.关闭此文件输出流并释放与此流相关联的任何系统资源
fos01.close();
}
}
上述代码使用了2种构造方法创建FileOutputStream对象。
字节流写数据的三种方式
| 方法名 | 说明 |
|---|---|
| void write(int b) | 将指定的字节写入此文件输出流 一次写一个字节数据 |
| void write(byte[] b) | 将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组数据 |
| void write(byte[] b, int off, int len) | 将 len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据(off是第几个索引开始,len是写几个) |
字节流写数据的两个小问题
-
字节流写数据如何实现换行
-
windows:\r\n
-
linux:\n
-
mac:\r
-
这里可以使用getBytes()方法,得到一个操作系统默认的编码格式的字节数组

-
字节流写数据如何实现追加写入
-
public FileOutputStream(String name,boolean append) 第3个构造
-
创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头(追加)
-
public class Demo02 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt",true);
for (int i = 0; i < 10; i++) {
fos.write("hello".getBytes());
fos.write("\r\n".getBytes());
}
fos.close();
}
}
关于字节流的异常处理
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
执行所有清除操作;
}
finally特点
-
被finally控制的语句一定会执行,除非JVM退出
Coding
public class FileOutputStreamDemo04 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("a.txt");
fos.write("hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
读取数据
-
字节输入流
-
FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
-
-
字节输入流读取数据的步骤
-
创建字节输入流对象
-
调用字节输入流对象的读数据方法
-
释放资源
-

基本样例
public class FileInputStreamDemo01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
int read = fis.read();
System.out.println((char)read);
fis.close();
}
}
字节流读多个字节
public class FileInputStreamDemo01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("myByteStream\\fos.txt");
int by;
// -1 表示文件读到了结束
// 不同操作系统可能会有不同!
while ((by=fis.read())!=-1) {
System.out.print((char)by);
}
fis.close();
}
}
案例-文件复制
-
案例需求
把“E:\itcast\窗里窗外.txt”复制到模块目录下的“窗里窗外.txt” (文件可以是任意文件)
-
实现步骤
-
复制文本文件,其实就把文本文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)
-
数据源:
E:\itcast\窗里窗外.txt --- 读数据 --- InputStream --- FileInputStream
-
目的地:
myByteStream\窗里窗外.txt --- 写数据 --- OutputStream --- FileOutputStream
-
Coding
public class CopyTxtDemo {
public static void main(String[] args) throws IOException {
//根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("E:\\itcast\\窗里窗外.txt");
//根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myByteStream\\窗里窗外.txt");
//读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
int by;
while ((by=fis.read())!=-1) {
fos.write(by);
}
//释放资源
fos.close();
fis.close();
}
}
案例改进方案-小数组拷贝
上述代码存在的效率问题,每次只能读取一个字节,一次一次的传递导致效率十分低下!
措施

Coding
package IO流.FileOutputStream类;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException, IOException {
//根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("E:\\itcast\\窗里窗外.txt");
//根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("myByteStream\\窗里窗外.txt");
byte [] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}
}
小数组拷贝的原理分析
我们可以举一个例子来说明,假设byte数组的大小是2,数据源有abcde,则每次读入两个字符,这里第一次读入的是ab

第二次读入是cd,将覆盖字符数组原来的值。

最后一次,因为只剩下一个e,所以读入后字符数组中的值为ed,len长度为1,但是不影响,在write(bytes,0,len),表示输出长度为len = 1 的。


浙公网安备 33010602011771号