1 FileInputStream
2 FileOutputStream
3 BufferedInputStream
4 BufferedOutputStream
1 FileInputStream
-
字节流的概念:字节流读取的都是文件中的二进制数据,读取到的二进制数据不会经过任何的处理。
-
InputStream 是所有输入字节流的基类(抽象类)
-
FileInputStream 是读取文件数据的输入字节流
使用FileInputStream读取文件数据的步骤:
- 找到目标文件
- 建立数据的输入通道
- 读取文件中的数据
- 关闭资源
方法1和方法3已经被淘汰了,推荐使用方法4,理论上效率更高。
public class Demo1 {
public static void main(String[] args) throws IOException {
readTest4();
}
// 方式4:使用缓冲数组配合循环读取。
public static void readTest4() throws IOException {
// 1.找到目标文件
File file = new File("G:\\a.txt");
// 2.建立数据的输入通道
FileInputStream fileInputStream = new FileInputStream(file);
// 3.读取文件中的数据
byte[] buf = new byte[4]; // 缓冲数组的长度一般是1024的倍数,符合计算机的处理单位。理论上缓冲数组越大,效率越高。
int length = 0; // 保存每次读取到的字节数
while((length = fileInputStream.read(buf)) != -1) { // read方法如果读取到文件的末尾,那么就会返回-1表示
System.out.print(new String(buf, 0, length));
}
// 4.关闭资源
fileInputStream.close();
}
// 方式3:使用缓冲数组读取 缺点:无法完整读取一个文件的数据。
public static void readTest3() throws IOException {
// 1.找到目标文件
File file = new File("G:\\a.txt");
// 2.建立数据的输入通道
FileInputStream fileInputStream = new FileInputStream(file);
// 3.读取文件中的数据
byte[] buf = new byte[1024]; // 相当于超市里的购物车
int length = fileInputStream.read(buf); // 如果使用read读取数据传入字节数组,那么数据是存储到字节数组中的,而这时read方法返回值表示本次读取了几个字节数据到字节数组中。
System.out.println(length);
String content = new String(buf, 0, length); // 使用字节数组构建字符串
System.out.println("内容:" + content);
// 4.关闭资源
fileInputStream.close();
}
// 方式2:使用循环读取文件的数据。
public static void readTest2() throws IOException {
long startTime = System.currentTimeMillis();
// 1.找到目标文件
File file = new File("G:\\a.txt");
// 2.建立数据的输入通道
FileInputStream fileInputStream = new FileInputStream(file);
// 3.读取文件中的数据
int content = 0; // 声明该变量用于存储读取到的数据
while((content = fileInputStream.read()) != -1) { // read方法如果读取到文件的末尾,那么就会返回-1表示
System.out.print((char)content);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
// 读取方式1的缺陷:无法将一个文件的数据完整读取。
public static void readTest1() throws IOException {
// 1.找到目标文件
File file = new File("G:\\a.txt");
// 2.建立数据的输入通道
FileInputStream fileInputStream = new FileInputStream(file);
// 3.读取文件中的数据
int content = fileInputStream.read(); // read() 读取一个字节的数据,把读取的数据返回。
System.out.println("读到的内容是:" + (char)content); // a
// 4.关闭资源 实际上就是释放资源
fileInputStream.close();
}
}
- 问题1:读取完一个文件的数据时,不关闭资源有什么影响?
资源一旦使用完毕应该马上释放,否则其他的程序无法对该资源文件进行操作。 - 问题2:方式4中,当缓冲数组的长度为4时,就会对文件中的数据每4个字节一读取。文件中的4个字节存储到缓冲数组后,那么下一次存储的方式是怎样的?
是以覆盖的方式存储的。假如文件中的数据为:aaaabbb,构建字符串时若没有指定长度的话,读取到的完整数据就会是:aaaabbba
2 FileOutputStream
- OutputStream 是所有输出字节流的父类(抽象类)
- FileOutputStream 是向文件输出数据的输出字节流
FileOutputStream的使用步骤:
- 找到目标文件。
- 建立数据的输出通道。
- 把数据转成字节数据写出。
- 关闭资源。
FileOutputStream要注意的细节:
- 使用FileOutputStream写数据时,如果目标文件不存在,那么自动创建目标文件对象。
- 使用FileOutputStream写数据时,如果目标文件已存在,那么会先清空目标文件中的数据,然后再写入数据。
- 使用FileOutputStream写数据时,如果目标文件已存在,需要在原来数据基础上追加数据,就要使用:new
FileOutputStream(file, true)构造函数,第二个参数为true。 - 使用FileOutputStream的write方法写数据时,虽然接收到的是一个int类型(32位)的数据,但是真正写出的只是一个字节(8位)的数据,只把低八位的数据写出,其他24位数据全部丢弃。
public class Demo1 {
public static void main(String[] args) throws IOException {
writeTest2();
}
/**
* 使用字符数组把数据写出
*/
public static void writeTest2() throws IOException {
// 找到目标路径
File file = new File("G:\\a.txt");
// 建立数据的输出通道
// FileOutputStream fileOutputStream = new FileOutputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(file, true);
// 把数据写出
// String data = "hello world";
String data = "\r\nhello world";
fileOutputStream.write(data.getBytes()); // 将字符串转换为字节数组写出。
// 关闭资源
fileOutputStream.close();
}
/**
* 每次只能写出一个字节的数据
*/
public static void writeTest1() throws IOException {
// 找到目标路径
File file = new File("G:\\a.txt");
// 建立数据的输出通道
FileOutputStream fileOutputStream = new FileOutputStream(file);
// 把数据写出
fileOutputStream.write('h'); // 传入的是字符类型,会自动转换成int类型
fileOutputStream.write('e');
fileOutputStream.write('l');
fileOutputStream.write('l');
fileOutputStream.write('o');
// 关闭资源
fileOutputStream.close();
}
}
/**
* 需求:拷贝一张图片
*/
public class Demo3 {
public static void main(String[] args) throws IOException {
copy();
}
public static void copy() throws IOException {
// 找到目标文件
File inFile = new File("G:\\1.jpg");
File destFile = new File("F:\\1.jpg");
// 建立数据的输入输出通道
FileInputStream fileInputStream = new FileInputStream(inFile);
// 每创建一个FileOutputStream时,默认情况下,FileOutputStream的指针会指向文件的开始位置。而当FileOutputStream创建后,每写出一次数据,指针都会移动到文件的末尾处。因此这里是没有必要加true的。
FileOutputStream fileOutputStream = new FileOutputStream(destFile);
// 建立缓冲数组,边读边写
byte[] buf = new byte[1024];
int length = 0;
while((length = fileInputStream.read(buf)) != -1) {
fileOutputStream.write(buf, 0, length); // 如果不指定长度,拷贝过去的图片就很可能比源图片大!
}
// 关闭资源 原则:先开后关,后开先关
fileOutputStream.close();
fileInputStream.close();
}
}
3 BufferedInputStream
- 输入字节流的体系:
--------| InputStream 输入字节流的基类(抽象类)
--------------| FileInputStream 读取文件数据的输入字节流
--------------| BufferedInputStream 缓冲输入字节流。缓冲输入字节流的出现主要是为了提高读取文件的效率。其实该类内部只不过是维护了一个8KB的字节数组而已。
注意:凡是缓冲流都不具备读写文件的能力
使用BufferedInputStream的步骤:
- 找到目标文件
- 建立数据的输出通道
- 建立缓冲输入字节流
- 关闭资源
备注:使用缓冲输入字节流(BufferedInputStream)读取数据和创建字节数组使用数据输入字节流(FileInputStream)读取效率差不多,一般都习惯使用FileInputStream读取。
public class Demo1 {
public static void main(String[] args) throws IOException {
readTest2();
}
public static void readTest2() throws IOException {
// 找到目标文件
File file = new File("G:\\a.txt");
// 建立数据的输入通道
FileInputStream fileInputStream = new FileInputStream(file);
// 建立缓冲输入字节流
// 疑问1:为什么创建BufferedInputStream时需要传递FileInputStream?因为BufferedInputStream本身不具备读文件的能力,所以需要借助FileInputStream来读取文件中的数据。
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
// 读取文件数据
int content = 0;
// 疑问2:BufferedInputStream出现的目的是为了提高读取文件的效率,但是BufferedInputStream的read方法每次只读取一个字节的数据,而FileInputStream的read方法每次也是读取一个数据,那么BufferedInputStream的高效率从何而来?
// 根本原因是BufferedInputStream在内存中维护了一个8KB的缓冲数组,文件中的数据会先填充到该缓冲数组中,然后一个一个的读取;而FileInputStream是在硬盘中一个一个的直接读取数据的,所以BufferedInputStream的效率要高得多。
while((content = bufferedInputStream.read()) != -1) {
System.out.print((char)content);
}
// 关闭资源
bufferedInputStream.close(); // 调用BufferedInputStream的close方法实际上关闭的是FileInputStream。
}
// 读取文件时我们都会使用缓冲数组读取。效率会更高
public static void readTest1() throws IOException {
File file = new File("G:\\a.txt");
FileInputStream fileInputStream = new FileInputStream(file);
byte[] buf = new byte[1024*8];
int length = 0;
while((length = fileInputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, length));
}
fileInputStream.close();
}
}
4 BufferedOutputStream
- 输出字节流体系:
--------| OutputStream 所有输出字节流的基类 抽象类
--------------| FileOutputStream 向文件输出字节的输出字节流
--------------| BufferedOutputStream 缓冲输出字节流。缓冲输出字节流出现的目的是为了提到写数据的效率。 内部也维护了一个8KB的字节数组
使用BufferedOutputStream的步骤:
- 找到目标文件
- 建立数据的输出通道
- 建立缓冲输出字节流对象
- 将数据写出
- 将缓冲数组中的数据写到硬盘上
BufferedOutputStream要注意的细节:
- 使用BufferedOutputStream写数据时,它的write方法会先把数据写到它内部维护的缓冲字节数组中,如果需要将数据写到硬盘上,就要调用flush方法或者close方法,或者是当内部维护的字节数字填满数据时,会自动写到硬盘上。
public class Demo2 {
public static void main(String[] args) throws IOException {
// 找到目标文件
File file = new File("G:\\a.txt");
// 建立数据的输出通道
FileOutputStream fileOutputStream = new FileOutputStream(file);
// 建立缓冲输出字节流对象
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
// 将数据写出
bufferedOutputStream.write("hello world".getBytes());
// 将缓冲数组中的数据写到硬盘上
// bufferedOutputStream.flush();
bufferedOutputStream.close(); // 其实调用的FileOutputStream的close方法。close方法内部会先调用flush方法,然后再关闭。
}
}
/**
* 需求:使用缓冲输入输出字节流拷贝一个图片
*/
public class Demo3 {
public static void main(String[] args) throws IOException {
copyImage();
}
public static void copyImage() throws IOException {
// 找到目标文件
File inFile = new File("G:\\1.jpg");
File outFile = new File("F:\\1.jpg");
// 建立数据输入输出通道
FileInputStream fileInputStream = new FileInputStream(inFile);
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
// 建立缓冲输入输出流
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
// 边读边写
int content = 0;
while((content = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(content);
}
// 关闭资源
bufferedOutputStream.close();
bufferedInputStream.close();
}
}