需求
有一个http链接,需要我针对大文件分片下载byte数组,然后将这些byte数组合并。
因为是前期的开发,上传的都是小文件,并且也没有并发。但是一旦上线,上传文件就会出现IO阻塞等问题。
关键
我们要知道http里面有个参数,它将自动帮助我们完成网络请求文件分片
比如:有一个4字节的文件,这时我么需要分片,我就可以这样分片后,for循环多次请求。
Range:bytes=0-2
Range:bytes=2-4
Range:bytes=4-0
实现
/**
* 输入流导出byte数组
*
* @param is 文件输入流
* @return 文件byte数组
* @throws IOException IO读取异常
*/
public static byte[] inputStreamToByte(InputStream is) throws IOException {
return IOUtils.toByteArray(is);
}
/**
* 内部方法,获取远程文件大小
*
* @param remoteFileUrl 网络连接
* @return 远程文件大小
* @throws IOException IO读取异常
*/
public static long getRemoteFileSize(String remoteFileUrl) throws IOException {
long fileSize = 0;
HttpURLConnection httpConnection = (HttpURLConnection) new URL(remoteFileUrl).openConnection();
httpConnection.setRequestMethod("HEAD");
int responseCode = 0;
try {
responseCode = httpConnection.getResponseCode();
} catch (IOException e) {
e.printStackTrace();
}
if (responseCode >= HttpURLConnection.HTTP_BAD_REQUEST) {
return 0;
}
String sHeader;
for (int i = 1; ; i++) {
sHeader = httpConnection.getHeaderFieldKey(i);
if (sHeader != null && sHeader.equals(HttpEncoding.CONTENT_LENGTH)) {
fileSize = Long.parseLong(httpConnection.getHeaderField(sHeader));
break;
}
}
return fileSize;
}
/**
* 获取不分片的文件byte数组
*
* @param url 网络连接
* @return 不分片的文件byte数组
* @throws IOException IO读取异常
*/
public static byte[] getHtmlByteArrayNotSplice(String url) throws IOException {
return getHtmlByteByFileSize(url).get(0);
}
/**
* 根据文件大小是否启用多线程分片
*
* @param url 网络连接
* @return 多个文件byte数组
* @throws IOException IO读取异常
*/
public static List<byte[]> getHtmlByteByFileSize(String url) throws IOException {
long remoteFileSize = getRemoteFileSize(url);
List<byte[]> results = new ArrayList<>();
// 设定文件分块大小,设定40M
long chunkSize = 1024 * 1024 * 40;
// 文件太小,不分片的场合
if (chunkSize > remoteFileSize) {
byte[] htmlByteArray = getHtmlByteArray(url);
results.add(htmlByteArray);
return results;
}
// 分块数量
long chunkNum = (long) Math.ceil(remoteFileSize * 1.0 / chunkSize);
FileSpliceResultVo fileSplice = getFileSplice(remoteFileSize, chunkNum);
for (SpliceDetailVo spliceDetail : fileSplice.getSpliceDetail()) {
String range = spliceDetail.getRange();
byte[] htmlByteSplice = getHtmlByteSplice(url, range);
results.add(htmlByteSplice);
}
return results;
}
/**
* 获取网络连接返回文件byte数组
*
* @param url 网络连接
* @return 文件byte数组
* @throws IOException IO读取异常
*/
public static byte[] getHtmlByteArray(final String url) throws IOException {
URL htmlUrl = null;
InputStream inStream = null;
htmlUrl = new URL(url);
URLConnection connection = htmlUrl.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setConnectTimeout(5 * 1000);
httpConnection.setReadTimeout(5 * 1000);
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_PARTIAL) {
inStream = httpConnection.getInputStream();
}
return inputStreamToByte(inStream);
}
测试
public static void main(String[] args) {
try {
File file2 = new File("F:\\Downloads\\xxx.docx");
OutputStream out = new FileOutputStream(file2,true);
String url = "http://xxx.docx";
List<byte[]> htmlByteByFileSize = FileTest.getHtmlByteByFileSize(url);
for (byte[] data: htmlByteByFileSize)
out.write(data);
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}