如何使用Java/Scala从URL加载前x个字节?

dea*_*mon 0 java url scala urlconnection

我想从a读取前x个字节java.net.URLConnection(虽然我不是被迫使用这个类 - 欢迎其他建议).

我的代码看起来像这样:

val head = new Array[Byte](2000)  
new BufferedInputStream(connection.getInputStream).read(head)
IOUtils.toString(new ByteArrayInputStream(head), charset)
Run Code Online (Sandbox Code Playgroud)

它工作,但这个代码只加载网络的前2000个字节?

下一次试验

由于'JB Nizet'说使用缓冲输入流是没用的,所以我试了一下InputStreamReader:

val head = new Array[Char](2000)  
new InputStreamReader(connection.getInputStream, charset).read(head)
new String(head)
Run Code Online (Sandbox Code Playgroud)

此代码可能更好,但加载时间大致相同.那么这个程序是否限制了传输的字节?

JB *_*zet 7

不,它没有.它最多可读取8192个字节(deault缓冲区大小BufferedInputStream).它还可以读取0个字节或0到2000之间的任意数量的字节,因为您不检查实际已读取的字节数,以及该方法返回的字节数read().

最后,根据charset的值以及HTTP响应使用的实际字符集,这可能会返回一个不正确的字符串,或者在多字节字符中间截断的字符串.您应该使用Reader来阅读文本.

我建议你阅读Java IO教程.

  • 为什么要缓冲流,因为您确切地知道要读取多少字节,并一次性读取它们(如果可用)? (2认同)

Pet*_*lák 5

您可以使用read(Reader, char[])Apache Commons IO.只需将一个2000个字符的缓冲区传递给它,它将填充尽可能多的字符,最多2000个.

请务必了解其他答案/评论中的异议,特别是:

  • 不要使用Buffered...包装纸,这违背了你的意图.
  • 如果您阅读文本数据,则使用a Reader来读取2000个字符而不是InputStream读取2000 个字节.正确的过程是从response(Content-Type)的头部确定字符编码并将该编码设置为InputStreamReader.
  • read(char[])在a上调用plain Reader将无法完全填充您提供给它的数组.无论阵列有多大,它都可以读取一个字符!
  • 之后不要忘记关闭阅读器.

除此之外,我强烈推荐你使用Apache的HttpClient的支持java.net.URLConnection.它更加灵活.


编辑:要理解之间的区别Reader.readIOUtils.read,这是值得研究的,后者的来源:

public static int read(Reader input, char[] buffer,
                       int offset, int length)
    throws IOException
{
    if (length < 0) {
        throw new IllegalArgumentException("Length must not be negative: " + length);
    }
    int remaining = length;
    while (remaining > 0) {
        int location = length - remaining;
        int count = input.read(buffer, offset + location, remaining);
        if (EOF == count) { // EOF
            break;
        }
        remaining -= count;
    }
    return length - remaining;
}
Run Code Online (Sandbox Code Playgroud)

因为Reader.read可以读取比给定长度更少的字符(我们只知道它至少为1,最多只有长度),我们需要迭代调用它直到得到我们想要的数量.