最近写了一个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方法(即为单线程下载)是没有问题的,下载后的文件也没有错误.但多线程就是有问题,如何解决呢?

解决方案 »

  1.   

    多个线程同时写一个文件会有你所说的问题,可以这样改进:
    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); 
        }}