流的概念/分类/常用流/FileInputStream+FileOutputStream实现(重点)/文件复制
流的概念/分类/常用流/FileInputStream+FileOutputStream实现(重点)/文件复制
流的概念
“流”是一个抽象的概念,它是对输入输出设备的一种抽象理解,在java中,对数据的输入输出操作都是以“流”的方式进行的。
I:Input
O:Output
通过IO可以完成硬盘文件的读和写
流的close()和flush()
close: 所有的流都实现了java.io.Closeable接口,都是可关闭的,都有close()方法。流毕竟是一个管道,这个是内存和硬盘之间的管道,用完之后一定要关闭,不然会耗费(占用)很多资源
flush: 所有的输出流 都实现了 java.io.Flushable接口,都是可刷新的,都有flush()方法。在输出流最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道的作用就是清空管道。
注:如果没有flush()可能会导致丢失数据
io流的分类,以及各个流的特点
按照流的方向进行分类:以内存作为参照物
- **输入流:**从内存中进去,叫做输入(Input),或者叫做读(Read)
- **输出流:**从内存中出来,叫做输出(Output),或者叫做写(Write)
按照读取数据的方式不同进行分类:
字节流(万能流): 按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件(文本文件,图片,声音文件,视频文件等等)都可以读取。( char 在java中是两个字节,windows操作系统中文件的a字符占用的是1个字节)
字符流: 按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取 普通文本文件(.txt) 而存在,只能读取纯文本文件。不能读取:图片,声音,word文件(存在格式,不属于普通文档/纯文本),视频等文件,
在java中只要“类名”以stream结尾的都是字节流,以“Reader/Writer结尾的都是字符流”
常用的流(16个)
//文件专属
java.io.FileInputStream
java.io.FileOutputStream
java.io.FileReader
java.io.FileWriter
//转换流(将字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter
//缓冲流专属:都是带缓冲区的
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream
//数据流专属:
java.io.DataInputStream
java.io.DataOutputStream
//标准输出流
java.io.PrintWriter
java.io.PrintStream
//对象专属流
java.io.ObjectInputStream
java.io.ObjectOutputStream
java.io.FileInputStream实现(重点)
先在D盘创建了一个txt文件,输入内容如下:
int read(byte b)
读取方式 int read(byte b),一个一个字节的读,硬盘和内存的交互大,时间/资源消耗大——>不常用
/*
java.io.FileInputStream:
1.文件字节输入流(万能流),任何类型文件都可以采用这个流来读
2.字节的方式,完成输入的操作,完成读的操作(硬盘--->内存)
*/
public static void main(String[] args) {
FileInputStream fis = null;
//创建文件字节输入流对象
//java.io.FileInputStream(string name),
//name为文件路径
/*文件路径中'\'要转换成'\\',因为'\'在java中表示转义
以下路径采用了:绝对路径的方式
"D:\\temp.txt"
所以,写成这个/也是可以的*/
//注意:在IDEA中默认的当前路径 是project的根
try {
fis = new FileInputStream("D:\\temp.txt");
//开始读
int readData = fis.read();
//这个方法的返回值是:读取到的“字节”本身
System.out.println(readData);//a-->97
int readData02 = fis.read();
System.out.println(readData02);//b-->98
int readData03 = fis.read();
System.out.println(readData03);//c-->99
int readData04 = fis.read();
System.out.println(readData04);//d-->100
int readData05 = fis.read();
System.out.println(readData05);
/*当读到文件末尾,再继续读,
读取不到任何数据,
就会返回-1
*/
} catch (FileNotFoundException e) {
e.printStackTrace();
}//编译异常,需要捕捉异常
catch (IOException e) {
e.printStackTrace();
}
finally {
//finally语句块中确保流一定关闭
//fis.close直接调用会爆红,
//需要在try/catch外给fis赋值为空
if(fis != null){//避免空指针异常
//关闭流的前提:流不是空
//流是null的时候没必要关闭
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
int read(byte[] b)
读取方式 int read(byte[] b),采用byte数组,一次读取多个字节。最多读取“数组。length”个字节,减少硬盘和内存的交互,提高程序的执行效率——>常用/掌握
/*
int read(byte[] b)
一次最多读取b.length个字节
减少硬盘和内存的交互,提高程序的执行效率
往byte[]数组当中读
*/
public class FileInputStreamTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\temp.txt");
//开始读,采用byte数组,一次读取多个字节。
//最多读取“数组。length”个字节
byte[] bytes = new byte[3];
//准备一个长度为3的byte数组,一次最多读3个字节
int readCount = fis.read(bytes);
//返回值是读到的字节数-->3
System.out.println(readCount);//abc
readCount = fis.read(bytes);
//返回值是读到的字节数-->1,覆盖之前的
System.out.println(readCount);//dbc
readCount = fis.read(bytes);
//一个字节数都读不到,就返回-1
System.out.println(readCount);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
int available()——返回流中剩余的没有读到的字节数量
可以获得总字节数量,就不需要循环,可以一次直接一次读完
注:不适合大文件,因为byte数组不能太大,几十万个应该问题不大
byte[] bytes = new byte[fis.available()];
long skip(long n):——跳过几个字节不读
fis.skip(3);
System.out.println(fis.read());
//输出第四个字节本身-->d的ascii码值100
java.io.FileOutputStream实现(重点)
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//temp02文件不存在的时候会自动新建
/*
fos = new FileOutputStream("D:\\temp02.txt");
//temp02文件不存在的时候会自动新建
fos = new FileOutputStream("D:\\temp.txt");
已经存在的文件,会先清空原文件,再写入
*/
fos = new FileOutputStream("D:\\temp.txt",true);
//以追加的方式在文件末尾写入,不会清空原文件内容
//开始写
byte[] bytes = {97,98,99,100};
//讲byte数组全部写出
fos.write(bytes);
//写完后,最后一定要要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
文件复制
/*
使用FileInputStream+FileOutputStream完成文件的拷贝
拷贝过程应该是一边读,一边写
使用以上的字节流拷贝文件的时候,文件类型随意(万能流),都能拷贝
*/
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建一个输入流对象
fis = new FileInputStream("D:\\a.txt");
//创建一个输出流对象
fos = new FileOutputStream("D:\\copy.txt");
//一边读一边写
byte[] bytes = new byte[fis.available()];
int readCount = 0;
while((readCount = fis.read(bytes)) != -1){
fos.write(bytes,0,readCount);
}
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
//分开try,防止其中一个出现异常,影响另一个流的关闭
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}