Почему загрузка файла изображения с использованием потока ввода-вывода приводит к повреждению файлов изображения в Java? - PullRequest
0 голосов
/ 06 июня 2018

Я читаю книгу о параллельности Java, в которой приведен пример загрузки файла изображения из Интернета.Программа использует встроенную функцию 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();
        }
    }
}

Я изменил программу следующим образом, чтобы показать ход загрузки:

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();
            }
        }
    }
}

Вместо использования Files.copy () я читал байты из входного потока, а затем записывалбайт для вывода файла.Но мой подход приводит к неправильным изображениям.В чем проблема?

Исходное изображение: https://secure.meetupstatic.com/photos/event/e/9/f/9/600_464039897.jpeg

Сломанное изображение: https://imgur.com/UrgafA5

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...