1.I/O流概述

定义:I/O(Input/Output)流,即输入/输出流,是 Java 中实现输入/输出的基础,它可以方便地实现数据的输入/输出操作。

可分为如下几类:👇👇👇

Java——I/O流(一):字节流(概念理解+应用举例)_System

结构:Java 中的 I/O 流主要定义在 java.io 包中,该包下定义了很多类,其中有4个类为流的顶级类,分别为 InputStream 和OutputStream,Reader 和 Writer。

说明:①InputStream 和 OutPutStream 是字节流,而 Reader 和 Writer 是字符流。

           ②InputStream和Reader是输入流,而OutPutStream和Writer是输出流。

           ③下图中的4个顶级类都是抽象类,并且是所有流类型的父类。

Java——I/O流(一):字节流(概念理解+应用举例)_释放资源_02

 

2.字节流概述 

定义:在计算机中,无论是文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的,I/O流中针对字节的输入/输出提供了一系列的流,统称为字节流。

说明:①字节流是程序中最常用的流。

           ②在JDK中,所有的字节输入流都继承自 InputStream,所有的字节输出流都继承自 OutputStream。

Java——I/O流(一):字节流(概念理解+应用举例)_System_03

2.1 字节输入流InputStream常用的方法 

Java——I/O流(一):字节流(概念理解+应用举例)_System_04

2.2 字节输出流OutputStream常用的方法 

Java——I/O流(一):字节流(概念理解+应用举例)_释放资源_05

2.3 InputStream和OutputStream的继承体系 

Java——I/O流(一):字节流(概念理解+应用举例)_System_06

 

3.字节流读写文件 

说明:①针对文件的读写操作,JDK专门提供了两个类,分别是 FileInputStream 和 FileOutputStream。

           ②FileInputStream 是 InputStream 的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。

从文件读取数据是重复的操作,因此需要通过循环语句来实现数据的持续读取。

3.1 字节输出流读写文件 

写入数据的原理(内存-->硬盘):

Java程序 → Java虚拟机 → 操作系统 → 操作系统调用写数据的方法 → 把数据写到文件中

写数据的时候,会把要写入的数据转换为二进制数。在打开文件的时候,都会查询编码表(例如:ASCII表),把字节转换为字符表示。

import java.io.*;
public class IODemo01 {
	public static void main(String[] args) throws IOException {
		//使用文件名创建字节流对象
		FileOutputStream fos1=new FileOutputStream("FOS1.txt");
		fos1.write(65);//依次写出三个字节的数据
		fos1.write(66);
		fos1.write(67);
		fos1.close();//关闭字节输出流,并释放资源
		
		FileOutputStream fos2=new FileOutputStream("FOS2.txt");
		byte[] bytes2={97,98,99};//创建一个byte数组
		fos2.write(bytes2);//将bytes2字节数组中的所有字节写入fos2输出流
		fos2.close();//关闭字节输出流,并释放资源
		
		FileOutputStream fos3=new FileOutputStream("FOS3.txt");
		byte[] bytes3={97,98,99,100,101,102};
		//将bytes3数组中从1开始往后的4个字节写入fos3输出流
		fos3.write(bytes3,1,4);//即字节98,99,100,101
		fos3.close();//关闭字节输出流,并释放资源
		
		FileOutputStream fos4=new FileOutputStream("FOS4.txt");
		String str1="大佬,你好!";//创建一个字符串
		byte[] bytes4=str1.getBytes();//调用String类的getBytes()方法将该字符串转为byte数组
		fos4.write(bytes4);//将bytes4字节数组中的所有字节写入fos4输出流
		fos4.close();//关闭字节输出流,并释放资源
		
		/**字节输出流的续写,有如下两个构造方法
		 * public FileOutputStream(File file, boolean append)
		 * 创建文件输出流以写入,由指定的File对象表示的文件
		 * 
		 * public FileOutputStream(String name, boolean append)
		 * 创建文件输出流以指定的名称写入文件
		 * 参数中有一个boolean类型的值:true表示追加数据,false表示清空原有数据 
		 */
		FileOutputStream fos5=new FileOutputStream("FOS5.txt",true);
		String str2="一路相遇,";
		byte[] bytes5=str2.getBytes();
		fos5.write(bytes5);//第一次向"FOS5.txt"文件中写入相应的内容
		String str3="感谢有你!";
		byte[] bytes6=str3.getBytes();
		fos5.write(bytes6);//第二次向"FOS5.txt"文件中追加写入相应的内容
		fos5.close();//关闭字节输出流,并释放资源
		
		FileOutputStream fos6=new FileOutputStream("FOS6.txt",true);
		String str4="天行健,君子以自强不息!";
		byte[] bytes7=str4.getBytes();
		fos6.write(bytes7);//第一次向"FOS6.txt"文件中写入相应内容
		String str5="\n";
		byte[] bytes8=str5.getBytes();
		fos6.write(bytes8);//第二次向"FOS5.txt"文件中写入一个换行
		String str6="地势坤,君子以厚德载物!";
		byte[] bytes9=str6.getBytes();
		fos6.write(bytes9);//第三次向"FOS5.txt"文件中写入相应内容
		fos6.close();//关闭字节输出流,并释放资源
	}
}

在运行上述代码之后,我们就可以在指定的文件路径下,找到我们所写的文件以及相应的内容。如下图:👇👇👇 

Java——I/O流(一):字节流(概念理解+应用举例)_释放资源_07

Java——I/O流(一):字节流(概念理解+应用举例)_释放资源_08

Java——I/O流(一):字节流(概念理解+应用举例)_输出流_09

Java——I/O流(一):字节流(概念理解+应用举例)_输出流_10

Java——I/O流(一):字节流(概念理解+应用举例)_释放资源_11

Java——I/O流(一):字节流(概念理解+应用举例)_输出流_12

Java——I/O流(一):字节流(概念理解+应用举例)_输出流_13

3.2 字节输入流读写文件

读取数据的原理(硬盘-->内存):
Java程序 → Java虚拟机 → 操作系统 → 操作系统调用读取数据的方法 → 读取文件 

构造方法:
//通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
public FileInputStream(String name) throws FileNotFoundException

//通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的File对象file命名
public FileInputStream(File file) throws FileNotFoundException
import java.io.*;
public class IODemo02 {
	public static void main(String[] args) throws IOException {
		//创建FileInputStream对象,构造方法中绑定要读取的数据源
		FileInputStream fis1=new FileInputStream("E:/Eclipse/Java Project/Love/FOS1.txt");
		System.out.println("读取文件FOS1中的内容:");
		int len=0;
		//read()方法是一个字节一个字节的进行读取
		while((len=fis1.read())!=-1) {
			System.out.print((char)len + " ");
		}
		/*int byte0=fis1.read();
		char ch0=(char)byte0;//65 对应字符 A
		System.out.println(byte0 + " 对应:" + ch0);
		int byte1=fis1.read();
		char ch1=(char)byte1;//66 对应字符 B
		System.out.println(byte1 + " 对应:" + ch1);
		int byte2=fis1.read();
		char ch2=(char)byte2;//67 对应字符 C
		System.out.println(byte2 + " 对应:" + ch2);
		int byte3=fis1.read();
		char ch3=(char)byte3;
		System.out.println(byte3 + " 对应:" + ch3);
		此时已将FOS1文件中的内容全部读完,再进行读取,将输出-1*/
		fis1.close();//关闭字节输入流,并释放资源
                System.out.print();
		
		FileInputStream fis2=new FileInputStream("E:/Eclipse/Java Project/Love/FOS2.txt");
		System.out.println("读取文件FOS2中的内容:");
		byte[] bytes1=new byte[3];
		int len1=fis2.read(bytes1);
		for(int i=0;i<len1;i++) {
			char ch3=(char)bytes1[i];
			System.out.print(ch3 + " ");
		}
		fis2.close();//关闭字节输入流,并释放资源
		System.out.println();
		
		FileInputStream fis3=new FileInputStream("E:/Eclipse/Java Project/Love/FOS3.txt");
		System.out.println("读取文件FOS3中的内容:");
		byte[] bytes2=new byte[5];
		int len2=fis3.read(bytes2,1,4);//len2=4
		for(int i=1;i<=4;i++) {
			char ch4=(char)bytes2[i];
			System.out.print(ch4 + " ");
		}
		fis3.close();//关闭字节输入流,并释放资源
		System.out.println();
	}
}

在运行上述代码之后,可以看到下面的运行结果,以及我们拷贝文件的结果。如下图:👇👇👇

Java——I/O流(一):字节流(概念理解+应用举例)_System_14

3.3 字节缓冲流的效率测试

缓冲流,也叫高效流。能够高效读写缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化对象等等。它是四个基本File流的增强,所以也是4个流,按照数据类型分类。

  • 字节缓冲流:BufferedInputStream,BufferedOutputStream
  • 字符缓冲流:BufferedReader,BufferedWriter

缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO读取次数,从而提高读写的效率。

说明:除了定义字节缓冲区来提高文件拷贝效率外,IO中还提供了两个字节缓冲流来提高文件拷贝效率:BufferedInputStream 和 BufferedOutputStream。它们的构造方法中分别接收 InputStream 和 OutputStream 类型的参数作为对象,在读写数据时提供缓冲功能。

构造方法:
//创建一个新的字节缓冲输入流
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)

//创建一个新的字节缓冲输出流
BufferedOutputStream(OutputStream out)//将数据写入指定的底层输出流
BufferedOutputStream(OutputStream out, int size)//将具有指定缓冲区大小的数据写入指定的底层输出流

//参数:
InputStream in:字节输入流
OutputStream out:字节输出流
int size:缓冲区大小,不写的话,默认
import java.io.*;
public class IODemo03 {
	public static void main(String[] args) throws IOException {
		//普通的文件拷贝
		long beginTime1=System.currentTimeMillis();
		FileInputStream FIS1=new FileInputStream("E:/Eclipse/Java Project/Love/集合.jpg");
		FileOutputStream FOS1=new FileOutputStream("E:/Eclipse/Java Project/Love/集合1.jpg");
		System.out.print("普通的文件拷贝");
		int length1=0;
		while((length1=FIS1.read())!=-1) {
			FOS1.write(length1);
		}
		FIS1.close();//关闭字节输入流,并释放资源
		FOS1.close();//关闭字节输出流,并释放资源
		long endTime1=System.currentTimeMillis();
		System.out.println("花费的时间为:" + (endTime1-beginTime1) + "ms");
				
		//使用字节流的缓冲区进行文件拷贝
		long beginTime2=System.currentTimeMillis();
		FileInputStream FIS2=new FileInputStream("E:/Eclipse/Java Project/Love/集合.jpg");
		FileOutputStream FOS2=new FileOutputStream("E:/Eclipse/Java Project/Love/集合2.jpg");
		System.out.print("使用字节流的缓冲区进行文件拷贝");
		int length2=0;
		byte[] bytes1=new byte[1024];
		while((length2=FIS2.read(bytes1))!=-1) {
			FOS2.write(bytes1,0,length2);
		}
		FIS2.close();//关闭字节输入流,并释放资源
		FOS2.close();//关闭字节输出流,并释放资源
		long endTime2=System.currentTimeMillis();
		System.out.println("花费的时间为:" + (endTime2-beginTime2) + "ms");
		
		//使用字节缓冲流进行文件拷贝
		long beginTime3=System.currentTimeMillis();
		BufferedInputStream BIS=new BufferedInputStream(new FileInputStream("E:/Eclipse/Java Project/Love/集合.jpg"));
		BufferedOutputStream BOS=new BufferedOutputStream(new FileOutputStream("E:/Eclipse/Java Project/Love/集合3.jpg"));
		System.out.print("使用字节缓冲流进行文件拷贝");
		int length3=0;
		byte[] bytes2=new byte[1024];
		
		while((length3=BIS.read(bytes2))!=-1) {
			BOS.write(bytes2,0,length3);
		}
		BIS.close();//关闭字节缓冲输入流,并释放资源
		BOS.close();//关闭字节缓冲输出流,并释放资源
		long endTime3=System.currentTimeMillis();
		System.out.println("花费的时间为:" + (endTime3-beginTime3) + "ms");
	}
}

Java——I/O流(一):字节流(概念理解+应用举例)_输出流_15

Java——I/O流(一):字节流(概念理解+应用举例)_释放资源_16

从图中可以看出拷贝文件所消耗的时间明显减少了很多,这说明使用字节缓冲流同样可以有效的提高程序的传输效率。

这种方式与字节流的缓冲区类似,都对数据进行了缓冲,从而有效的提高了数据的读写效率。