目录
一.IO流概述
生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了ctrl+s ,可能文件就白白编辑了。当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?U盘、内存、硬盘、外接设备等等。
我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input和输出output,即流向内存是输入流,流出内存的输出流。
Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据
二.IO的分类
- 根据数据的流向分为:输入流和输出流
- 输入流 :把数据从其他设备上读取到内存中的流
- 输出流 :把数据从内存中写出到`其他设备上的流
- 根据数据的类型分为:字节流和字符流。
- 字节流:以字节为单位,读写数据的流
- 字符流:以字符为单位,读写数据的流(使用文本工具,例如记事本,打开文件,可以看懂的)
三.字节流
- 一切都是字节
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。提示:8个二进制位为1个字节,0000-0000 是1个字节。
- 字节输出流OutputStream
java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
public abstract void write(int b) :将指定的字节输出流。
注意:close方法,当完成流的操作时,必须调用此方法,释放系统资源
- FileOutputStream类
OutputStream有很多子类,我们从最简单的一个子类开始。
java.io.FileOutputStream 类是文件输出流,用于将数据写出到文件。
/**
* 字节输出流
* public FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
* public FileOutputStream(String name): 创建文件输出流以指定的名称写入文件。
* 当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。
* 构造方法中传递的都是写入的数据的目的
* IO流使用的通用步骤:
* 1.创建IO流对象
* 2.调用方法,写出或者读取
* 3.释放资源
*/
public class Demo {
public static void main(String[] args) throws Exception {
method03();
}
/*
public abstract void write(int b) :将指定的字节输出流。
写入单个字节
*/
public static void method01() throws IOException {
FileOutputStream fos=new FileOutputStream("d:\\a.txt");
//fos.write(100);
fos.write(49);
fos.write(48);
fos.write(48);
fos.close();
//while (true){}
}
/*
void write(byte[] b)写入字节数组
* void write(byte[] b ,int off,int len)字节数组一部分写入到设备
*/
public static void method02()throws IOException{
FileOutputStream fos=new FileOutputStream("d:\\a.txt");
//准备字节数组
byte[] bytes="abcdef".getBytes();
//fos.write(bytes);
//写入数组一部分,例如1开始,写3个
fos.write(bytes,1,3);
fos.close();
}
/*
字节输出流创建文件,文件存在,覆盖
在文件的基础之上接着写
FileOutputStream()构造方法第二个参数,布尔类型,传递true,追加写入
*/
public static void method03() throws IOException{
FileOutputStream fos=new FileOutputStream("d:\\a.txt",true);
fos.write(99);
fos.close();
}
}
- 字节输入流InputStream
java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法
public void close():关闭此输入流并释放与此流相关联的任何系统资源
public abstract int read(): 从输入流读取数据的下一个字节
public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中
- FileInputStream类
java.io.FileInputStream 类是文件输入流,从文件中读取字节
/* 字节输入流
* FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
* FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
* 在输入流的构造方法中,传递的称为数据源
*/
public class Demo {
public static void main(String[] args) throws Exception {
method01();
}
/*
public abstract int read(): 从输入流读取数据的下一个字节
读取一个字节,返回int类型
返回值:int类型,读取到的字节,转成int类型
读取到流的末尾,返回-1
*/
public static void method01() throws IOException {
//创建字节输入流对象,构造方法中,传递数据源(必须是存在的)
FileInputStream fis=new FileInputStream("d:/a.txt");
//接受read()返回值
int len=0;
while((len=fis.read()) !=-1){
System.out.print((char)len);
}
fis.close();
}}
/字节输入流
* public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中
* 返回值:读取到的个数
*/
public class Demo {
public static void main(String[] args) throws Exception {
FileInputStream fis=new FileInputStream("d:/a.txt");
//定义字节数组
byte[] bytes=new byte[2];
//定义变量,接受read()返回值
int len=0;
while((len=fis.read(bytes))!=-1){
System.out.print(new String(bytes,0,len));
}
fis.close();
}}
四.IO流中的异常处理
- 在字节流的案例中,我们一直使用的是throws抛出异常。如果出现异常的话,程序将不会执行close()方法,因此异常需要使用try catch进行处理
- try外声明变量,try内建立对象。
- 目的是提升变量的作用域。
- finally中进行资源释放。
- 进行流对象非空判断。
- 如果有多个流对象,单独进行释放
public class Demo { public static void main(String[] args){ FileOutputStream fos=null; try { fos=new FileOutputStream("d:/b.txt"); fos.write(97); }catch (IOException ex){ ex.printStackTrace(); }finally { try { if(fos !=null){ fos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
五.文件复制
使用字节流可以进行任何文件的复制,因为字节流操作的是组成文件的最小单元-字节
-
public class Demo { public static void main(String[] args) throws IOException { long s1 = System.currentTimeMillis(); method01(); long s2 = System.currentTimeMillis(); System.out.println(s2-s1); } /* FileInputStream 读取单个字节 FileOutputStream 写入单个字节 */ public static void method01() throws IOException { //输入流对象,绑定数据源 FileInputStream fis=new FileInputStream("d:/a.wmv"); //输出流对象,绑定数据目的 FileOutputStream fos=new FileOutputStream("d:/copy/b.wmv"); int len=0; while((len=fis.read()) !=-1){ fos.write(len); } fos.close(); fis.close(); } /* FileInputStream 读取字节,存储数组 FileOutputStream 写入字节数组 */ public static void method02()throws IOException{ //输入流对象,绑定数据源 FileInputStream fis=new FileInputStream("d:/a.wmv"); //输出流对象,绑定数据目的 FileOutputStream fos=new FileOutputStream("d:/copy/b.wmv"); byte[] bytes=new byte[1024]; int len=0; while((len=fis.read(bytes)) !=-1){ fos.write(bytes,0,len); } fis.close(); fos.close(); } }
七.字节缓冲流
- 缓冲流介绍
-
缓冲流:针对基础流对象进行高效处理的流对象。或者为基础流增加功能。
字节缓冲流:BufferedInputStream,BufferedOutputStream
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
/**
* @author lzw
* @create 2022-02-19 14:57
* 使用IO流对象,需要考虑效率
* 读取单个字节的方式,效率低
* 字节数组换从方式,效率高
* JDK提供了缓冲流,提高原有流对象的效率
* 字节输出流的缓冲流java.io.BufferedOutputStream类
* 缓冲流对象,必须依赖原始流 FileOutputStrem
* 构造方法:BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
* 方法:write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。
* 字节输入流的缓冲流java.io.BufferedInputStream类
* 构造方法:BufferedInputStream(InputStream in) 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用
* 方法:int read()
*/
public class Demo {
public static void main(String[] args) throws IOException {
//创建字节输入流的缓冲流
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("d:/sp/1.wmv"));
//创建字节输出流的缓冲流
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("d:/sp/b/2.wmv"));
//缓冲流读写字节数组
byte[] bytes=new byte[1024];
int len=0;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
}
}