黑马程序员技术交流社区

标题: 用字节流读取文件,定义缓冲区的大小问题[ 已解决 ] [打印本页]

作者: 郑传庆    时间: 2012-6-8 18:57
标题: 用字节流读取文件,定义缓冲区的大小问题[ 已解决 ]
本帖最后由 郑传庆 于 2012-6-8 21:51 编辑

用FileInputStream在读取文件的时候,定义缓冲区的大小用下面哪个比较好?它们在什么情况下使用比较合适?
byte[] buff = new byte[input.availabe()]和byte[] buff = new byte[1024]
作者: 杨天皓    时间: 2012-6-8 19:08
availabe()在有些 InputStream 的实现将返回流中的字节总数,但也有很多实现不会这样做。试图使用此方法的返回值分配缓冲区,以保存此流所有数据的做法是不正确的。
也就是说,因为网络传输的非实时性,在你的程序去检查available的时候,实际上另一端可能还没有发送数据,或对方网络拥挤,要发给你的数据包还在队列中。所以你调用 available时有可能 会返回0。

建议你还是用1024吧。


作者: 潘东升    时间: 2012-6-8 19:14
byte[] buff = new byte[input.availabe()]是根据读取流的剩余字节变化长度的,一般读取内容少的文件的时候用会效率高,因为刚刚好一次就把源文件读取到了缓冲中,但是在内容量大的文件读取的时候用这种方法,有可能会耗尽虚拟机的使用内存,进而内存溢出,导致读取失败。还有,这种方式在网络读取时需要一次不受阻塞地读取完,容易因异常而中断导致读取失败。byte[] buff = new byte[1024],而这种方法的缓冲是固定大小的,不会出现这种情况,因为未知文件的大小是不确定的,所以一般建议使用这种方式。
作者: 麦田守望者0812    时间: 2012-6-8 20:24
import java.io.*;

public class FileStreamDemo {

public static void main(String[] args) throws IOException {

//创建两个文件,face.gif是已经存在文件,newFace.gif是新创建的文件

File inFile = new File("face.gif");

File outFile = new File("newFace.gif");

//创建流文件读入与写出类

FileInputStream inStream = new FileInputStream(inFile);

FileOutputStream outStream = new FileOutputStream(outFile);

//通过available方法取得流的最大字符数

byte[] inOutb = new byte[inStream.available()];

inStream.read(inOutb);  //读入流,保存在byte数组

outStream.write(inOutb);  //写出流,保存在文件newFace.gif中

inStream.close();

outStream.close();

}

}

实例:读写任意大文件应用

因为byte数组最大存储值不超过64M,所以当一个文件大于60M 的时候,需要分开几个流操作。我们把上面的程序作一个修改,就可以写入任意大小的文件。这个程序应用了FileInputStream类的方法如下:

read(byte[] b,int off,int len)

把特定位置的流内容读入数组,已经读入byte[]数组的内容,会在流文件中删除。

程序运行的结果会产生一个新文件。

样例:

import java.io.*;

public class FileStreamDemo2 {

public static void main(String[] args) throws IOException {

//创建两个文件

File inFile = new File("tcty36.rm");

File outFile = new File("newtcty36.rm");

//最大的流为60Mb,当文件的容量大于60Mb的时候便分开流

final int MAX_BYTE = 60000000;

long streamTotal = 0;  //接受流的容量

int streamNum = 0;  //流需要分开的数量

int leave = 0;  //文件剩下的字符数

byte[] inOutb;  //byte数组接受文件的数据

//创建流文件读入与写出类

FileInputStream inStream = new FileInputStream(inFile);

FileOutputStream outStream = new FileOutputStream(outFile);

//通过available方法取得流的最大字符数

streamTotal = inStream.available();

//取得流文件需要分开的数量

streamNum = (int)Math.floor(streamTotal/MAX_BYTE);

//分开文件之后,剩余的数量

leave = (int)streamTotal % MAX_BYTE;

//文件的容量大于60Mb时进入循环

if (streamNum > 0) {

for(int i = 0; i < streamNum; ++i){

inOutb = new byte[MAX_BYTE];

//读入流,保存在byte数组

inStream.read(inOutb, 0, MAX_BYTE);

outStream.write(inOutb);  //写出流

outStream.flush();  //更新写出的结果

}

}

//写出剩下的流数据

inOutb = new byte[leave];

inStream.read(inOutb, 0, leave);

outStream.write(inOutb);

outStream.flush();

inStream.close();

outStream.close();

}

}
希望可以有帮助  固定数组缓冲区可以通过循环的方式读取任意大的文件 另一种方法 在文件过大的条件下 会过多占用电脑资源
作者: 朝哥    时间: 2012-6-8 21:35
数组在哪里,在堆内存中,java的堆内存大小是有限度,如果的文件是2G的话,用byte[] buff = new byte[input.availabe()]的话,堆内存是装不下的。但是你用byte[] buff = new byte[1024],每次数组存满1024的字节以后,就会回头重存数组。
还有java的堆内存肯定小于你计算机的内存。
作者: 王月    时间: 2012-6-8 21:47

available()
这个方法只有在读取的内容很少时,可以用。
还有因为它可以不受阻塞地读取的估计剩余字节数,但是在网速缓慢的网络上读取大文件时很可能会中断读取,导致失败。

建议使用byte[] buff=new byte[1024],在这里它作为缓冲区是固定长度的,所以不会出现以上的问题


作者: 王月    时间: 2012-6-8 21:50
还有就是,avalible读取是一次就把所有的数据读取到缓冲区,而虚拟机的内存只有64M,所以在读取大文件时,很可能导致内存溢出.




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2