有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在从URL(使用http连接)下载的过程中检索文件的大小?

我正在做一个项目,通过http连接下载一个文件。我在下载过程中显示一个水平进度条,其中包含进度条状态。 我的函数如下所示:

.......
try {           
        InputStream myInput = urlconnect.getInputStream();
        BufferedInputStream buffinput = new BufferedInputStream(myInput);

        ByteArrayBuffer baf = new ByteArrayBuffer(capacity);
        int current = 0;
        while((current = buffinput.read()) != -1) {
            baf.append((byte) current);
        }
File outputfile = new File(createRepertory(app, 0), Filename);
        FileOutputStream myOutPut = new FileOutputStream(outputfile);
        myOutPut.write(baf.toByteArray());
...
}

我预先知道文件的大小,因此需要在下载过程中检索文件的大小(在我的while块中)。因此,我将能够确定进度条的状态

progressBarStatus = ((int) downloadFileHttp(url, app) * 100)/sizefile;

长下载文件http(…,…)是我函数的名称

我已经尝试使用outputfile检索它。长度,但他的值是“1”,可能是我要下载的文件数

Is there any way to figure it out?

更新1

I haven't got any thread which allow me to figure this out. Currently I have got a horizontal progress bar whch displays only 0 and 100% whitout intermediate values. I think about another approach. If I know the rate of my wifi and the size of the file I can determinate the time of downloading.

I know that I can retrieve the piece of information of my Wifi connection and the size of my file to download.

Is anybody already have worked or have thread on it?


共 (6) 个答案

  1. # 1 楼答案

    AsyncTask可能是最适合您的解决方案:

    private class DownloadFileTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
        Url url = urls[0];
        //connect to url here
        .......
        try {           
            InputStream myInput = urlconnect.getInputStream();
            BufferedInputStream buffinput = new BufferedInputStream(myInput);
    
            ByteArrayBuffer baf = new ByteArrayBuffer(capacity);
            int current = 0;
            while((current = buffinput.read()) != -1) {
                baf.append((byte) current);
                //here you can send data to onProgressUpdate
                publishProgress((int) (((float)baf.length()/ (float)sizefile) * 100));
            }
        File outputfile = new File(createRepertory(app, 0), Filename);
        FileOutputStream myOutPut = new FileOutputStream(outputfile);
        myOutPut.write(baf.toByteArray());
        ...
     }
    
     protected void onProgressUpdate(Integer... progress) {
         //here you can set progress bar in UI thread
         progressBarStatus = progress;
     }
    

    }

    在方法中启动AsyncTask调用

    new DownloadFileTask().execute(url);
    
  2. # 2 楼答案

    简单。以下代码:

    try {
        URL url = new URL(yourLinkofFile);
        URLConnection conn = url.openConnection();
        conn.connect();
        totalFileSize = conn.getContentLength();
    } catch (Exception e) {
        Log.e(TAG, "ERROR: " + e.toString());
    }
    
  3. # 3 楼答案

    我假设你正在使用HttpURLConnection。在这种情况下,需要在urlconnect上调用getContentLength()方法

    但是,服务器不需要发送有效的内容长度,因此您应该准备将其设置为-1

  4. # 4 楼答案

    听起来您的主要问题不是获取文件的长度或计算实际值,而是如何从另一个线程访问当前值,以便适当地更新状态栏

    有几种方法可以解决这个问题:

    1.)在进度条项中有一个回调函数,可以让您在每次更新下载线程中的计数时设置值并调用该方法。 2.)将该值放在两个线程都可以访问的某个字段中(可能不是线程安全的)

    如果是我,在我的进度条中,我会有一个方法,允许用一些值更新进度。然后我会从下载文件的线程中调用该方法

    所以基本上是用户-->;单击一些下载按钮-->;Handler调用该方法开始下载,并将回调传递给更新进度条方法-->;下载线程在每个迭代周期调用该方法,并更新完成百分比

  5. # 5 楼答案

    在HTTP 1.1规范中,chunk响应数据应该在多轮中被拉回。实际上,区块响应中的内容长度是-1,所以我们不能在Inputstream中使用availble方法。顺便说一句,Inputstream.availble方法仅在通过TearrayInputStream获得中的内容长度时稳定

    如果你只想得到总长度,你需要在每一轮阅读中自己计算。请参见apache commons io项目中的IOUtils类,如下所示:

    //-----------------------------------------------------------------------
    /**
     * Copy bytes from an <code>InputStream</code> to an
     * <code>OutputStream</code>.
     * <p>
     * This method buffers the input internally, so there is no need to use a
     * <code>BufferedInputStream</code>.
     * <p>
     * Large streams (over 2GB) will return a bytes copied value of
     * <code>-1</code> after the copy has completed since the correct
     * number of bytes cannot be returned as an int. For large streams
     * use the <code>copyLarge(InputStream, OutputStream)</code> method.
     * 
     * @param input  the <code>InputStream</code> to read from
     * @param output  the <code>OutputStream</code> to write to
     * @return the number of bytes copied
     * @throws NullPointerException if the input or output is null
     * @throws IOException if an I/O error occurs
     * @throws ArithmeticException if the byte count is too large
     * @since Commons IO 1.1
     */
    public static int copy(InputStream input, OutputStream output) throws IOException {
        long count = copyLarge(input, output);
        if (count > Integer.MAX_VALUE) {
            return -1;
        }
        return (int) count;
    }
    
    /**
     * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
     * <code>OutputStream</code>.
     * <p>
     * This method buffers the input internally, so there is no need to use a
     * <code>BufferedInputStream</code>.
     * 
     * @param input  the <code>InputStream</code> to read from
     * @param output  the <code>OutputStream</code> to write to
     * @return the number of bytes copied
     * @throws NullPointerException if the input or output is null
     * @throws IOException if an I/O error occurs
     * @since Commons IO 1.3
     */
    public static long copyLarge(InputStream input, OutputStream output)
            throws IOException {
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        long count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;
    }
    

    如果你想检查下载进度,你需要在拷贝到磁盘的过程中,从输入流输入到输出流输出的每一轮read上回调。在回调中,您可以复制一段数据,并将金额添加到计数器中,该计数器设计用于progressbar功能。这有点复杂

  6. # 6 楼答案

    检查响应上的内容长度标题。应该设置它。所有主要的HTTP服务器都使用这个头