package com.sikaijian.websiteTest;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* curl下载
* @author sikj
*
*/
public class Curl {
private static Pattern p = Pattern.compile(".*?state=(\\d+)size=(.*?)end.*?");
public static String DEFAULT_UA = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:11.0) Gecko/20100101 Firefox/11.0";
public static String TEMP_SUFFIX = ".curltemp";
// 连接超时时间
private static final int CONNECT_TIME_OUT = 1*60;
// 下载超时时间
private static final int DOWNLOAD_TIME_OUT = 10 * 60;
/**
* curl下载
* @param url 下载地址
* @param extraMap 下载附加信息
* @param savePath 下载保存路径,包含文件名称
* @param errSb 错误信息Buffer
* @return 1表示下载成功, 0表示下载失败, -1表示下载超时, -2下载返回结果中没有找到Http状态和文件大小
* @throws IOException
* @throws InterruptedException
*/
public static int curl(String url, Map extraMap,
String savePath, StringBuffer errSb) throws IOException, InterruptedException{
int state = 0;
url = encodeUrl(url);
String user_agent = DEFAULT_UA;
if(null!=extraMap){
String ua = extraMap.get("user-agent");
if(null!=ua && !"".equals(ua)){
user_agent = ua;
}
}
String tempFilePath = savePath + ".curltemp";
// 拼写下载命令
String[] cmdString = {"/bin/bash", "-c", "/usr/bin/curl "
+ " --connect-timeout " + CONNECT_TIME_OUT + " -m " + DOWNLOAD_TIME_OUT
+ " -L -w state=%{http_code}size=%{size_download}end"
+ " -A " + "\"" + user_agent + "\""
+ " -o " + tempFilePath +" "
+ url};
String resultStr = exec(Arrays.asList(cmdString));
if(resultStr.contains("timed out")){
errSb.append("下载超时");
return -1;
}
// 匹配下载输出结果中的 Http状态和文件大小
Matcher match = p.matcher(resultStr);
if(match.find()){
String stateStr = match.group(1);
String sizeStr = match.group(2);
// http状态为200 Ok
if("200".equals(stateStr)){
File downFile = new File(tempFilePath);
if(downFile.exists()){
try{
long fileSize = Long.parseLong(sizeStr);
// 比较下载下来的文件和Get请求返回的真实文件大小
if(fileSize!=downFile.length()){
errSb.append("文件下载中断,下载未完成!");
}
else{
// 下载的文件大小和真实文件大小相符合,下载成功
state = 1;
downFile.renameTo(new File(savePath));
}
}
catch(Exception e){
e.printStackTrace();
errSb.append("下载失败" + ", Http_code:" + stateStr + ";size:" + sizeStr
+";Excpetion:" + e.getMessage());
}
}else{
errSb.append("下载已完成,但文件丢失!");
}
}
else{
errSb.append("下载失败" + ", Http_code:" + stateStr);
}
}
else{
state=-2;
}
return state;
}
private static String encodeUrl(String url){
url = url.replace("&", "\\&");
url = url.replace("(", "%28");
url = url.replace(")", "%29");
return url;
}
private static String exec(List commandList) {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commandList);
builder.redirectErrorStream(true);
Process p;
StringBuffer sb = new StringBuffer();
try {
p = builder.start();
BufferedReader inputBuf = null;
String line = null;
inputBuf = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = inputBuf.readLine()) != null) {
sb.append(line);
continue;
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
// 这里线程阻塞,将等待外部转换进程运行成功运行结束后,才往下执行
try {
p.waitFor();
} catch (InterruptedException e) {
throw new RuntimeException("Curl下载过程被打断!");
}
return sb.toString();
}
// ------------------ Local Test ------------------------
public static void main(String[] args) throws Exception{
String url = "http://f.youku.com/player/getFlvPath/sid/00_00/st/flv/fileid/030002010051AC0D548F9C006CD8A1970257F7-0E3F-430C-54B7-BC27A23FD339?K=1e479c427fcf8dd5261d1204";
StringBuffer errSb = new StringBuffer();
int result = Curl.curl(url, null, "/opt/testApp/vision222.flv", errSb);
System.out.println("result:" + result + " error: " + errSb.toString());
}
}