为什么在Java中使用输入输出流下载图像文件会导致图像文件损坏?
我正在读一本关于java并发性的书,书中有一个从internet下载图像文件的例子。程序使用Files.copy()内置函数下载图像文件。代码:为什么在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
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();
}
}
}
}