简体   繁体   English

(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

I'm using Apache HttpClient 4.5 , trying to download a 2.4 MB file . 我正在使用Apache HttpClient 4.5 ,试图下载2.4 MB的文件 File is available and fully downloadable in Chrome. 文件在Chrome中可用并且可以完全下载。

Problem is, InputStream is returned by entity.getContent() contains only 8192 bytes of buffer, and is.available() returns 7748. Private filed contentLength of is is 2488649, which should be the desired file size, so I don't understand what the problem is. 问题是, InputStream is由归国entity.getContent()只包含8192字节的缓冲区,并is.available()返回7748.私人提起contentLengthis为2488649,这应该是所需的文件大小,所以我不明白问题是什么。 All buffer sizes that I found in Variables module of Debug are 8192. 我在“调试”的“变量”模块中找到的所有缓冲区大小均为8192。

I have tried to replace the is on-the-spot with FileInputStream targeting the same file on my computer. 试图取代 is在现场用FileInputStream瞄准我的电脑上相同的文件。 It transferred perfectly, all 2.4 MB. 传输完美,全部2.4 MB。 So I suppose I'm doing something wrong with http utils configuration. 所以我想我在http utils配置上做错了什么。

Please help me fix this. 请帮我解决这个问题。 The code seems a bit long but it should be easy to comprehend. 该代码似乎有点长,但是应该很容易理解。

CommRunnable. CommRunnable。 Base class for the class below: 下面的类的基类:

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

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

GetFileRunnable. GetFileRunnable。 Running in separate thread. 在单独的线程中运行。 Initiates the connection and the file transfer: 启动连接和文件传输:

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. HttpPostAgent。 Basically a controller for Apache http utilities. 基本上是Apache http实用程序的控制器。 Methods are described in comments above them. 方法在其上方的注释中进行了描述。

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...//
}

Please tell me if I should add any more information. 请告诉我是否应该添加更多信息。

From the Javadoc of InputStream.available() : 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. 返回可以从此输入流读取(或跳过)而不会被该输入流的方法的下一次调用阻塞的字节数的估计值。

So the available bytes are not the total input bytes, but the first chunk of bytes which have been buffered when you start reading the input. 因此,可用字节不是总输入字节,而是开始读取输入时已缓冲的第一个字节块。 8192 seems to be the buffer size in your example. 8192似乎是您的示例中的缓冲区大小。

Therefore your HttpPostAgent.transfer method effectively only handles the first 8192 bytes and then stops. 因此,您的HttpPostAgent.transfer方法仅有效处理前8192个字节,然后停止。

Can you try the following replacement for the HttpPostAgent.transfer method? 您可以尝试使用以下替代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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM