先放调试好的代码
/**
* 从网络Url中下载文件
*
* @param urlStr 视频文件路径
* @param fileName 本地生成的视频文件名称
* @param savePath 本地生成的视频文件保存路径
*/
public File downLoadFromUrl(String urlStr, String fileName, String savePath) {
File file = null;
try {
logger.info("准备下载文件["+fileName+"]...");
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
logger.info("已和["+urlStr+"]建立连接...");
// 设置超时间为10秒。
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
// 防止屏蔽程序抓取而返回403错误
conn.setRequestProperty(
"User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
logger.info("["+urlStr+"]准备获取返回...");
// 得到输入流
InputStream inputStream = conn.getInputStream();
logger.info("["+urlStr+"]取得返回的输入流 || " + inputStream);
int count = 0;
int idx = 0;
count = conn.getContentLength();
/*while (idx < 10) {
idx++;
try {
count = inputStream.available();
} catch (Exception ex) {
logger.info("获取字节数异常:", ex);
}
if (count == 0) {
Thread.sleep(240);
} else {
Thread.sleep(120);
}
}*/
logger.info("取得的字节数:" + count);
// 获取自己数组
byte[] getData = readBytesContent(inputStream, count);
logger.info("获取视频数据流长度:" + (getData != null ? getData.length : "未获取到视频数据"));
// 文件保存位置
file = getFileByBytesAndResturn(getData, savePath, fileName);
logger.info("info:" + url + " download success");
} catch (Exception ex) {
logger.error("获取视频异常["+fileName+"]:", ex);
}
return file;
}
/**
* 输入流的字节数据读取
* @param input 输入流
* @param bytesLength 输入流总的字节长度
* @return
* @throws Exception
*/
private byte[] readBytesContent(InputStream input,int bytesLength) throws Exception {
logger.info("准备转换成字节数组...");
int bytesRead = 0;
int n = 0;
int leftbytes = bytesLength;
byte[] in_b = new byte[bytesLength];
while (leftbytes > 0
&& (n = input.read(in_b, bytesRead, leftbytes)) != -1) {
bytesRead = bytesRead + n;
leftbytes = bytesLength - bytesRead;
}
return in_b;
}
/**
* 将Byte数组转换成文件并返回
*
* @param bytes
* @param filePath 文件保存路径
* @param fileName 文件名称
* @return
*
*/
public File getFileByBytesAndResturn(byte[] bytes, String filePath, String fileName) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try {
File dir = new File(filePath);
if (!dir.exists()) {// 判断文件目录是否存在
dir.mkdirs();
}
file = new File(filePath + "\\" + fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(bytes);
} catch (Exception e) {
logger.error("生成文件异常:", e);
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
logger.error("关闭BufferedOutputStream异常:", e);
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
logger.error("关闭FileOutputStream异常:", e);
}
}
}
return file;
}
我是把这个方法放到线程里的,一开始使用的是不获取输入流中的字节长度,直接读取的输入流,但是实际使用的时候有时会出现线程阻塞的问题。
/**
* 从输入流中获取字节数组
* 这种方法在线程里使用,有时会出现线程阻塞,导致出现有的文件下载不下来的问题
*
* @param inputStream
* @return
* @throws Exception
*/
public byte[] readInputStream(InputStream inputStream) throws Exception {
logger.info("准备转换成字节数组...");
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}
获取输入流的字节长度用conn.getContentLength();方法获取到的是完整的,一开始使用的是inputStream.available();方法、但是这个方法获取网络文件的大小不好用,后改为的conn.getContentLength()。
还有超时时间的设置,连接超时和读取超时都要设置,一开始只设置了连接超时也有点小问题。