Know the total file size to download

Asked

Viewed 114 times

2

I have the following code that downloads file from the internet

public boolean copiar(){
        boolean teste = false;
        try
        {
            String local = System.getProperty("user.dir") +"\\PDV.jar";;
            String archive = "https://github.com/cbcarlos07/PDV-client/blob/master/PDV.jar";            
            InputStream in  = new URL(archive).openStream();
            OutputStream out = new FileOutputStream( local, false );
            long expectedBytes = in.available(); // This is the number of bytes we expected to copy..
            long totalBytesCopied = 0; // This will track the total number of bytes we've copied
            byte[] buf = new byte[1024];
            int len = 0;
            System.out.println("Total: "+expectedBytes);
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
                totalBytesCopied += len;
                System.out.println("Len: "+len);
                System.out.println("totalCopiado: "+totalBytesCopied);
                double total = ( totalBytesCopied * 100 ) / expectedBytes;
                double percentual = ( totalBytesCopied / expectedBytes ) * 100;
                System.out.println( total );
                System.out.println(percentual+"%");
            }
            System.out.println("");
            in.close();
            out.close();
            teste = true;

        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        return teste;
    }

It works, but I would like to know before, which file size to make a progress indicator

Know the total file, how much has been downloaded and how many more to download, to make up the download time

  • An alternative would be read the header Content-Length, but this URL returns the header Transfer-Encoding: chunked, and in such cases the Content-Length is not returned (see more about this here, here and here). So I guess in this case there really is no way...

1 answer

2

The size of an HTTP resource is informed via an HTTP header, the Content-length. In HTTP 1.1, you can omit this information, as long as the header is used Transfer-encoding: chunked. For static features, like this one possibly is, it’s easy to know the size of the resource before to begin transmission, but there are cases where it is not possible.

To know from Java, you need to somehow have access to the HTTP connection, then rescue the headers. I didn’t see how to do it through URL.openStream(), but it is plausible to obtain this information via URL.openConnection(). You can get HTTP headers because one of the subclasses of URLConnection (the exit of URL.openConnection()) is HttpURLConnection. In addition, the class itself URLConnection provides the method URLConnection.getContentLength() (or, according to the documentation, URLConnection.getContentLengthLong(), which is preferable).

Note that in the documentation it is explicit that you can return -1 if the resource is of unknown size!

I modified your code as little as possible to get the expected size of the resource and somehow inform when it is not possible to know this:

public boolean copiar(){
        boolean teste = false;
        try
        {
            String local = System.getProperty("user.dir") +"\\PDV.jar";;
            String archive = "https://github.com/cbcarlos07/PDV-client/blob/master/PDV.jar";
            URLConnection conn  = new URL(archive).openConnection();
            InputStream in  = conn.getInputStream();
            OutputStream out = new FileOutputStream( local, false );
            long expectedBytes = conn.getContentLengthLong(); // This is the number of bytes we expected to copy..
            long totalBytesCopied = 0; // This will track the total number of bytes we've copied
            byte[] buf = new byte[1024];
            int len = 0;
            System.out.println("Total: "+expectedBytes);
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
                totalBytesCopied += len;
                System.out.println("Len: "+len);
                System.out.println("totalCopiado: "+totalBytesCopied);
                if (expectedBytes != -1) {
                    double total = ( totalBytesCopied * 100 ) / expectedBytes;
                    double percentual = ( totalBytesCopied / expectedBytes ) * 100;
                    System.out.println( total );
                    System.out.println(percentual+"%");
                } else {
                    System.out.println( "???" );
                    System.out.println("???%");
                }
            }
            System.out.println("");
            in.close();
            out.close();
            teste = true;

        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        return teste;
    }

Note that the idea was to change as little as possible your code to improve understanding, I did not rewrite in a way that pleases me to the point that I use in production.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.