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