2

I am trying to download an exe file with following code, any idea why it downloads only ~30% of the file? At least it doesn't throw any exceptions.

My main method looks like this: new DownloadWorker().execute();

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;

import javax.swing.SwingWorker;

public final class DownloadWorker extends SwingWorker<Object, Object> {

    @Override
    protected Object doInBackground() throws Exception {
        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        try {
            URL url = new URL("http://download.piriform.com/ccsetup320.exe");
            URLConnection conn = url.openConnection();
            conn.connect();

            int fileLength = conn.getContentLength();

            in = new BufferedInputStream(url.openStream());
            out = new BufferedOutputStream(new FileOutputStream("ccsetup320.exe"));

            byte[] buffer = new byte[4096];
            long total = 0;
            int bytesRead = 0;
            while ( (bytesRead = in.read(buffer)) != -1 ) {
                total += bytesRead;
                System.out.println((int) (total * 100 / fileLength));
                out.write(buffer, 0, bytesRead);
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        } finally {
            if ( out != null ) {
                out.flush();
                out.close();
            }
            if ( in != null ) {
                in.close();
            }
        }

        return null;
    }

    @Override
    protected void done() {

    }

}

Thanks.

Matt Solnit
  • 32,152
  • 8
  • 53
  • 57
perak
  • 1,310
  • 5
  • 20
  • 31
  • 2
    Your exact code (cut and paste) works fine for me, giving the same size (3,889,704 bytes) and MD5 sum (9039731b97c63d6759bbcbbbb14db6ab) as downloading in Chrome. – Jon Skeet Jul 01 '12 at 21:27
  • I'm using jdk1.7.0_04 and the System.out.println stops between 30 and 36, and the output file is also around 1.3 mb – perak Jul 01 '12 at 21:31
  • @perrtuk, your code works fine for me? It goes to 100, and I have the same Java version, why not try using NIO API of java 7, see answer below – David Kroukamp Jul 01 '12 at 21:47
  • I just noticed that both codes do work when I execute them directly from the main method, but fail when I use SwingWorker. – perak Jul 01 '12 at 21:55
  • I think the problem is using `execute()`, on my worker I call `run()`, if I call `execute()` it doesnt work! – David Kroukamp Jul 01 '12 at 22:15
  • Calling run instead of execute fixed it! Thanks. – perak Jul 01 '12 at 22:17

2 Answers2

2

Have you tried using Java NIO seen as you have Java 7 installed:

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;


public class TestApp {

    public static void main(String[] args) {
        try {
            URL url = new URL("http://download.piriform.com/ccsetup320.exe");
            ReadableByteChannel rbc = Channels.newChannel(url.openStream());
            FileOutputStream fos = new FileOutputStream("c:/ccsetup320.exe");
            fos.getChannel().transferFrom(rbc, 0, 1 << 24);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}

The above code is tested and works just fine, I got it from a similar question found here we can see how the NIO makes coding so much easier :)

EDIT:

I have updated the code to use a swingworker and it downloads the file without a problem:

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import javax.swing.SwingWorker;

public class JavaApplication174 {

    public static void main(String[] args) {
        SwingWorker worker = new SwingWorker() {

            @Override
            protected Object doInBackground() throws Exception {

                try {
                    URL google = new URL("http://download.piriform.com/ccsetup320.exe");
                    ReadableByteChannel rbc = Channels.newChannel(google.openStream());
                    FileOutputStream fos = new FileOutputStream("c:/ccsetup320.exe");
                    fos.getChannel().transferFrom(rbc, 0, 1 << 24);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                return this;
            }
        };
        worker.run();
    }
}

EDIT 2:

You call execute() on your workers instance use run() instead works for me!

Community
  • 1
  • 1
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • This works when executed directly from main method, but not when it's in SwingWorker, I've updated my question. – perak Jul 01 '12 at 22:01
  • @perrtuk I have edited the code to incorporate a `SwingWorker`, and it seems to be working just fine? – David Kroukamp Jul 01 '12 at 22:09
0

i think your error lies in this loop because the -1 isn't being written (that is the last byte that marks the file end):

        while ( (bytesRead = in.read(buffer)) != -1 ) {
            total += bytesRead;
            System.out.println((int) (total * 100 / fileLength));
            out.write(buffer, 0, bytesRead);
        }

Change it to:

        do {
            bytesRead = in.read(buffer);
            total += bytesRead;
            System.out.println((int) (total * 100 / fileLength));
            out.write(buffer, 0, bytesRead);
        }while(bytesRead!=-1);
Vedant Agarwala
  • 18,146
  • 4
  • 66
  • 89