1.本文概述
本文讲解IO系列有关字节流对象部分的内容。
字节流主要包含以下四个部分:
FileOutputStream
FileInputStream
BufferedOutputStream
BufferedinputStream
2.字节流的输出操作
1.输出流OutputStream
常用方法:
void close()
关闭此输出流并释放与此流有关的所有系统资源。
void flush()
刷新此输出流并强制写出所有缓冲的输出字节。
void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
abstract void write(int b)
将指定的字节写入此输出流。
说明:OutputStream是一个抽象类,无法直接实例化,因此一般使用其直接子类FileOutputStream。
2.文件输出流FileOutputStream
构造方法:
FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(File file, boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果为append为true,则将字节写入文件末尾处,而不是覆盖整个文件。
FileOutputStream(String name)
创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(String name, boolean append)
创建一个向具有指定 name 的文件中写入数据的输出文件流。
常用方法:
void close()
关闭此文件输出流并释放与此流有关的所有系统资源。
void write(byte[] b)
将 b.length 个字节从指定 byte 数组写入此文件输出流中。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
void write(int b)
将指定字节写入此文件输出流。
void close()
关闭此输出流并释放与此流有关的所有系统资源。
需求描述:将字符串数据以字节流的形式写入指定文件中
示例代码:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) {
//声明FileOutputStream对象
FileOutputStream fos=null;
try {
//实例化FileOutputStream对象
fos=new FileOutputStream("G:\\file_out_test.txt");
//用于输出的目标字符串
String tarStr="这是通过字节流写入文件的测试数据";
//以字节流的输出目标字符串
fos.write(tarStr.getBytes());
//刷新字节流缓存
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fos!=null)
try {
//关闭字节流
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
程序运行结果
4.png
3.字节流的读取操作
1.输入流InputSteam
常用方法:
int available()
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
void close()
关闭此输入流并释放与该流关联的所有系统资源。
abstract int read()
从输入流中读取数据的下一个字节。
int read(byte[] b)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
int read(byte[] b, int off, int len)
将输入流中最多 len 个数据字节读入 byte 数组。long skip(long n)
跳过和丢弃此输入流中数据的 n 个字节。
说明:FileInputStream是一个抽象类,无法直接实例化,因此一般使用其直接子类FileInputStream。
2.文件输入流FileInputStream
构造方法:
FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
FileInputStream(String name)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
常用方法:
int available()
返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
void close()
关闭此文件输入流并释放与此流有关的所有系统资源。
int read()
从此输入流中读取一个数据字节。
int read(byte[] b)
从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
int read(byte[] b, int off, int len)
从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
long skip(long n)
从输入流中跳过并丢弃 n 个字节的数据。
第一种方式:
//部分代码
public static void main(String[] args) {
//声明FileInputStream对象
FileInputStream fis=null;
try {
//实例化FileInputStream对象
fis=new FileInputStream("G:\\file_out_test.txt");
int ch=0;
while((ch=fis.read())!=-1){
//将获取到的int型数据强转为char型输出
System.out.print((char)ch);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(fis!=null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序运行结果:
test:this file is used by OutputStream
说明:使用这种方式读取数据,目标文件中不能存在中文,否则会出现乱码。因为无参构造方法每次只会读取单个字节,而每个中文由两个字节组成
第二种方式:
//部分代码
public static void main(String[] args) {
//声明FileInputStream对象
FileInputStream fis=null;
try {
//实例化FileInputStream对象
fis=new FileInputStream("G:\\file_out_test.txt");
//定义用于临时存储数据的字节数组,请区别于FileReader的字符数组
byte[] bufArr=new byte[1024];
//记录读取到的字符数组长度
int len;
while((len=fis.read(bufArr))!=-1){
System.out.println(new String(bufArr,0,len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(fis!=null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序运行结果:
test:this file is used by OutputStream
test:这里使用了字节数组作为缓冲区
tsst:所以我终于可以出现中文了
第三种方式-特有方式
示例代码:
//部分代码
public static void main(String[] args) {
//声明FileInputStream对象
FileInputStream fis=null;
try {
//实例化FileInputStream对象
fis=new FileInputStream("G:\\file_out_test.txt");
//建立和目标文件字节流大小一致的字节数组
byte[] bufArr=new byte[fis.available()];
//读取字节流
fis.read(bufArr);
//将字节数组转化为字符串输出
System.out.println(new String(bufArr));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(fis!=null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序运行结果
test:this file is used by OutputStream
test:这里使用了字节数组作为缓冲区
tsst:所以我终于可以出现中文了
说明:这种方式只适用于文件较小的情况,因为java虚拟机初始化时的默认内存仅为64M
总结:考虑到实际开发中的效率要求,建议使用第二种方式。
4.拷贝图片
需求描述:将G盘根目录下的测试图片复制到D盘
步骤:
1.用字节读取流对象和图片文件关联
2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3.通过循环读写,完成数据存储
4.关闭资源
示例代码:
//部分代码
public static void main(String[] args) {
//声明字节输入输出流对象
FileOutputStream fos=null;
FileInputStream fis=null;
try {
//进行实例化
fos=new FileOutputStream("D:\\test.png");
fis=new FileInputStream("G:\\test.png");
//临时存储数据的缓冲数组
byte[] bufArr=new byte[1024];
//记录读取的数据长度
int len;
while((len=fis.read(bufArr))!=-1){
fos.write(bufArr, 0, len);
fos.flush();//刷新流缓存
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fis!=null)
try {
//关闭流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fos!=null)
try {
//关闭流
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.字节流的缓冲区
对应类:
BufferedOutputStream
BufferedInputStream
1.缓冲输出流
构造方法:
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size)
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
常用方法:
void flush()
刷新此缓冲的输出流。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。
void write(int b)
将指定的字节写入此缓冲的输出流。
void close()
关闭此输出流并释放与此流有关的所有系统资源。
void write(byte[] b)
将 b.length 个字节写入此输出流。
2.缓冲输入流
构造方法:
BufferedInputStream(InputStream in)
创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedInputStream(InputStream in, int size)
创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
常用方法:
int available()
返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。
void close()
关闭此输入流并释放与该流关联的所有系统资源。
int read()
参见 InputStream 的 read 方法的常规协定。
int read(byte[] b)
从此输入流中将 byte.length 个字节的数据读入一个 byte 数组中。
int read(byte[] b, int off, int len)
从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。long skip(long n)
跳过和丢弃此输入流中数据的 n 个字节。
3.简单应用
需求描述:将G盘的MP3文件通过缓冲字节流复制到D盘
示例代码:
//部分代码
public static void main(String[] args) {
long start=System.currentTimeMillis();
//声明输入输出缓冲字节流对象
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
//实例化对象
bis=new BufferedInputStream(new FileInputStream("G:\\test.mp3"));
bos=new BufferedOutputStream(new FileOutputStream("D:\\test.mp3"));
//写入数据
byte[] b=new byte[1024];
int len=0;
while((len=bis.read(b))!=-1){
bos.write(b, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally{
if(bos!=null)
try {
//关闭流
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
if(bis!=null)
try {
//关闭流
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
long end=System.currentTimeMillis();
System.out.println("消耗时间:"+(end-start)+"ms");
}
}
程序运行结果
消耗时间:13ms
说明:在本例中可以不使用flush进行刷新。并且因为缓冲流的应用,文件的复制效率得到了大幅度提高