使用HttpURLConnection下载文件时出现 java.io.FileNotFoundException彻底解决办法

时间:2022-01-18 08:35:06

使用HttpURLConnection下载文件时经常会出现 java.io.FileNotFoundException文件找不到异常,下面介绍下解决办法

首先设置tomcat对get数据的编码:conf/server.xml

    <Connector port="8080" protocol="HTTP/1.1" 
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8" />

其次对请求的文件名进行编码:

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

/**
* 多线程下载
* @author bing
*
*/
public class OmbDownloadOfThreadsUtil {

private String urlPath ; // 资源网络路径
private String targetFilePath ; // 所下载文件的保存路径
private int threadNum ; // 启用多少条线程进行下载
// 用于下载线程对象集合
private DownloadThread[] downloadThreads ;
// 要下载文件的大小
private int fileSize ;


public OmbDownloadOfThreadsUtil(String urlPath, String targetFilePath,
int threadNum) {
this.urlPath = urlPath;
this.targetFilePath = targetFilePath;
this.threadNum = threadNum;
downloadThreads = new DownloadThread[threadNum] ;
}

public void downloadFile() throws Exception{
URL url = new URL(urlPath) ;
HttpURLConnection conn = (HttpURLConnection) url.openConnection() ;
conn.setConnectTimeout(4*1000) ;
conn.setRequestMethod("GET") ;
conn.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, " +
"application/x-shockwave-flash, application/xaml+xml, " +
"application/vnd.ms-xpsdocument, application/x-ms-xbap, " +
"application/x-ms-application, application/vnd.ms-excel, " +
"application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
//设置浏览器类型和版本、操作系统,使用语言等信息
conn.setRequestProperty(
"User-Agent",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; Trident/4.0; " +
".NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; " +
".NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
//设置为长连接
conn.setRequestProperty("Connection", "Keep-Alive");
//得到要下载文件的大小
fileSize = conn.getContentLength() ;

System.out.println("fileSize:"+fileSize);

//断开连接
conn.disconnect() ;
//计算每条线程需要下载的大小
int preThreadDownloadSize = fileSize/threadNum+1 ;
System.out.println("preThreadDownloadSize:"+preThreadDownloadSize);


RandomAccessFile file = new RandomAccessFile(targetFilePath, "rw") ;
file.setLength(fileSize) ;
file.close() ;
for (int i = 0; i < threadNum; i++) {
// 计算每条线程下载的起始位置
int startPos = i*preThreadDownloadSize+1 ;
RandomAccessFile currentPart = new RandomAccessFile(targetFilePath, "rw") ;
currentPart.seek(startPos) ;
downloadThreads[i] = new DownloadThread(startPos,preThreadDownloadSize,currentPart) ;
new Thread(downloadThreads[i]).start() ;
}
}

/**
* 获取下载的完成百分比
* @return 完成的百分比
*/
public double getCompleteRate() {
// 统计多条线程已经下载的总大小
int sumSize = 0;
for (int i = 0; i < threadNum; i++) {
sumSize += downloadThreads[i].hasReadLength;
}
// 返回已经完成的百分比
return sumSize * 1.0 / fileSize;
}
/**
* 用于下载的线程
* @author bing
*
*/
private final class DownloadThread implements Runnable{

private int startPos ;
private int preThreadDownloadSize ;
private RandomAccessFile currentPart ;
//已下载长度
private int hasReadLength ;

public DownloadThread(int startPos, int preThreadDownloadSize,
RandomAccessFile currentPart) {
this.startPos = startPos;
this.preThreadDownloadSize = preThreadDownloadSize;
this.currentPart = currentPart;
}

@Override
public void run() {
InputStream inputStream = null ;
try{
URL url = new URL(urlPath) ;
HttpURLConnection conn = (HttpURLConnection) url.openConnection() ;
conn.setConnectTimeout(4*1000) ;
conn.setRequestMethod("GET") ;
conn.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, " +
"application/x-shockwave-flash, application/xaml+xml, " +
"application/vnd.ms-xpsdocument, application/x-ms-xbap, " +
"application/x-ms-application, application/vnd.ms-excel, " +
"application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
inputStream = conn.getInputStream() ;
inputStream.skip(startPos) ;//定位到开始位置
byte[] buffer = new byte[1024] ;
int temp = 0 ;
while(hasReadLength<preThreadDownloadSize
&&(temp=inputStream.read(buffer))!=-1){
currentPart.write(buffer,0,temp) ;
hasReadLength += temp ;
}

}catch(Exception e){
e.printStackTrace() ;
}finally{
try {
currentPart.close() ;
} catch (Exception e) {
e.printStackTrace();
}
try {
inputStream.close() ;
} catch (Exception e) {
e.printStackTrace();
}
}

}

}

public static void main(String[] args) throws Exception {
String songName = "许嵩 - 半城烟沙.mp3" ;
songName = URLEncoder.encode(songName,"UTF-8") ;
String urlPath = "http://172.16.2.50:8080/mp3/"+songName ;
String targetDir = "E:"+File.separator+songName ;
OmbDownloadOfThreadsUtil odtu = new OmbDownloadOfThreadsUtil(urlPath,targetDir, 6) ;
odtu.downloadFile() ;
}
}
经过以上三步基本上问题已经解决,但如果的文件名含有空格的话还需一步:

URLs是不能包含空格的。URL encoding一般会使用“+”号去替换空格,但后台服务器(我的是Tomcat6.0)又不能把“+”还原为空格,所以导致文件找不到,解决办法:只需把“+”替换为“%20”

public static void main(String[] args) throws Exception {
String songName = "许嵩 - 半城烟沙.mp3" ;
songName = URLEncoder.encode(songName,"UTF-8").replace("+", "%20") ;

String urlPath = "http://172.16.2.50:8080/mp3/"+songName ;
String targetDir = "E:"+File.separator+songName ;

OmbDownloadOfThreadsUtil odtu = new OmbDownloadOfThreadsUtil(urlPath,targetDir, 6) ;
odtu.downloadFile() ;
}