文件操作 FileInputStream和FileOutputStream类 三种read方法对比概述
今天介绍FileInputStream类和FileOutputStream类,从本地文件中读 / 写数据。
流
1、流的概念
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
2、流的分类
根据处理数据类型的不同分为:字符流和字节流。
字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串;而字节流处理单元为 1 个字节,操作字节和字节数组。
根据数据流向不同分为:输入流和输出流 。
字节流
1、读写字节流:InputStream 输入流(读)和OutputStream 输出流(写)
![](https://img-blog.csdnimg.cn/20200403164840796.png)
![](https://img-blog.csdnimg.cn/20200403171008499.png)
如图所示,InputStream 是所有的输入字节流的父类,它是一个抽象类。
ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据
2、FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。Java也提供了FileReader专门读取文本文件。
FileOutputStream通过字节的方式写数据到文件中,适合所有类型的文件。Java也提供了FileWriter专门写入文本文件。
InputStream特有方法:
int available(); //返回文件中的字节个数
注:可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用!
3. 字节流缓冲区
1)缓冲区的出现时为了提高流的操作效率而出现的.
2)需要被提高效率的流作为参数传递给缓冲区的构造函数
3)在缓冲区中封装了一个数组,存入数据后一次取出
FileInputStream及FileOutputStream类的构造方法
![](https://img-blog.csdnimg.cn/20200403162126563.png)
FileInputStream的构造方法:
1.FileInputStream(File file)------------从File对象的文件读入数据
2.FileInputStream(String name)-------------从指定文件读入数据,这里要写具体文件路径
![](https://img-blog.csdnimg.cn/20200403163702208.png)
FileOutputStream的构造方法:
1.FileOutputStream(File file)-------------向File对象的文件写入数据
2.FileOutputStream(File file,boolean append);------向File对象的文件追加写入数据
3.FileOutputStream(String path)-------------向指定文件写入数据
4.FileOutputStream(String path,boolean append);--------向指定文件追加写入数据
当append的值为true时,向文件中写入的数据会追加到原数据的后面,否则会重写该文件的数据。默认为false。
代码测试read()以及write()三个方法各自性能及用法
由于FileInputStream 和 FileOutputStream类是可以读写媒体文件的,我们就来测试一下这两个类中的所有读写方法,让我们对它们有所了解。
大致操作流程:(以File类为例)
使用File类打开一个文件;
通过字节流或字符流的子类,指定输出的位置;
进行读/写操作;
关闭输入/输出。
我们新建两个Folder分别为res 和 tag ,我们在res文件夹下放入一首歌。
![](https://img-blog.csdnimg.cn/2020040317320079.png)
刷新后,res出现mp3文件.
![](https://img-blog.csdnimg.cn/20200403172436100.png)
我们的目标是,将res下的这个文件,重新写入到另一个文件中,要求能播放且两个文件字节数相同。
第一次读写代码------read()、write()方法
package com.mec.netframework.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FisReadMethodTest {
public static void main(String[] args) {
File file = new File("./bin/res/summer.mp3");//得到summer.mp3文件
try {
FileInputStream fis = new FileInputStream(file);//用file new一个输入流
FileOutputStream fos = new FileOutputStream("./bin/tag/summer.mp3");
//“.”代表从当前目录开始,因为src和bin是镜像关系,我们可以在bin中进行测试
//new 一个输出流,后面的目录路径代表最后“写”的mp3文件生成的位置和命名
int result ;
long starttime = System.currentTimeMillis();
//经过测试发现fis.read()是一个一个字节进行读取的!
//fis.read()进行“读”操作并返回一个int类型的数据,一旦字节数据被读完,它就会返回-1!
//所以我们将它作为循环条件。
//当输入流读取一个字节,输出流就写入一个字节,直到字节数据被读完,循环结束!
while((result = fis.read()) != -1) {
fos.write(result);
}
long endtime = System.currentTimeMillis();
int time =(int) (( endtime - starttime)/1000);
//这是读写过程的总消耗时长
System.out.println("时间:" + time + "( s )");
//记得关闭输入输出流!
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果展示
我们在tag中得到了新写成的summer.mp3
总耗时:30s!!!
![](https://img-blog.csdnimg.cn/20200403175825889.png)
现在看看它们的字节数是否相同呢?
一点没错!但是效率太低了,9.86M就要用30s,那再传个电影可还得了!再去试试别的方法吧!
第二次读写代码------read(byte[] b)、write(byte[] b)方法
关于字节数组长度定义的原因:(BUFFER_SIZE)
IP数据报报文的报头部分有一个表示报文长度的量,占2B,即,16bit;
这就意味着,一个IP数据报文的最大长度应该是2^16B,即,64KB;
但是,考虑到IP数据报报文包含数据报头部,因此,实际数据量应该小于
64KB;
因此,在考虑网络数据传输时,最好以32KB字节作为每一次传输的数据
量。
原因:对于大于64KB的数据报文,会被路由器自动切割成小于64KB的小
报文片段。这是TCP协议自动完成的。
package com.mec.netframework.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FisReadByLength {
//1左一15位就是2的15次方 。这里定义数组容量为32KB
public static int BUFFER_SIZE = 1 << 15;
public static void main(String[] args) {
File file = new File("./bin/res/summer.mp3");
long len = file.length();
try {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("./bin/tag/summer.mp3");
byte[] buffer = new byte[BUFFER_SIZE];//构造了一个类似缓冲区的字节数组
int resLen = (int) len;
long starttime = System.currentTimeMillis();
//从fis中读取长度为字节的数据存到字节数组buffer中,并返回int类型的数据值
resLen = fis.read(buffer);
while(resLen != -1) {
//再从buffer数组中将字节按顺序写入新的文件
fos.write(buffer);
resLen = fis.read(buffer);
}
long endtime = System.currentTimeMillis();
long time =endtime - starttime;
System.out.println("时间:" + time + "( ms )");
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果展示:
同样生成了相应的summer.mp3文件
耗间:7( ms ) 注意单位变了!
速度可以但是我们发现,得到的文件大小变大了。
resLen = fis.read(buffer);
while(resLen != -1) {
fos.write(buffer);
resLen = fis.read(buffer);
}
仔细分析代码,可以想到,最后一次将数据读入数组时,它的字节个数大概率会小于2的15次方(数组长度),而不是恰好等于,所以最后一次数据并没有把倒数第二次的后面一些数据覆盖掉,导致在写入操作的时候,把倒数第二次最后面的一些数据又写了进去,相当于垃圾数据!所以字节数增加了,这是不可以的,因为严重时将会导致文件不能播放。
第三次读写代码------read(byte[] b, int off, int len)、write(byte[] b, int off, int len)方法
package com.mec.netframework.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FisReadThreePara {
public static int BUFFER_SIZE = 1 << 15;
public static void main(String[] args) throws IOException {
File file = new File("./bin/res/summer.mp3");
long fileLen = file.length();
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("./bin/tag/summer.mp3");
byte[] buffer = new byte[BUFFER_SIZE];
int length;//将要读进数组的字节个数
int readLen;//文件剩余字节数(长度)
int resLen = (int) fileLen;//刚开始剩余长度就等于文件长度
long starttime = System.currentTimeMillis();
while(resLen > 0) {
//如果剩余长度比定义的数组长度长,就将length赋值为BUFFER_SIZE
//短的话,就赋值为剩余长度resLen
//这一步保证读数的准确性
length = (resLen > BUFFER_SIZE ? BUFFER_SIZE : resLen);
//将输入流中的数据读进buffer数组,从下标0开始读入,读length个字节数据
readLen = fis.read(buffer, 0, length);
//将字节数组buffer中的数据从下标0开始写,写readLen个字节数据到指定文件
//这部操作保证了最后一次数据的准确性
fos.write(buffer, 0, readLen);
//没读写一次,意味着剩余长度减少BUFFER_SIZE
resLen -= BUFFER_SIZE;
}
long endtime = System.currentTimeMillis();
long time =endtime - starttime;
System.out.println("时间:" + time + "( ms )");
fis.close();
fos.close();
}
}
结果展示:
时间:8( ms )
完美撒花!
参考博文:https://www.cnblogs.com/caixiaohua/p/6737808.html