IO流
什么是IO流
IO,即in
和out
,也就是输入和输出,指应用程序和外部设备之间的数据传递,常见的外部设备包括文件、管道、网络连接。流(stream),是一个抽象的概念,是一连串的数据(字符或字节),以先进先出的方式发送信息的通道。
在我们电脑中所有的文件,文档,音频,视频,图片都可以进行读和写,他们都经过流的形式进行
一般来说关于流的特性有下面几点:
1.先进先出:最先写入输出流的数据最先被输入流读取到。
2.顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile除外)
3.只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。
什么是缓冲流
缓冲流是程序跟磁盘交互时非常重要的部分,我们知道,程序与磁盘的交互相对于内存运算是很慢的,容易成为程序的性能瓶颈。减少程序与磁盘的交互,是提升程序效率一种有效手段。
缓冲流,就应用这种思路:普通流每次读写一个字节,而缓冲流在内存中设置一个缓存区,缓冲区先存储足够的待操作数据后,再与内存或磁盘进行交互。这样,在总数据量不变的情况下,通过提高每次交互的数据量,减少了交互次数。
IO流的分类
IO流分为:输入流,输出流
输入流的意思就是:从磁盘中读取数据到内存(java代码)
输出流的意思就是:从内存(java代码)写入数据到磁盘中某个文件
输入流分为:字节输入流,字符输入流
输出流分为:字节输出流,字符输出流
字节流和字符流的其他区别:
字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,但不能处理图像视频等非文本文件。用一句话说就是:字节流可以处理一切文件,而字符流只能处理纯文本文件。字节流本身没有缓冲区,缓冲字节流相对于字节流,效率提升非常高。而字符流本身就带有缓冲区,缓冲字符流相对于字符流效率提升就不是那么大了。
字节输入流(FileInputStream)
案例:磁盘上面有一个1.txt文件,现在要将1.txt文件中的内容读取到内存(Java代码中)
public class Demo1 {
public static void main(String[] args) throws IOException {
//1.创建File对象,是咱们本地磁盘文件的一个File对象
File file = new File("c:/aaa/1.txt");
//2.创建文件字节输入流对象,来操作1.txt
//将c:/aaa/1.txt文件转为字节输入流的形式,之后可以按照流的形式读取到内存中
FileInputStream fis = new FileInputStream(file);
//3.加上缓冲功能
BufferedInputStream bis = new BufferedInputStream(fis);
//5.创建一个缓冲区的数组 byte 是byte类型的数组
byte[] buf = new byte[1024 * 4];//缓冲区4096字节
//现在数组是空的
//6.读取数据
// 如果没有字节可用,因为流在文件末尾,则返回值-1
int length = -1;
//如果length=-1 那么就会到达流的末尾 就证明后面没哟数据
//循环结束,不要再读了
while ((length = bis.read(buf)) != -1) {
System.out.println(new String(buf, 0, length));
}
//7.流是需要关闭的
bis.close();
fis.close();
}
}
字节输出流(FileOutputStream)
案例:Java代码中有一个字符串 将这个字符串写入磁盘某一个文件中
public class Demo2 {
public static void main(String[] args) throws IOException {
//将Java代码中的一个字符串写入到咱们的磁盘的某一个文件中
//1.创建File对象,文件路径对象 告知编译器要把数据写到哪个文件中
File file = new File("c:/aaa/2.txt");
//2.实例化字节输出流对象
FileOutputStream fos = new FileOutputStream(file);
//3.对FileOutputStream 加上缓冲的效果
//猜测一下 FileInputStream所对应的缓冲流 BufferedInputStream
//FileOutputStream 所对应的缓冲流 BufferedOutputStream
BufferedOutputStream bos = new BufferedOutputStream(fos);
//4.将一个字符串写入到磁盘中
String str = "大家再等我一天,后天见面!!!";
// write(byte[] b)
//咱们的参数是字节数组,咋办?str是一个字符串 但是参数是一个字节数组,咋解决?
//str是字符串 不能强转 将字符串转为字节数组,没有讲过!!!
//将str字符串转为字节数组
byte[] bytes = str.getBytes();
bos.write(bytes);
//5.写完以后一定要刷新流然后关闭流
bos.flush();//没有实际的意义,可以不写的
//6.关闭流
//在输入流的时候一定是先开的后关,后开的先关
bos.close();
fos.close();
}
}
案例:对比有缓冲流,和没有缓冲流的效率对比
public class Demo1 {
public static void main(String[] args) throws IOException {
copyVideo1();
}
//现在咱们讲的这个是带有缓冲的,看看带有缓冲视频的复制的耗时多少 2610ms
//写一个方法将bbb文件夹下面的3.map4格式的视频复制到aaa文件夹下面
//用带缓冲的,效率高
public static void copyVideo () throws IOException {
//获取系统的当前的毫秒数
long start = System.currentTimeMillis();
//1.创建字节缓冲输入流 将磁盘的数据读取到内存
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("c:/bbb/3.mp4")));
//2.创建字节缓冲输出流 从内存写入到的文件 源文件是mp4格式,写入到的也必须是mp4格式的
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("c:/aaa/goudan.mp4")));
//3.准备一个字节数组 缓冲区数组
byte[] buf = new byte[4 * 1024];//代码走到这一步是空的
//4.从磁盘读取数据到内存
int length = -1;
//这个视频很大,依靠循环来读取,每次读4 * 1024字节
while ((length = bis.read(buf)) != -1) {//从磁盘上读取数据到buf缓冲数组中
//每次循环 buf数组中有值,顺便依靠循环写入到磁盘
System.out.println("qwer");
bos.write(buf, 0, length);
}
//5.关闭流
bos.close();
bis.close();
//复制完以后再得到一个毫秒数,相减 就得到复制一个视频需要的时间
long end = System.currentTimeMillis();
System.out.println(end - start);
}
//看一下不带缓冲的流的读写
public static void copyVideo1 () throws IOException {
long start = System.currentTimeMillis();
FileInputStream fis = new FileInputStream(new File("c:/bbb/3.mp4"));
FileOutputStream fos = new FileOutputStream(new File("c:/aaa/goudan.mp4"));
int length = -1;
while ((length = fis.read()) != -1) {
fos.write(length);
}
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
字符输入流(FileReader)
FileReader:
是一个阅读字符文件的便利类,是专门处理字符文件的,比如txt文件。
音频视频图片不能使用这个流。
案例:将c盘下面的aaa文件夹下面的1.txt文件的内容 读取到Java内存中
public class Demo3 {
public static void main(String[] args) throws IOException {
//将c盘下面的aaa文件夹下面的1.txt文件的内容 读取到Java内存中
//和字节流一模一样
//1.新建一个File对象
File file = new File("c:/aaa/1.txt");
//2.新建FileReader 对象 字符输入流
FileReader fr = new FileReader(file);
//3.FileRFeader没有缓冲的效果,可以加上缓冲的效果
//杂加?BufferedReader
BufferedReader br = new BufferedReader(fr);
//4.字节的缓冲数组 是字节
//字符的缓冲数组 是字符
char[] cbuf = new char[4];//缓冲区是4个字符
//这个方法是用的!!!
//int read()一次读取,一个字符
//5.read(char[] cbuf) 将文件内容读取到字符数组中(缓冲区)
int length = -1;
while ((length = br.read(cbuf)) != -1) {
System.out.println(length);
//6.将数组展示到控制台
System.out.println(new String(cbuf, 0, length));
}
//7.关闭流
br.close();
fr.close();
}
}
字符输出流(FileWriter)
案例:将一个字符串类型的数据写入到磁盘中
public class Demo1 {
public static void main(String[] args) throws IOException {
//从内存写入数据到磁盘的文件中
File file = new File("c:/aaa/2.txt");
FileWriter fw = new FileWriter(file);
//加缓冲流
BufferedWriter bw = new BufferedWriter(fw);
//viod writer(char[] cbuf, int off, int length);
String str = "今天的天气真的太热了";
//将字符串转为char数组
char[] chars = str.toCharArray();
//将chars数组中 从0 开始 取3个字符写入到缓冲流中
bw.write(chars, 3, 3);
bw.close();
fw.close();
}
}
拷贝文件案例
案例:复制一本小说到另一个盘符下
public class Demo4 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(new File("c:/bbb/DiBa.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("c:/aaa/sb1.txt")));
int length = -1;
char[] cbuf = new char[4 * 1024];
while ((length = br.read(cbuf)) != -1) {
bw.write(cbuf, 0, length);
}
bw.close();
br.close();
}
}
在进行拷贝文件时,我们会写许多的重复代码,那我们能想到什么呢?
对!我们可以对其进行封装,所以我们创建一个FileUtil工具类
package com.qfedu.homework;
import java.io.*;
public class FileUtil {
/**
*
* @param start
* @param end
* @throws IOException
*/
public static void copyFile(File start,File end) throws IOException {
if (!start.isFile()){
System.out.println("只能拷贝文件");
throw new IOException("只能拷贝文件");
}
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(String.valueOf(start))));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(String.valueOf(end))));
byte[] buf = new byte[4*1024];
int length;
while ((length = bis.read(buf)) != -1){
bos.write(buf,0,length);
}
bos.flush();
bos.close();
bis.close();
}
}
当我们需要进行拷贝文件时,可以继承FileUtil类,然后调用copyFile方法,就可以完成功能。