为什么在Java中使用输入输出流下载图像文件会导致图像文件损坏?

为什么在Java中使用输入输出流下载图像文件会导致图像文件损坏?,java,image,download,Java,Image,Download,我正在读一本关于java并发性的书,书中有一个从internet下载图像文件的例子。程序使用Files.copy()内置函数下载图像文件。代码: import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; impor

我正在读一本关于java并发性的书,书中有一个从internet下载图像文件的例子。程序使用Files.copy()内置函数下载图像文件。代码:

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.TimeUnit;

public class TwoFileDownloadingWithJoin {
    public static void main(String[] args) {
        Thread beatPrinter = new BeatPrinter();
        Thread down1 = new FileDownloader("https://secure.meetupstatic.com/photos/event/e/9/f/9/600_464039897.jpeg", "meet1.jpg");
        Thread down2 = new FileDownloader("https://secure.meetupstatic.com/photos/event/2/d/0/f/600_464651535.jpeg", "meet2.jpg");
        beatPrinter.setName("Beat Printer");
        down1.setName("file1 downloader");
        down2.setName("file2 downloader");

        try {
            down1.start();
            down2.start();
            TimeUnit.MILLISECONDS.sleep(100);
            beatPrinter.start();

            down1.join();
            down2.join();
            ((BeatPrinter) beatPrinter).kill();
            beatPrinter.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Download Complete");
    }
}

class BeatPrinter extends Thread {

    private volatile boolean live = true;

    @Override
    public void run() {
        while (live) {
            printStar("Downloading ");
        }
    }

    void kill() {
        live = false;
    }

    private void printStar(String msg) {
        System.out.print(msg);
        char[] signs = {'-', '\\', '|', '/'};
        for (char s : signs) {
            System.out.print(s);
            try {
                Thread.sleep(300);
                System.out.print('\b');
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (int i = 0; i < msg.length(); i++)
            System.out.print('\b');
    }
}

class FileDownloader extends Thread {
    private String url;
    private String fileName;

    FileDownloader(String url, String fileName) {
        this.url = url;
        this.fileName = fileName;
    }

    @Override
    public void run() {
        File destinationFile = new File(fileName);
        try {
            System.out.println("Starting download of " + fileName);
            URL fileUrl = new URL(url);

            HttpURLConnection connection = (HttpURLConnection) fileUrl.openConnection();
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = connection.getInputStream();
                Files.copy(inputStream, destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                inputStream.close();
            } else {
                System.out.println("Error: " + connection.getResponseMessage());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
我没有使用Files.copy()而是从输入流中读取字节,然后将字节写入输出文件。但我的方法会产生破碎的图像。问题在哪里

原始图像:


破损图像:

我猜你在复制时写得太多了。在
FileDownloader.run()
中,它应该是
fos.write(缓冲区,0,currRead)而不是
fos.write(缓冲区)。你做过任何调试吗?跟踪IDE中的代码?你发现了什么?@Izruo没错。非常感谢。抱歉,反馈太晚。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;

public class TwoFileDownloadingWithJoin {
    public static void main(String[] args) {
        Thread down1 = new FileDownloader("https://secure.meetupstatic.com/photos/event/e/9/f/9/600_464039897.jpeg", "meet1.jpg");
        Thread down2 = new FileDownloader("https://secure.meetupstatic.com/photos/event/2/d/0/f/600_464651535.jpeg", "meet2.jpg");

        down1.setName("file1 downloader");
        down2.setName("file2 downloader");

        try {
            down1.start();
            down2.start();
            TimeUnit.MILLISECONDS.sleep(100);

            down1.join();
            down2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Download Complete");
    }
}

class FileDownloader extends Thread {
    private String url;
    private String fileName;
    private double totRead;
    private ProgressUpdater progressUpdater;

    FileDownloader(String url, String fileName) {
        this.url = url;
        this.fileName = fileName;
        this.progressUpdater = new ProgressUpdater(this, fileName);
    }

    double getTotRead() {
        return totRead;
    }

    @Override
    public void run() {
        File destinationFile = new File(fileName);
        try {
            System.out.println("Starting download of " + fileName);
            URL fileUrl = new URL(url);

            HttpURLConnection connection = (HttpURLConnection) fileUrl.openConnection();
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                double fileSize = Double.parseDouble(connection.getHeaderField("content-length"));

                InputStream fis = connection.getInputStream();
                FileOutputStream fos = new FileOutputStream(destinationFile);

                byte[] buffer = new byte[1024];
                double currRead;
                double totSize = fileSize / 1024.0;

                progressUpdater.setTotSize(totSize);
                progressUpdater.start();

                while ((currRead = fis.read(buffer)) != -1) {
                    fos.write(buffer);
                    totRead += currRead / 1024;
                }
                fis.close();
                fos.close();
                progressUpdater.kill();
                progressUpdater.join();
            } else {
                System.out.println("Error: " + connection.getResponseMessage());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ProgressUpdater extends Thread {
    private FileDownloader fileDownloader;
    private volatile boolean killed;
    private String fileName;
    private double totSize;

    public ProgressUpdater(FileDownloader fileDownloader, String fileName) {
        this.fileDownloader = fileDownloader;
        this.fileName = fileName;
        killed = false;
    }

    public void kill() {
        killed = true;
    }

    public void setTotSize(double totSize) {
        this.totSize = totSize;
    }

    @Override
    public void run() {
        boolean hundredPercent = false;
        while (!killed || !hundredPercent) {
            double totRead = fileDownloader.getTotRead();
            System.out.println(String.format("%s: %.2fKB of %.2fKB downloaded(%.2f%%)", fileName, totRead, totSize, 100 * totRead / totSize));
            hundredPercent = (100 * totRead / totSize) > 99.00;
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}