【问题标题】:Java BufferedInputStream.read() IndexOutOfBoundsJava BufferedInputStream.read() IndexOutOfBounds
【发布时间】:2012-03-14 11:21:09
【问题描述】:

我想编写一个将文件中的一部分读入字节数组的方法。 为此,我正在使用文件输入流和缓冲输入流。

像这样:

fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);

我只通过调用方法名称“OpenFile(String File)”来执行此操作一次。 使用此方法打开文件后,我尝试使用以下函数进行操作:“ReadParts(byte[] buffer, int offset, int len)”

dis.read(buffer, offset, len);            
for(int i = 0; i < buffer.length; i++) System.out.print((char)buffer[i]);

// used data:
// file = "C:\Temp\test.txt" with a size of 949
// buffer: always in this case with a size of 237, except for the last one its 238
// offsets: 0, 237, 474, 711 
// len is always 237, except for the last one its 238

在第一步之后 dis.read() 行总是抛出一个 indexOutOfBounds 错误消息,但我不知道为什么和什么。使用 netbeans 调试器没有帮助,因为我找不到索引的问题.....

【问题讨论】:

  • 请在计算偏移量和长度以及初始化缓冲区的位置发布代码。这很可能会导致您的问题。

标签: java java-io bufferedinputstream datainputstream


【解决方案1】:

如果您将 Stream 读入缓冲区数组,您的偏移量和 len 将始终为:

offset = 0;
len = buffer.length();

这些参数指定将数据放入缓冲区的位置,而不是从 Stream 中读取哪些数据。 Stream 是连续读取的(或者无论如何拼写?)!

如果你总是打电话:

buffer = new byte[256];
dis.read(buffer, 0, 256);

这将发生: 在第一次调用之前,Streamposition(返回的下一个字节的位置)为 0。

  1. 调用后的流位置=256,缓冲区包含字节 0-255
  2. 调用后的流位置=512 并且缓冲区包含字节 256-511
  3. ...

    dis.reset();

Streamposition 再次为 0。

此代码仅将字节 256-511 从 Stream 读取到缓冲区中:

byte[] buffer = new byte[512];
dis.skip(256);
dis.read(buffer, 0, 256);

请注意缓冲区的最后 256 个字节未填充。这是 read(byte[], int, int) 和 read(byte[]) 的区别之一!

这里有一些链接描述了流的概念和读取方法的使用: read() Streams

【讨论】:

  • 那么为什么还要使用 read(byte, off, len) 函数呢? read(byte[]) 会做同样的工作 -> offset = 0 和 len = byte.length。这意味着它读取整个文件。我的计划是从文件中读取部分而不是整个文件。同样,我计划(在本例中)从 237 读取到 474。这是 236 字节。所以如果缓冲区长 237 就足够了。我只是没有得到偏移量(> = 0)和偏移量+ len(对于缓冲区大小)之间的连接....
  • 如果要将读取的字节放在缓冲区的特殊位置,请使用 read(byte, offset, len)。如果您只想从流中读取一些而不是所有字节,则必须使用 skip()。如果您在流中使用带有绝对偏移量的跳过,如果之前从该流中读取过某些内容,您也必须调用 reset()。
  • 我这样做是为了跳过空字节: for (int i = 0; i
【解决方案2】:

你是怎么想出偏移量和长度的。我现在的猜测是你 offset + len 大于缓冲区。

【讨论】:

  • 好吧,这是我现在不明白的问题吗?关于文档: dis.read(b, off, len): b - 读取数据的缓冲区。 off - 数据的起始偏移量。 len - 读取的最大字节数。所以我必须更改缓冲区才能获取字节 238 到 474? (在这种情况下 237 就足够了?!)
【解决方案3】:

你会得到 IndexOutOfBoundsException - If

  • 偏移量为负,

  • len 为负数,

  • len 大于 buffer.length - 关闭

第 3 点示例:

如果输入文件有500个字符或者1500个字符,下面的程序就会运行成功,

byte[] buffer = new byte[1000];
int offset = 0;
int len = 1000;
dis.read(buffer, offset, len);            
for(int i = 0; i < buffer.length; i++) System.out.print((char)buffer[i]);

但是如果,它会失败并抛出异常,

byte[] buffer = new byte[1000];
int offset = 0;
int len = 1001;
dis.read(buffer, offset, len); 
for(int i = 0; i < buffer.length; i++) System.out.print((char)buffer[i]);

检查两种情况下的长度值。

【讨论】:

  • 是的,但这意味着如果我想从字节 237 读取到 474,我需要更大的缓冲区,即使“真实”字节大小是 236??
【解决方案4】:

偏移量是缓冲区而不是文件中的偏移量。

我怀疑你想要的是什么

byte[] buffer = new byte[237];

int len = dis.read(buffer); // read another 237 bytes.

if (len < 0) throw new EOFException(); // no more data.
for(int i = 0; i < len; i++)
   System.out.print((char)buffer[i]);
// or
System.out.print(new String(buffer, 0, 0, len));

在您的调试器中,您能否检查偏移量 >= 0 和偏移量 + 长度

来自 InputStream.read()

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();

检查的条件之一无效。

【讨论】:

  • offset 是 237,len 也是 237。所以bufferlengh是237。它不是用237的len计算在offsetnum上吗?异常不包含任何细节,或者我无法提取细节......:/(当我使用 ex.getCause() 时,我会得到一个空指针异常)
  • 这么说,我必须提高缓冲区,即使我只想在第二步中读取 237 个字节(从文件中读取 237 到 474)需要双倍缓冲区?对吗?
  • 不,看我的帖子。你在滥用 offset 和 len。
  • @TonyB 如果您从位置 237(偏移)读取 237(长度)字节,则缓冲区(字节 b[])至少需要 474 字节长。
  • @AlexS:您的帖子在某种程度上不是我所要求的,只有当我想从 0 开始到缓冲区的长度时,您的示例才存在。 Peter Lawrey 做对了……不知何故(在我看来)它有点不合逻辑,因为缓冲区会比读取的字节长……但是好吧,我会试一试。谢谢彼得。
猜你喜欢
  • 2012-09-14
  • 2015-02-15
  • 2023-04-11
  • 1970-01-01
  • 2013-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多