IO流概述
IO流用用来处理设备之间的数据传输,Java对数据的操作是通过流的方式,Java用于操作流的对象都在IO包中。
IO流的分类
按数据流向分为:输入流、输出流
按数据类型分为:字节流、字符流
字节流可以读写任何类型的文件,如:音频、视频、文本。
字符流只能读写文本文件。
字节流的抽象基类:InputStream(输入)、OutputStream(输出)
字符流的抽象基类:Reader(读取)、Writer(写入)
而由这四个类衍生出的子类都是以父类名作为后缀名的,并且不同子类名表示对不同数据进行操作。
FileOutputStream(文件输出流),FileInputStream(文件输入流)。并且输入输出(读取写入)成对出现。
字节流
FileOutputStream
FileOutputStream:文件输出流,用于将数据写入File或FileDescriptor的输出流。
构造方法
public FileOutputStream(File file) throws FileNotFoundException
创建一个向指定File对象表示的文件中写入数据的文件输出流。创建一个新FileDescriptor对象来表示此文件连接。
public FileOutputStream(String name) throws FileNotFoundException
创建一个向具有指定名称的文件中写入数据的输出文件流。创建一个新FileDescriptor对象来表示此文件连接。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");
//如果输出流所关联的文件不存在,会自动创建
FileOutputStream outputStream = new FileOutputStream(file);
FileOutputStream outputStream1 = new FileOutputStream("b.txt");
//close方法用于关闭流,每创建一个流在最后都需要关闭
/*作用:
1.通知系统释放关系管理a.txt文件的资源(释放资源)。
2.让流对象变成垃圾,等待垃圾回收器回收。*/
outputStream.close();
outputStream1.close();
}
}
创建字节输出流对象的过程
- 调用系统资源创建a.txt文件(如果该文件不存在)
- 创建一个outputStream对象
- 把outputStream对象指向这个文件
在上述两个构造方法中,还可以传入第二个boolean类型参数append,在之后会讲解用处
方法
public void write(int b) throws IOException
将指定字节写入此文件输出流。
public void write(byte[] b) throws IOException
将 b.length 个字节从指定 byte 数组写入此文件输出流中。
public void write(byte[] b,int off,int len) throws IOException
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
FileOutputStream out = new FileOutputStream("a.txt");
//write方法可将数据写入此文件输出流中
/*如果传入0-127,会将ASCII码表对应的内容写入文本中
如果传入此范围之外的数,不会报错,但会写入�*/
out.write(97);
String str="抗击疫情,武汉加油";
byte[] bytes = str.getBytes();
out.write(bytes);
//用于换行
out.write("\r\n".getBytes());
//在UTF-8中,一个汉字占三个字节,若要写入抗击疫情,则需要从0开始写入12个字节
out.write(bytes,0,12);
out.close();
}
}
在Windows系统中,\r\n表示换行;在Linux系统中,\n表示换行;在Mac系统中,\r表示换行。
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
//在构造方法中传入参数append可决定是覆盖还是续写原有数据
//传入true代表续写,传入false代表覆盖
FileOutputStream out = new FileOutputStream("a.txt",true);
out.write("中国加油!".getBytes());
out.close();
}
流的异常处理
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo4 {
public static void main(String[] args) {
FileOutputStream out=null;
try {
out=new FileOutputStream("a.txt");
out.write("abcd".getBytes());
}
catch (IOException e){
e.printStackTrace();
}
finally {
//关闭资源的操作out.close();放在finally中
try {
/*如果创建FileOutputStream对象时或者之前发生异常,导致对象未创建成功,就不需要关闭资源
所以需要if判断流对象是否为空*/
if (out!=null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileInputStream
FileInputStream用于读取诸如图像数据之类的原始字节流。
构造方法
public FileInputStream(File file) throws FileNotFoundException
通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定。创建一个新FileDescriptor对象来表示此文件连接。
public FileInputStream(String name) throws FileNotFoundException
通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名name指定。创建一个新FileDescriptor对象来表示此文件连接。
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
//输入流关联的文件如果不存在就会报错。
File file = new File("b.txt");
FileInputStream in1 = new FileInputStream(file);
FileInputStream in2 = new FileInputStream("b.txt");
in1.close();
in2.close();
}
}
方法
public int read() throws IOException
从此输入流中读取一个数据字节。
public int read(byte[] b) throws IOException
从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
public int read(byte[] b,int off,int len) throws IOException
从此输入流中将最多len个字节的数据读入一个byte数组中。
import java.io.FileInputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
//b.txt中的数据为abcd。
FileInputStream in = new FileInputStream("b.txt");
//每次返回一个字节的ASCII码,如果读完,返回-1
int b1 = in.read();
System.out.println(b1);
int b2 = in.read();
System.out.println(b2);
int b3 = in.read();
System.out.println(b3);
int b4 = in.read();
System.out.println(b4);
int b5 = in.read();
System.out.println(b5);
in.close();
}
}
/*
运行结果:
97
98
99
100
-1
*/
public class Demo {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("b.txt");
byte[] bytes = new byte[1024];
//将文件中的数据读取到字节数组中。
//返回读取的有效字节数
int len = in.read(bytes);
System.out.println(len);
//数组bytes的的0~3索引的位置上分别存储了a、b、c、d
String str = new String(bytes,0,len);
System.out.println(str);
in.close();
}
}
/*
运行结果:
4
abcd
*/
/*、
b - 存储读取数据的缓冲区。
off - 目标数组b中的起始偏移量。
len - 读取的最大字节数。
*/
import java.io.FileInputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("b.txt");
byte[] bytes = new byte[1024];
//从文件首部开始,读取len长度的字节,到数组中,从数组中的off索引处开始存储
//如果off为2,那么从bytes数组的2索引处开始存储a、b、c。所以一般off为0。
int len = in.read(bytes, 0, 3);
System.out.println(len);
//文件中的
String str = new String(bytes, 0, len);
System.out.println(str);
in.close();
}
}
/*
运行结果:
3
abc
*/
字节流复制文件
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
//创建输入流,关联源文件
FileInputStream inputStream = new FileInputStream("a.txt");
//创建输出流,关联目标文件
FileOutputStream outputStream = new FileOutputStream("C:\\Users\\彭洋\\Desktop\\aCopy.txt");
int b=0; //用于接收读取到的字节
while ((b=inputStream.read())!=-1){
outputStream.write(b);
}
//释放资源
inputStream.close();
outputStream.close();
}
}
在一般情况下一个文件的字节数会很多,如果每次只读取一个字节,速度很慢,我们可以一次读取一个字节数组,提高效率
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("a.txt");
FileOutputStream out = new FileOutputStream("C:\\Users\\彭洋\\Desktop\\aCopy.txt");
//创建一个数组充当缓冲区,一般大小为8kb,可根据实际情况决定
byte[] bytes=new byte[1024*8];
int len=0; //记录每次读取的有效字节个数
while((len=in.read(bytes))!=-1){
//如果不设置写入的长度len,如果最后一次读取的有效字节个数小于数组长度,就会将多余的字节复制到文件中
out.write(bytes,0,len);
}
in.close();
out.close();
}
}
BufferedOutputStream&BufferedInputStream
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区的效果,java在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流。
BufferedOutputStream
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
BufferedInputStream
在创建BufferedInputStream时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark操作记录输入流中的某个点,reset作使得在从包含的输入流中获取新字节之前,再次读取自最后一次mark操作后读取的所有字节。
复制文件
public BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
public BufferedInputStream(InputStream in)
创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用。
import java.io.*;
public class Demo {
public static void main(String[] args) throws IOException {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("b.txt"));
int b=0;
while ((b=inputStream.read())!=-1){
outputStream.write(b);
}
inputStream.close();
outputStream.close();
}
}
因为在创建BufferedInputStream对象时,会创建一个缓冲数组,将读取到的字节先存入缓冲数组,再写入文件,
所以每次读取一个字节和自己定义一个缓冲数组存储读取的元素的效率差不多。
所以当使用BufferedOutputStream和BufferedInputStream来进行复制文件的操作时,不需要再自己定义一个缓冲数组。
而对于使用FileInputStream和FileOutputStream复制文件时,自己定义缓冲数组与使用BufferedOutputStream和BufferedInputStream的效率差不多。