canghailan 使用URLConnection下载文件

canghailan 使用URLConnection下载文件
package canghailan;

import canghailan.util.StopWatch;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * User: canghailan
 * Date: 11-12-9
 * Time: 下午2:03
 */
public class Downloader implements Callable<File> {
    protected int connectTimeout = 30 * 1000; // 连接超时:30s
    protected int readTimeout = 1 * 1000 * 1000; // IO超时:1min

    protected int speedRefreshInterval = 500; // 即时速度刷新最小间隔:500ms

    protected byte[] buffer;

    private URL url;
    private File file;

    private float averageSpeed;
    private float currentSpeed;

    public Downloader() {
        buffer = new byte[8 * 1024]; // IO缓冲区:8KB
    }

    public void setUrlAndFile(URL url, File file) {
        this.url = url;
        this.file = autoRenameIfExist(file);
        this.averageSpeed = 0;
        this.currentSpeed = 0;
    }

    public URL getUrl() {
        return url;
    }

    public File getFile() {
        return file;
    }

    public float getAverageSpeed() {
        return averageSpeed;
    }

    public float getCurrentSpeed() {
        return currentSpeed;
    }

    @Override
    public File call() throws Exception {
        StopWatch watch = new StopWatch();
        watch.start();

        InputStream in = null;
        OutputStream out = null;
        try {
            URLConnection conn = url.openConnection();
            conn.setConnectTimeout(connectTimeout);
            conn.setReadTimeout(readTimeout);
            conn.connect();

            in = conn.getInputStream();
            out = new FileOutputStream(file);

            int time = 0;
            int bytesInTime = 0;
            for (; ; ) {
                watch.split();
                int bytes = in.read(buffer);
                if (bytes == -1) {
                    break;
                }
                out.write(buffer, 0, bytes);

                time += watch.getTimeFromSplit();
                if (time >= speedRefreshInterval) {
                    currentSpeed = getSpeed(bytesInTime, time);
                    time = 0;
                    bytesInTime = 0;
                }
            }
        } catch (IOException e) {
            file.delete();
            throw e;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                }
            }
        }

        watch.stop();
        averageSpeed = getSpeed(file.length(), watch.getTime());

        return file;
    }

    private static float getSpeed(long bytesInTime, long time) {
        return (float) bytesInTime / 1024 / ((float) time / 1000);
    }

    private static String getExtension(String string) {
        int lastDotIndex = string.lastIndexOf('.');
        // . ..
        if (lastDotIndex > 0) {
            return string.substring(lastDotIndex + 1);
        } else {
            return "";
        }
    }

    private static File autoRenameIfExist(File file) {
        if (file.exists()) {
            String path = file.getAbsolutePath();

            String extension = getExtension(path);
            int baseLength = path.length();
            if (extension.length() > 0) {
                baseLength = path.length() - extension.length() - 1;
            }

            StringBuilder buffer = new StringBuilder(path);
            for (int index = 1; index < Integer.MAX_VALUE; ++index) {
                buffer.setLength(baseLength);
                buffer.append('(').append(index).append(')');
                if (extension.length() > 0) {
                    buffer.append('.').append(extension);
                }
                file = new File(buffer.toString());
                if (!file.exists()) {
                    break;
                }
            }

        }
        return file;
    }

    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        URL url = new URL("http://www.google.com.hk/");
        File file = new File("/home/canghailan/google.html");

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Downloader downloader = new Downloader();
        downloader.setUrlAndFile(url, file);
        File downloadFIle = executorService.submit(downloader).get();
        System.out.println("download " + downloadFIle.getName() +
                " from " + url +
                " @" + downloader.getAverageSpeed() + "KB/s");
    }
}
package canghailan.util;

import java.util.concurrent.TimeUnit;

/**
 * User: canghailan
 * Date: 11-12-9
 * Time: 下午3:45
 * <pre>
 * RUNNING:
 * startTime              split                        now
 * |<-   getSplitTime()   ->|<-   getTimeFromSplit()   ->|
 * |<-                   getTime()                     ->|
 * <pre/>
 * <pre>
 * STOPPED:
 * startTime                           stop            now
 * |<-           getTime()            ->|
 * <pre/>
 */
public class StopWatch {
    private long startTime;
    private long stopTime;

    private State state;
    private boolean split;

    public StopWatch() {
        reset();
    }

    public void start() {
        if (state == State.UNSTARTED) {
            startTime = System.nanoTime();
            state = State.RUNNING;
            return;
        }
        throw new RuntimeException("Stopwatch already started or stopped.");
    }

    public void stop() {
        switch (state) {
            case RUNNING: {
                stopTime = System.nanoTime();
            }
            case SUSPENDED: {
                state = State.STOPPED;
                split = false;
                return;

            }
        }
        throw new RuntimeException("Stopwatch is not running.");
    }

    public void reset() {
        state = State.UNSTARTED;
        split = false;
    }

    public void split() {
        if (state == State.RUNNING) {
            stopTime = System.nanoTime();
            split = true;
            return;
        }
        throw new RuntimeException("Stopwatch is not running.");
    }

    public void suspend() {
        if (state == State.RUNNING) {
            stopTime = System.nanoTime();
            state = State.SUSPENDED;
            return;
        }
        throw new RuntimeException("Stopwatch must be running to suspend.");
    }

    public void resume() {
        if (state == State.SUSPENDED) {
            startTime += System.nanoTime() - stopTime;
            state = State.RUNNING;
            return;
        }
        throw new RuntimeException("Stopwatch must be suspended to resume.");
    }

    public long getTime() {
        return TimeUnit.NANOSECONDS.toMillis(getNanoTime());
    }

    public long getNanoTime() {
        switch (state) {
            case RUNNING: {
                return System.nanoTime() - startTime;
            }
            case STOPPED:
            case SUSPENDED: {
                return stopTime - startTime;
            }
            case UNSTARTED: {
                return 0;
            }
        }
        throw new RuntimeException("Should never get here.");
    }

    public long getSplitTime() {
        return TimeUnit.NANOSECONDS.toMillis(getSplitNanoTime());
    }


    public long getSplitNanoTime() {
        if (split) {
            return stopTime - startTime;
        }
        throw new RuntimeException("Stopwatch must be running and split to get the split time.");
    }

    public long getTimeFromSplit() {
        return TimeUnit.NANOSECONDS.toMillis(getNanoTimeFromSplit());
    }

    public long getNanoTimeFromSplit() {
        if (state == State.RUNNING && split) {
            return System.nanoTime() - stopTime;
        }
        throw new RuntimeException("Stopwatch must be running and split to get the time from split.");
    }

    enum State {
        UNSTARTED,
        RUNNING,
        STOPPED,
        SUSPENDED
    }

}

你可能感兴趣的:(canghailan 使用URLConnection下载文件)