(java) HttpEntity.getContent() 输出有限的 InputStream (8192b / 7748b) ...我正在尝试下载一个 2.4MB 的文件

(java) HttpEntity.getContent() outputs limited InputStream (8192b / 7748b) ... I'm trying to download a 2.4MB file

我正在使用 Apache HttpClient 4.5,尝试下载 2.4 MB 文件文件可用且可完全下载 Chrome。

问题是,entity.getContent() 返回的 InputStream is 仅包含 8192 字节的缓冲区,而 is.available() returns 7748. contentLength 的私有字段 is是2488649,应该是想要的文件大小,所以没看懂是什么问题。我在 Debug 的 Variables 模块中找到的所有缓冲区大小都是 8192。

我已经 尝试用 FileInputStream 替换 现场 is 以我计算机上的相同文件为目标。 传输完美,全部 2.4 MB。所以我想我在 http utils 配置上做错了。

请帮我解决这个问题。代码好像有点长,但是应该很容易看懂。

CommRunnable。以下 class 的基础 class:

public abstract class CommRunnable implements Runnable {
    protected HttpPostAgent agent;
    protected boolean success;

    //...additional methods...//
}

GetFileRunnable。 运行 在单独的线程中。启动连接和文件传输:

public class GetFileRunnable extends CommRunnable implements Runnable {
    private String url;
    private String fileDestination;
    private NameValuePair[] postPairs;

    //...constructor...//

    public void run() 
    {
        synchronized (agent) {
            try {
                HttpClient client = HttpClients.createDefault();

                HttpResponse response = agent.getHttpResponse(client, url, postPairs);

                InputStream is = response.getEntity().getContent();
                FileOutputStream fos = new FileOutputStream(fileDestination);

                success = agent.transfer(is, fos);

                client.getConnectionManager().shutdown();

            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("IOException in HttpPostAgent.getFile");
            } finally {
                agent.setFree(true);
            }
        }
    }
}

HttpPostAgent。基本上是 Apache http 实用程序的控制器。方法在上面的注释中进行了描述。

public class HttpPostAgent {
    private int statusPerc;
    private boolean free;

    private Thread thread;
    private CommRunnable currentAction;

    //...constructor...//

    //executes POST request and returns resulting HttpResponse
    HttpResponse getHttpResponse(HttpClient client, String url, NameValuePair... postPairs)
    {
        try {
            List <NameValuePair> nvps = new ArrayList <NameValuePair>();

            for (NameValuePair pair : postPairs)
                nvps.add(pair);

            HttpPost post = new HttpPost(url);
            post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));

            return client.execute(post);

        } catch (IOException e) {
            throw new RuntimeException("IOException in getHttpResponse(HttpClient client, String url, NameValuePair... postPairs)");
        }
    }

    //...methods...//

    //Starts thread with GetFileRunnable. Included here for Your understanding of my context.
    public void getFileInit(String url, String destinationPath, NameValuePair... postPairs)
    {
        free = false;
        statusPerc = 0;
        currentAction = new GetFileRunnable(this, url, destinationPath, postPairs);
        thread = new Thread(currentAction);
        thread.setPriority(Thread.MIN_PRIORITY);
        thread.setDaemon(true);
        thread.start();
    }

    //...methods...//

    //Transfers a file from one input stream to the other. For downloading from response/entity/content.
    boolean transfer(InputStream is, OutputStream os)
    {
        boolean success = false;

        try {
            int remain = is.available();
            int total = remain;
            int read = 0;
            int chunk = 1024;
            byte[] buffer = new byte[chunk];

            while(remain > 0)
            {
                if(chunk > remain) chunk = remain;

                os.flush();
                is.read(buffer, 0, chunk);
                os.write(buffer, 0, chunk);

                remain -= chunk;
                read += chunk;

                synchronized (this) {
                    statusPerc = (read * 100) / total;
                }
            }
            remain = is.available();

            success = true;

        } catch (IOException e) {
            throw new RuntimeException("IOException in HttpPostAgent.transfer");
        } 

        return success;
    }

    //...methods...//
}

请告诉我是否应该添加更多信息。

来自 InputStream.available() 的 Javadoc:

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.

因此可用字节不是总输入字节,而是开始读取输入时缓冲的第一个字节块。 8192 似乎是您示例中的缓冲区大小。

因此,您的 HttpPostAgent.transfer 方法实际上只处理了前 8192 个字节,然后就停止了。

您可以尝试使用以下方法替换 HttpPostAgent.transfer 方法吗?

boolean transfer(InputStream is, OutputStream os) throws IOException
{
    byte buffer[] = new byte[2048];
    int count;
    while ((count = is.read(buffer)) != -1)
        os.write(buffer, 0, count);
}