读取jar包中的文件的诡异问题

jlabel 2008-11-09 11:48:10
我将类打成jar包将资源也放到jar包中的res目录下.
我用方式一读取文件能够正常把整个文件读入数组 b 中
方式一:
InputStream is = this.getClass().getResourceAsStream("/res/a.jpg");
byte[] b = new byte[is.available()];
for(;is.available()>0;i++){
b[i] = (byte)is.read();
}
ImagIcon image = new ImageIcon(b);



用方式二读取文件只能将文件的前一部分读入数组 b 中导致创建ImageIcon时出错
方式二:
InputStream is = this.getClass().getResourceAsStream("/res/a.jpg");
byte[] b = new byte[is.available()];
is.read(b);
ImagIcon image = new ImageIcon(b);


我看到有人说不能用getResourceAsStream()方法读取jar包中的数据不知道这种说法正确吗?

当然用这种方式一和这个
ImageIcon image = new ImageIcon(this.getClass().getResource("/res/a.png"));
能够正常运行.

有没有人遇到从jar包中读取资源的问题?
方式二为什么只能读取前一部分数据到数组中呢?
...全文
632 60 打赏 收藏 转发到动态 举报
写回复
用AI写文章
60 条回复
切换为时间正序
请发表友善的回复…
发表回复
Friend_NO1 2008-12-16
  • 打赏
  • 举报
回复
路过了!
jlabel 2008-12-16
  • 打赏
  • 举报
回复
没有太满意的答案,就这样吧,很长时间了.
估计就是54 56楼说的那个问题.
jlabel 2008-12-15
  • 打赏
  • 举报
回复
看来只能这样啦,准备结贴啦.
littlepboy 2008-12-11
  • 打赏
  • 举报
回复
lz,返回的len只要不是-1,就说明没有读完,这个read的方法没有保证一定可以读完。
你的情况是读到中途的时候就出现IO异常了。该方法也说了,建议子类提供此方法更为有效的实现,
所以不建议直接来用这个方法。

引用
public int read(byte[] b,
int off,
int len)
throws IOException将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。
在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。

如果 len 为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。

将读取的第一个字节存储在元素 b[off] 中,下一个存储在 b[off+1] 中,依次类推。读取的字节数最多等于 len。设 k 为实际读取的字节数;这些字节将存储在 b[off] 到 b[off+k-1] 的元素中,不影响 b[off+k] 到 b[off+len-1] 的元素。

在任何情况下,b[0] 到 b[off] 的元素以及 b[off+len] 到 b[b.length-1] 的元素都不会受到影响。

类 InputStream 的 read(b, off, len) 方法重复调用方法 read()。如果第一次这样的调用导致 IOException,则从对 read(b, off, len) 方法的调用中返回该异常。如果对 read() 的任何后续调用导致 IOException,则捕获该异常并将其视为到达文件末尾;到达该点时读取的字节存储在 b 中,并返回发生异常之前读取的字节数。在已读取输入数据 len 的请求数量、检测到文件结束标记、抛出异常前,此方法的默认实现将一直阻塞。建议子类提供此方法更为有效的实现。


参数:
b - 读入数据的缓冲区。
off - 数组 b 中将写入数据的初始偏移量。
len - 要读取的最大字节数。
返回:
读入缓冲区的总字节数;如果因为已到达流末尾而不再有数据可用,则返回 -1。
抛出:
IOException - 如果不是因为位于文件末尾而无法读取第一个字节;如果输入流已关闭;如果发生其他 I/O 错误。
NullPointerException - 如果 b 为 null。
IndexOutOfBoundsException - 如果 off 为负,len 为负,或者 len 大于 b.length - off
leo_bogard 2008-12-11
  • 打赏
  • 举报
回复
up
HuanxueOrSeaty 2008-12-11
  • 打赏
  • 举报
回复
学习了
hbwhwang 2008-12-10
  • 打赏
  • 举报
回复
public int read(byte b[], int off, int len) throws IOException 方法的JAVADOC说得很清楚:

Reads up to len bytes of data from the input stream into
an array of bytes. An attempt is made to read as many as
len bytes, but a smaller number may be read.
The number of bytes actually read is returned as an integer.

它没有保证读得跟你要求的len一样长
它只不过尝试attempt 读得跟len一样长
你还是得关注实际读的长度actually read
jlabel 2008-12-10
  • 打赏
  • 举报
回复
试验了多个文件
发现InputStream.read(byte[]) 就是有问题.
但是不知道是那里的问题.
chaorenwopashei 2008-12-04
  • 打赏
  • 举报
回复
太难了看不懂么不知道是怎么回事啊,
jlabel 2008-12-04
  • 打赏
  • 举报
回复
现在不是在讨论is.available()方法了 这个我不用了,现在是在讨论

1、我用for循环一个一个byte读能读完整个文件,像这样


for(;is.available()>0;i++){
int m = is.read();
b[i] = (byte) m;
}


2、根据我发的read(byte[],int,int)的源代码


public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}

int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;

int i = 1;
try {
for (; i < len ; i++) {
c = read(); //循环读取
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) { //估计是这里有异常抛出
}
return i;
}


这里面也是用循环读取的,所以我调用这个方法应该返回和我自己用for循环读取一样的结果.
但是返回的比我用for循环读取的要少

请看下面的例子 我把大家有争议的available()方法去了.


InputStream is = this.getClass().getResourceAsStream("/res/a.jpg");
System.out.println("文件大小/is.available():"+is.available());
int length = 30000;

byte[] b = new byte[length];
int i = 0;
for(;is.available()>0;i++){
int m = is.read();
b[i] = (byte) m;
}
System.out.println("用For循环读取字节数为: "+i);

System.out.println("--------用read(byte[])方法读取-------------------");
is = this.getClass().getResourceAsStream("/res/a.jpg");
b = new byte[length];
i = is.read(b);
System.out.println("用read共读取字节数为: "+i);


System.out.println("--------用read(byte[],int,int)方法读取-----------");
is = this.getClass().getResourceAsStream("/res/a.jpg");
BufferedInputStream bis = new BufferedInputStream(is);

b = new byte[length];
i = bis.read(b,0,b.length);
System.out.println("用read(b,int,int)共读取字节数为: "+i);



这个不打jar包输出的结果为:

文件大小/is.available():27446
用For循环读取字节数为: 27446
--------用read(byte[])方法读取-------------------
用read共读取字节数为: 27446
--------用read(byte[],int,int)方法读取-----------
用read(b,int,int)共读取字节数为: 27446

打成jar包后运行输出的结果为:

文件大小/is.available():27446
用For循环读取字节数为: 27446
--------用read(byte[])方法读取-------------------
用read共读取字节数为: 8497
--------用read(byte[],int,int)方法读取-----------
用read(b,int,int)共读取字节数为: 27446

看这个结果奇怪吧!!!

read(byte[]) 调用的就是 read(byte[],int,int) 而我自己调用返回的结果却不同?
各位再关注一下.
老紫竹 2008-12-04
  • 打赏
  • 举报
回复
for(;is.available()>0;i++){


你为何还在用这个方法,我无语。。。

你应该用返回值判断是否结束,而不是依赖于 available

至于为什么?自己去看API的说明吧。

if (c == -1) {
break;
}

这是jdk里面判断是否读取结束的方法,你自己看
jlabel 2008-12-04
  • 打赏
  • 举报
回复
郁闷,不能删自己的帖子,上一个回复(51楼)写错了.请大家忽略!

byte[] b = new byte[length];
int i = 0;
int c = -1;
while((c = is.read())!=-1){//不考虑性能等其它事情.
b[i++] = (byte)c;
}
System.out.println("用while循环读取字节数为: "+i);
//文件大小/is.available():27446
//用while循环读取字节数为: 27446

System.out.println("\n--------用read(byte[])方法读取-------------------");
is = this.getClass().getResourceAsStream("/res/a.jpg");
b = new byte[length];
i = is.read(b);
System.out.println("用read共读取字节数为: "+i);
//--------用read(byte[])方法读取-------------------
//用read共读取字节数为: 8497


while循环和read(byte[])方法内部类似吧?
为什么while可以读取的27446,而read(byte[]) 只可以读取8497


不用再关注available了 呵呵.
jlabel 2008-12-04
  • 打赏
  • 举报
回复
[Quote=引用 49 楼 java2000_net 的回复:]
for(;is.available()>0;i++){


你为何还在用这个方法,我无语。。。

你应该用返回值判断是否结束,而不是依赖于 available

至于为什么?自己去看API的说明吧。

if (c == -1) {
break;
}

这是jdk里面判断是否读取结束的方法,你自己看
[/Quote]

for(;is.available()>0;i++){ 这个只是一个例子当时随便写的 我只是把后面两种方法的available方法去掉了.

我改成这样:
int i= 0;
int c = -1;
while((c = is.read())!=-1){
b[i++] = (byte)c;
}

后面的结果也不对呀?


InputStream is = this.getClass().getResourceAsStream("/res/a.jpg");
System.out.println("文件大小/is.available():"+is.available());
int length = 30000;

byte[] b = new byte[length];
int i = 0;
int c = -1;
while((c = is.read())!=-1){ //只是例子没有优化.
b[i++] = (byte)c;
}
System.out.println("用while循环读取字节数为: "+i);

//文件大小/is.available():27446
//用while循环读取字节数为: 27446


System.out.println("\n--------用read(byte[])方法读取-------------------");
is = this.getClass().getResourceAsStream("/res/a.jpg");
//-------------------重点看这里!!!!!----------------
b = new byte[length];
i = is.read(b);
System.out.println("用read共读取字节数为: "+i);

//--------用read(byte[])方法读取-------------------
//用read共读取字节数为: 8497


System.out.println("\n--------用read(byte[],int,int)方法读取-----------");
is = this.getClass().getResourceAsStream("/res/a.jpg");
BufferedInputStream bis = new BufferedInputStream(is);
//-------------------重点看这里!!!!!----------------
b = new byte[length];
i = bis.read(b,0,b.length);
System.out.println("用read(b,int,int)共读取字节数为: "+i);

//--------用read(byte[],int,int)方法读取-----------
//用read(b,int,int)共读取字节数为: 27446



重点看后面两个例子的输出read(byte[]) 方法是调用的return read(b, 0, b.length)这个但是这两个方法的输出为什么不同?
一个输出的是
--------用read(byte[])方法读取-------------------
用read共读取字节数为: 8497


另一个输出的是

--------用read(byte[],int,int)方法读取-----------
用read(b,int,int)共读取字节数为: 27446



不用再关注available了 呵呵.
海会圣贤 2008-12-03
  • 打赏
  • 举报
回复
方式二是不是大小不够啊?
老紫竹 2008-12-03
  • 打赏
  • 举报
回复
is.available()
我真的不记得这个代表里面数据的长度,这个应该是已经准备好的数据,而不是总数据量,否则
如果你读取一个100G的文件,难道你要分配100G的数组啊?那还叫Stream吗?
所以应该有一点,读一点,所以第一个循环是正确的,不过还是有点....
byte[] bs = new byte[1024];
int len;
while((len = is.read(bs))!=-1){
....
我更推荐这样读取Stream的数据,自己控制缓冲区
yyinin 2008-12-03
  • 打赏
  • 举报
回复
//学习
getter 2008-12-02
  • 打赏
  • 举报
回复
available()寫明:
Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream.
不是其值不是文件的大小
而inputstream中的read()方法都是盡量方法,不保證是會一次讀滿整個buf的,你給出的源代碼就是證明
leo_bogard 2008-12-02
  • 打赏
  • 举报
回复
up
jlabel 2008-12-01
  • 打赏
  • 举报
回复
顶一下.
西瓜 2008-11-30
  • 打赏
  • 举报
回复
没玩过
加载更多回复(40)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧