最近写了一个java多线程下载的Demo,但运行时报错:
java.io.FileNotFoundException: mx_2.5.1.4751cn.exe (另一个程序正在使用此文件,进程无法访问。)
at java.io.RandomAccessFile.open(Native Method)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:212)
at org.angus.ch07.thread.multiThreadDownload.DownloadThread.writeFile(DownloadThread.java:84)
at org.angus.ch07.thread.multiThreadDownload.DownloadThread.run(DownloadThread.java:59)涉及到的代码如下:import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;/**
* 负责文件下载的类
*/
public class DownloadThread extends Thread {
/**
* //待下载的文件
*/
private String url = null; /**
* //本地存储路径
*/
private String file = null; /**
* //偏移量
*/
private long offset = 0; /**
* //分配给本线程的下载字节数
*/
private long length = 0; public DownloadThread(String url, String file, long offset, long length) {
this.url = url;
this.file = file;
this.offset = offset;
this.length = length;
System.out.println("偏移量=" + offset + ";字节数=" + length);
} public void run() {
try {
HttpURLConnection httpConnection = (HttpURLConnection) new URL(
this.url).openConnection(); httpConnection.setRequestMethod("GET");
httpConnection.setRequestProperty("RANGE", "bytes=" + this.offset
+ "-" + (this.offset + this.length - 1));
System.out.println("RANGE bytes=" + this.offset + "-" + (this.offset + this.length - 1));
BufferedInputStream bis = new BufferedInputStream(httpConnection
.getInputStream()); byte[] buff = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(buff, 0, buff.length)) != -1) {
this.writeFile(this.file, this.offset, buff, bytesRead);
this.offset = this.offset + bytesRead;
}
bis.close();
} catch (IOException ioe) {
ioe.printStackTrace();
} } /**
* 将字节数组以随机方式写入文件
*
* @param fileName
* 被写入的文件
* @param offset
* 写入文件的位置偏移量
* @param bytes
* 待写入的字节数组
* @param realLength
* 实际需要写入的字节数(realLength<=bytes.length)
*/
private void writeFile(String fileName, long offset, byte[] bytes,
int realLength) throws IOException {
File newFile = new File(fileName);
RandomAccessFile raf = new RandomAccessFile(newFile, "rw"); raf.seek(offset);
raf.write(bytes, 0, realLength);
raf.close(); }
}经debug,错误出现在private void writeFile(String fileName, long offset, byte[] bytes,
int realLength) throws IOException {
这个方法中RandomAccessFile raf = new RandomAccessFile(newFile, "rw");这一行.我将DownloadThread 改为一个普通的java类,调用其run方法(即为单线程下载)是没有问题的,下载后的文件也没有错误.但多线程就是有问题,如何解决呢?
java.io.FileNotFoundException: mx_2.5.1.4751cn.exe (另一个程序正在使用此文件,进程无法访问。)
at java.io.RandomAccessFile.open(Native Method)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:212)
at org.angus.ch07.thread.multiThreadDownload.DownloadThread.writeFile(DownloadThread.java:84)
at org.angus.ch07.thread.multiThreadDownload.DownloadThread.run(DownloadThread.java:59)涉及到的代码如下:import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;/**
* 负责文件下载的类
*/
public class DownloadThread extends Thread {
/**
* //待下载的文件
*/
private String url = null; /**
* //本地存储路径
*/
private String file = null; /**
* //偏移量
*/
private long offset = 0; /**
* //分配给本线程的下载字节数
*/
private long length = 0; public DownloadThread(String url, String file, long offset, long length) {
this.url = url;
this.file = file;
this.offset = offset;
this.length = length;
System.out.println("偏移量=" + offset + ";字节数=" + length);
} public void run() {
try {
HttpURLConnection httpConnection = (HttpURLConnection) new URL(
this.url).openConnection(); httpConnection.setRequestMethod("GET");
httpConnection.setRequestProperty("RANGE", "bytes=" + this.offset
+ "-" + (this.offset + this.length - 1));
System.out.println("RANGE bytes=" + this.offset + "-" + (this.offset + this.length - 1));
BufferedInputStream bis = new BufferedInputStream(httpConnection
.getInputStream()); byte[] buff = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(buff, 0, buff.length)) != -1) {
this.writeFile(this.file, this.offset, buff, bytesRead);
this.offset = this.offset + bytesRead;
}
bis.close();
} catch (IOException ioe) {
ioe.printStackTrace();
} } /**
* 将字节数组以随机方式写入文件
*
* @param fileName
* 被写入的文件
* @param offset
* 写入文件的位置偏移量
* @param bytes
* 待写入的字节数组
* @param realLength
* 实际需要写入的字节数(realLength<=bytes.length)
*/
private void writeFile(String fileName, long offset, byte[] bytes,
int realLength) throws IOException {
File newFile = new File(fileName);
RandomAccessFile raf = new RandomAccessFile(newFile, "rw"); raf.seek(offset);
raf.write(bytes, 0, realLength);
raf.close(); }
}经debug,错误出现在private void writeFile(String fileName, long offset, byte[] bytes,
int realLength) throws IOException {
这个方法中RandomAccessFile raf = new RandomAccessFile(newFile, "rw");这一行.我将DownloadThread 改为一个普通的java类,调用其run方法(即为单线程下载)是没有问题的,下载后的文件也没有错误.但多线程就是有问题,如何解决呢?
1) 在主线程中创建打开下载的文件
2) RandomAccessFile对象而不是文件名作为参数传给DownloadThread,在写数据到文件时,锁定RandomAccessFile对象后再写数据
3) 主线程调用Thread.join()等待所有DownloadThread的结束后,关闭打开的文件程序框架如下:在主线程中:
…
RandomAccessFile raFile = new RandomAccessFile(…);…
Thread thread = new DownloadThread( url, raFile, offset, length );
thread.start();
downloadThreads.add(thread );
…
for( Thread thread: downloadThreads ) {
thread.join();
}raFile.close();改写DownloadThread 中的writeFile方法:private void writeFile(RandomAccessFile raf, long offset, byte[] bytes,
int realLength) throws IOException { synchronized(raf ){
raf.seek(offset);
raf.write(bytes, 0, realLength);
}}