9

我正在开发一个使用 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;

long downloadFileHttp(.., ..) 是我的函数的名称。

我已经尝试使用 outputfile.length 来检索它,但他的值为“1”,也许这是我尝试下载的文件数。

有什么办法可以弄清楚吗?

更新 1

我没有任何线索可以让我弄清楚这一点。目前我有一个水平进度条,它只显示 0 和 100% 的中间值。我考虑另一种方法。如果我知道我的 wifi 的速率和文件的大小,我可以确定下载的时间。

我知道我可以检索我的 Wifi 连接的信息和要下载的文件的大小。

有没有人已经工作过或有线程?

4

8 回答 8

10

我假设您使用的是HttpURLConnection。在这种情况下,您需要 getContentLength()urlconnect.

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

于 2013-03-05T14:17:12.023 回答
6

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);
于 2013-03-19T21:08:47.733 回答
3

简单的。下面的代码:

try {
    URL url = new URL(yourLinkofFile);
    URLConnection conn = url.openConnection();
    conn.connect();
    totalFileSize = conn.getContentLength();
} catch (Exception e) {
    Log.e(TAG, "ERROR: " + e.toString());
}
于 2013-03-20T09:26:04.983 回答
2

检查响应中的 Content-Length 标头。应该设置它。所有主要的 HTTP 服务器都使用此标头。

于 2013-03-05T15:23:53.470 回答
2

在 HTTP 1.1 规范中,chunk响应数据应该被拉回多轮。实际上,块响应中的内容长度为-1,因此我们不能availble在 Inputstream 中使用方法。顺便说一句,Inputstream.availble方法仅在ByteArrayInputStream中获取内容长度是稳定的。

如果你只是想得到总长度,你需要在每一轮读取中自己计算它。请参阅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;
}

如果要查看下载进度,则需要在复制到磁盘的过程中readInputStream输入到OutputStream输出的每一轮回调。在回调中,您可以复制一条数据并将数量添加到旨在用于您的进度条功能的计数器中。这有点复杂

于 2013-03-18T11:49:58.207 回答
1

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

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

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

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

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

于 2013-03-19T20:05:46.453 回答
1

我认为你让你的生活太复杂了:)

第一:因为progressBarStatus = ((int) downloadFileHttp(url, app) * 100)/sizefile;总是 0 或 100,也许你没有正确计算值。您没有在那里发布整个方法,但不要忘记您正在处理 int 所以 sizefile 始终是 int,并且划分到更高或等于 sizefile 总是会返回 0 或 1。我怀疑是您需要研究的方向......另外,我没有在您的代码中看到您在读取中间字节后更新进度条的位置。

第二:我认为如果你分块阅读会更有效率。读取效率更高,您无需为每个下载的字节通知 UI 线程。Adamski 从这个线程中得到的答案 可能会对您有所帮助。只需使用较小的字节数组。我通常使用 256 (3G) 或 512 (Wi-Fi) - 但也许您不需要详细说明。因此,一旦您读取了一个新数组,请计算读取的字节总数,通知 UI 并继续读取直到流结束。

第三:将progressBar.setMax()下载前的字节数设置为sizeFile,根据“First”的注释正确计算下载的字节数,然后用计算出的数字调用setProgress。只是不要忘记更新 UI 线程上的进度条。AsyncTask 有一个很好的机制来帮助你。

祝你好运!

于 2013-03-20T12:52:50.260 回答
0

好吧,这应该可以帮助您

URLConnection connection = servletURL.openConnection();
BufferedInputStream buff = new BufferedInputStream(connection .getInputStream());
ObjectInputStream input = new ObjectInputStream(buff );
int avail = buff .available();

System.out.println("Response content size = " + avail);
于 2013-03-05T14:49:53.570 回答