用read从Filebyte转inputstreamm里读出的byte,怎么知道它的长度

最近使用MD5进行大文件验证,固使用NIO这种高效率的模式来进行文件映射:
FileInputStream in = new FileInputStream(file);
FileChannel ch = in.getChannel();
MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
messageDigest.update(byteBuffer);
String md5 = bufferToHex(messageDigest.digest());
ch.close();
in.close();
本来想如果文件md5与数据库存储的值不同就删掉该文件的,结果出现了文件无法删除的情况。
抛出的违例
java.io.FileNotFoundException: E:\hello.jar
(请求的操作无法在使用用户映射区域打开的文件上执行。)
后来经查,原来是当使用 FileChannel.map 方法时,MappedByteBuffer 已经在系统内占用了一个句柄,而使用
FileChannel.close 方法是无法释放这个句柄的,且FileChannel有没有提供类似 unmap 的方法,因此会出现无法删除文件的情况。
此问题一直让我很郁闷,后来到网上查询到两种方法...
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);
getCleanerMethod.setAccessible(true);
sun.misc.Cleaner cleaner = (sun.misc.Cleaner)
getCleanerMethod.invoke(byteBuffer, new Object[0]);
cleaner.clean();
} catch (Exception e) {
e.printStackTrace();
此种方法需要JDK支持,我用的是JRE 1.6,提示没有 sun.misc.Cleaner 类,JDK包太大,项目又不让用。
第二种方法是显性设置byteBuffer为null,并调用GC,没什么实际意义。
实在没招了,又回来使用InputStream了...
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream((int)file.length());
byte[] cache = new byte[1048576];
for(int i = in.read(cache);i != -1;i = in.read(cache)){
out.write(cache, 0, i);
in.close();
out.close();
messageDigest.update(out.toByteArray());
md5 = bufferToHex(messageDigest.digest());
不知道SUN为啥要搞这种半截子工程,大家有什么其他解决方法么?
浏览 10119
论坛回复 /
(17 / 11555)
我觉得mappedbytebuffer更适用于文件较小,但是有些字节需要反复读取得情况
大约是这样的,对于计算一个大文件的MD5来说,每个字节都只读取一次,映射到内存应该是不会快的。
对于特别小的文件,javadoc是这么说的:
引用For most operating systems, mapping a file into memory is more expensive than reading or writing a few tens of kilobytes of data via the usual read and write methods. From the standpoint of performance it is generally only worth mapping relatively large files into memory.
也就是说,它建议把“大”文件做映射(实际上它说的也就是要读写几十K),但是我想也许这个映射的开销是一次性的,对于小文件以后反复读写就快了吧。
这个映射的特点是可以将超过(物理内存+虚拟内存)、超过JVM最大内存大小的文件部分装入内存。因此,所谓装入内存实际上是虚拟的,我们看到的就是一个大数组,读的时候,如果在内存里面,就从内存里面读,否则就要读文件。
由于映射是操作系统负责的,所以其很多行为都是不确定的,在javadoc里面就有很多这方面的描述。主要是写操作后,数据对其它程序的可见性。
另外还有一个问题,就是map的文件部分的大小也是有限制的。如下:
WinXP 32位 2G内存,2G虚拟内存,Map一个2G的文件,XmX=64M
map 0~500M& OK
map 0~1G&&&&& 内存溢出错误
循环,每次map1M,返回的buffer不释放,到达将近2G时内存溢出,也就是说,map的文件部分的总和也是有限制的
Linux 32位 2G内存,1G虚拟内存,Map一个3G多的文件,XmX=64M
map 0~3G& IllegalArgumentException,map的长度不能超过Integer.MAX_VALUE,也就是不能超过2G
map 0~Integer.MAX_VALUE ok
循环,每次map1M,返回的buffer不释放,到达2G后(2G或者2G多一点?)时内存溢出
Linux 64位 2G内存,2G虚拟内存,Map一个5G的文件,XmX=64M
map 0~5G& IllegalArgumentException,map的长度不能超过Integer.MAX_VALUE,也就是不能超过2G
map 0~Integer.MAX_VALUE ok
循环,每次map1M,返回的buffer不释放,没有发现限制
有意思的是,第三个参数的类型是long,但是却不允许超过Interger.MAX_VALUE,不知是在其它操作系统下可以,还是给将来留一点余地?
反正现在在Linux64下,是基本够用了。
On some systems, acquiring a mandatory lock on a region of a file prevents that region from being mapped into memory, and vice versa. Programs that combine locking and mapping should be prepared for this combination to fail.
引用MappedByteBuffer是java平台共享内存的实现,把硬盘虚拟为内存,主要用于进程间共享数据,所以在进程没有退出前文件是不允许删除的。
不是这样的,看javadoc,不知道为什么有这么恶心的设计:
引用A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.
浏览: 169778 次
来自: 大连
不错。不错~
map是映射到直接内存,回收比较复杂。用堆内存缓存:
PHP这个基础本身是非持久的,你却硬要做持久层,无异于霸王硬上 ...
orm带来开发上的方便 但是增加性能优化上难度 所以要配合缓存 ...InputStream.read、OutputStream.write、Reader.read、Writer. write区别 - 就只会点Java - ITeye技术网站
博客分类:
InputStream.read()
返回int ,且范围为0到255间int值 ,从输入流读取下一个数据字节,它是以字节为单位来读的,即每次只读取一个字节内容 ,读取后面三前面补三个字节的0,这样读取出来的结果就永远为正,且为0到255间的数。如果因已到达流末尾而没有可用的字节,则返回值-1 。用于进制文件的读取。
如果我们读取的是二进制文件,如图片声音文件时,我们应该使用如下两种方式来读取:第一种 :还是使用InputStream.read(),方法来读取,只不过我们把int型强制转换byte型即可,这样在转换的过程中,会丢弃前三个字节所补的零,最终得到从流中读取的真实的编码。但如果这样直接通过read()方法读取,而不是通过read(byte[] b)时,我们判断流是否结尾,最好使用available()方法来判断,当然也可以使用直接比较读出的结果是否为-1,但是要注意的是我们不能在读取后强转成byte型后再判断,因为二进制文件有可能有-1的编码。
第二种 :使用InputStream.read(byte[] b)来接收,因为这样不会有byte到int提升的过程,byte数组b里存储的就是真实的编码。如果read(byte[] b)读取到流的尾,则返回-1,所以我们直接判断返回的读取子节数就可知道流是否结束。
OutputStream.write(int b)
将指定的字节写入此输出流。write 的规定是:向输出流写入一个字节。要写入的字节是参数b的八个低位。b 的24个高位将被忽略。此方法能向文件中写入负数编码,即可写入二进制流的文件,如声音、图片等文件。
我们再来看看Reader与Writer字符流相应方法:
Reader.read
Reader.read:读取单个字符。在有可用字符、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。范围在 0 到 65535 之间 (0x00-0xffff),实质上读取出来的就是一个char型,即为Unicode编码了。如果已到达流的末尾,则返回 -1
Writer. write(int c)
Writer. write(int c):写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。
从上面可以看出是两类字符流,一种是字节流,另一种是字符流,如果我们读取/写入的是一个二进制文件,则使用字节流InputStream.read/OutputStream.write;如果我们读取/写入的是一个字符文件,则使用字符流Reader.read/Writer.write会很方便,当然字符流也可以使用字节流来操作,只是在某些情况下不是很方便。
import java.io.F
import java.io.FileInputS
import java.io.FileNotFoundE
import java.io.FileOutputS
import java.io.IOE
import junit.framework.TestC
public class TestBinaryStreamReadWrite extends TestCase {
* 写二进制文件(如声音文件)时,只能使用字节流写。outputStream.write方法 只写入最低八位,
* 前三字节会丢弃掉,只存储最后一字节
public void testCreateByteFile() {
FileOutputStream fo = new FileOutputStream("e:/tmp/tmp");
byte b = -1;
//向文件写两个-1,没有编码为-1的字符,所以创建出的文件为纯二进制文件
fo.write(b);
fo.write(b);
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
* InputStream.read方式是读取一个字节内容后,以int型返回,在这之间有一个转换的过程:当读
* 取一个字节内容后,会在这八位二进制前再补24位二进制的0,所以最后返回的字节编码为正数,永不
* 会为负数,且范围为0-255间的整数。这样如果使用read方法读取二进制文件时,读出的编码是整数,
* 原本可能为负编码,最终显示成了正编码。为了确保得到正确的原本二进制编码,在读取后只能强制转
* 换成byte型,或使用read(byte b)方式来读取。
public void testReadEncodeError() {
FileInputStream fi = new FileInputStream("e:/tmp/tmp");
//read方ifc读取的一个字节内容,返回0到255范围内的int字节值,如果因已到达流
//末尾而没有可用的字节,则返回值-1
int readInt = fi.read();
//如果已到达文件末尾,则返回-1。虽然的文件中的每个字节的内容都是-1,但读出来的不是-1,
//所以第二个字节也能输出,而不会出现只能读取第一个字节,第二个字节读不出的问题
while (readInt != -1) {
//输入两个255,但输入的编码是错误的,应该为-1才对
System.out.println(readInt);
//读下一字节
readInt = fi.read();
fi.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
* 使用InputStream.read读取出的编码如果经过强转换byte型后,我们就不能再使用 readByte
* != -1 来判断文件流是否结束了,因为如果为二进制文件,读出的编码就有 为负的,总之,如果读取
* 的是二进制文件,就不能直接使用真实编码与-1比较,只能使用available或通InputStream.read
* (byte[] b)方法返回的所读字节数来判断
public void testAvailable() {
File file =
new File("e:/tmp/tmp");
FileInputStream fi = new FileInputStream(file);
System.out.println("available实质上与file的length相同:" +file.length());
//当使用read方法读取出的编码后经强转byte后,不能使用 (byte) fi.read() != -1 来
//判断是文件流是否结束,这里我们只能使用available来判断是否达文件尾
while (fi.available() & 0) {
System.out.println("available=" + fi.available());
//使用read()方法读取字节内容的编码后,只能强转byte型才能得到真实的编码
System.out.println((byte) fi.read());
fi.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
* 读取二进制文件(如图片)而非字符文件时,除了使用read()读取强转byte型,使用 InputStream.
* read(byte[] b)是最好的方式,此时使用读取返回的字节数来判断是否读完
public void testReadByByteArr() {
FileInputStream fi = new FileInputStream("e:/tmp/tmp");
byte[] byteArr = new byte[1024];
//读取的字节数
int readCount = fi.read(byteArr);
//如果已到达文件末尾,则返回-1
while (readCount != -1) {
for (int i = 0; i & readC i++) {
System.out.println(byteArr[i]);
readCount = fi.read(byteArr);
fi.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
* 使用InputStream.read读取二进制文件强转换byte型获取真实编码后,不能使用readByte !=
* -1 来判断是否到文件尾
public void testGetBytecodeByConvernt() {
FileInputStream fi = new FileInputStream("e:/tmp/tmp");
//读取的一个字节内容,强制转byte型,得到真实的编码
byte readByte = (byte) fi.read();
//这里我们不能使用如下方式来判断是否读流结束,因为编码内容本身就是-1,所以不会输出任何内容
while (readByte != -1) {
System.out.println((byte) readByte);
readByte = (byte) fi.read();
fi.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
很不理解明明是byte和char为什么api非要用int类型返回,究竟是出于哪种考虑呢?因为文件的传输会打成字节流,流就是0和1,的类型就不就是char或者是byte,不然还有什么类型可以匹配它的类型呢?你觉得呢?
junJZ_2008
浏览: 659980 次
来自: 湖南澧縣
log4j的功能很强大,这篇文章讲解的很详细:[url] ht ...
log4j的功能很强大,这篇文章讲解的很详细:[url= ht ...
希望能看到楼主更好的作品,,谢 ...
总结的非常不错,赞InputStream中read()与read(byte[] b) - 刘文涛 - ITeye技术网站
博客分类:
read()与read(byte[] b)这两个方法在抽象类InputStream中前者是作为抽象方法存在的,后者不是,JDK API中是这样描述两者的:
1:read() :
从输入流中读取数据的下一个字节,返回0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回-1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
2:read(byte[] b) :&
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。如果 b 的长度为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。将读取的第一个字节存储在元素 b[0] 中,下一个存储在 b[1] 中,依次类推。读取的字节数最多等于 b 的长度。设 k 为实际读取的字节数;这些字节将存储在 b[0] 到 b[k-1] 的元素中,不影响 b[k] 到 b[b.length-1] 的元素。
由帮助文档中的解释可知,read()方法每次只能读取一个字节,所以也只能读取由ASCII码范围内的一些字符。这些字符主要用于显示现代英语和其他西欧语言。而对于汉字等unicode中的字符则不能正常读取。只能以乱码的形式显示。
对于read()方法的上述缺点,在read(byte[] b)中则得到了解决,就拿汉字来举例,一个汉字占有两个字节,则可以把参数数组b定义为大小为2的数组即可正常读取汉字了。当然b也可以定义为更大,比如如果b=new byte[4]的话,则每次可以读取两个汉字字符了,但是需要注意的是,如果此处定义b 的大小为3或7等奇数,则对于全是汉字的一篇文档则不能全部正常读写了。
下面用实例来演示一下二者的用法:
实例说明:类InputStreamTest1.java 来演示read()方法的使用。类InputStreamTest2.java来演示read(byte[] b)的使用。两个类的主要任务都是通过文件输入流FileInputStream来读取文本文档xuzhimo.txt中的内容,并且输出到控制台上显示。
先看一下xuzhimo.txt文档的内容
InputStreamTest1.java
/**
* User: liuwentao
* Time: 12-1-25 上午10:11
public class InputStreamTest1 {
public static void main(String[] args){
String path = "D:\\project\\opensouce\\opensouce_demo\\base_java\\classes\\demo\\java\\inputstream\\";
File file = new File(path + "xuzhimo.txt");
InputStream inputStream =
inputStream = new FileInputStream(file);
while ((i = inputStream.read())!=-1){
System.out.print((char)i + "");
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
执行结果:
如果将while循环中的 (char)去掉,即改成:
引用 System.out.print(i + "");
则执行结果:
InputStreamTest2.java
/**
* User: liuwentao
* Time: 12-1-25 上午10:11
public class InputStreamTest2 {
public static void main(String[] args){
String path = "D:\\project\\opensouce\\opensouce_demo\\base_java\\src\\demo\\java\\inputstream\\";
File file = new File(path + "xuzhimo.txt");
InputStream inputStream =
inputStream = new FileInputStream(file);
byte[] bytes = new byte[16];
while ((i = inputStream.read(bytes))!=-1){
String str = new String(bytes);
System.out.print(str);
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
执行结果:
遗憾的是,还是有乱码,解决办法可以参见下面教程
修改后的代码:
/**
* User: liuwentao
* Time: 12-1-25 上午10:11
public class InputStreamTest3 {
public static void main(String[] args) {
String path = "D:\\project\\opensouce\\opensouce_demo\\base_java\\src\\demo\\java\\inputstream\\";
File file = new File(path + "xuzhimo.txt");
InputStream inputStream =
StringBuffer stringBuffer = new StringBuffer();
//InputStream :1)抽象类,2)面向字节形式的I/O操作(8 位字节流) 。
inputStream = new FileInputStream(file);
//Reader :1)抽象类,2)面向字符的 I/O操作(16 位的Unicode字符) 。
Reader reader = new InputStreamReader(inputStream, "UTF-8");
//增加缓冲功能
BufferedReader bufferedReader = new BufferedReader(reader);
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line);
if (bufferedReader != null) {
bufferedReader.close();
String content = stringBuffer.toString();
System.out.print(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
执行结果:
还是遗憾,没有换行。
解决办法,通过 commons-io-*.jar
/**
* User: liuwentao
* Time: 12-1-25 上午10:11
public class InputStreamTest4 {
public static void main(String[] args) {
String path = "D:\\project\\opensouce\\opensouce_demo\\base_java\\src\\demo\\java\\inputstream\\";
File file = new File(path + "xuzhimo.txt");
String content =
content = FileUtils.readFileToString(file, "utf-8");
} catch (IOException e) {
e.printStackTrace();
System.out.println("content:" + content);
执行结果:
浏览: 493320 次
来自: 北京
&div class=&quote_title ...
可是怎么没有后续了》
是哪本书啊?
收藏 了,呵呵。
您好在第五步创建简单的java工程报错了[ERROR] Fai ...当前位置: >
> 怎么将inputStream写入一个byte[]
怎么将inputStream写入一个byte[]
qzy1234 & at
如何将inputStream写入一个byte[]InputStream方法提供了read(byte[] & b)方法将其内容写入一个byte数组,但是我事先不能知道这个数组的长度,我应该如何将InputStream里面的内容完全写入一个数组中呢?
不知道为什么非要写到一个数组中,你是什么需求
qzz314 & &
& & (0)(0)InputStream.available()就是数组的长度!!
qzyuanmu & &
& & (0)(0)正好有一个这样的类
import java.io.ByteArrayOutputS
import java.io.F
import java.io.FileInputS
import java.io.FileNotFoundE
import java.io.FileOutputS
import java.io.IOE
import java.io.InputS
import java.io.OutputS
public class FileByteUtil {
public static void main(String[] args) throws Exception {
File file=new File( &f:/test.doc &);
byte[] fileByte = file2byte(file);
byte2file(fileByte,
&f:/test2.doc &);
public static byte[] file2byte(File f) throws Exception {
return file2byte(f.getPath());
public static byte[] file2byte(String f) throws Exception {
InputStream in = new FileInputStream(f);
byte[] tmp = new byte[512];
ByteArrayOutputStream out = new ByteArrayOutputStream();
int bytesRead = in.read(tmp);
while (bytesRead != -1) {
out.write(tmp, 0, bytesRead);
bytesRead = in.read(tmp);
return out.toByteArray();
} catch (Exception e) {
e.printStackTrace();
// writes byte [] to a file
public static void byte2file(byte[] data, String fn) throws Exception {
OutputStream out = new FileOutputStream(fn);
out.write(data);
out.flush();
} catch (FileNotFoundException e) {
} catch (IOException e) {
qzzhua & &
& & (0)(0)int len = in.available();
byte b = new byte[len];
in.read(b);qzyuer & &
& & (0)(0)
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&&&湘教QS2-164&&增值电信业务经营许可证湘B2-}

我要回帖

更多关于 byteinputstream 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信