From 4ba708bd935321a9c448f97d5f807209e1ea8c79 Mon Sep 17 00:00:00 2001 From: aohanhongzhi Date: Wed, 23 Dec 2020 09:59:09 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=E5=BD=93=E7=88=B6=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E6=97=B6=E5=80=99=E4=BC=9A?= =?UTF-8?q?=E6=8A=9B=E5=87=BA=E7=A9=BA=E6=8C=87=E9=92=88=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ejlchina/okhttps/internal/ResultBody.java | 575 +++++++++--------- 1 file changed, 288 insertions(+), 287 deletions(-) diff --git a/okhttps/src/main/java/com/ejlchina/okhttps/internal/ResultBody.java b/okhttps/src/main/java/com/ejlchina/okhttps/internal/ResultBody.java index 0d58bfe..d24c2fc 100644 --- a/okhttps/src/main/java/com/ejlchina/okhttps/internal/ResultBody.java +++ b/okhttps/src/main/java/com/ejlchina/okhttps/internal/ResultBody.java @@ -17,304 +17,305 @@ import okio.Buffer; import okio.ByteString; public class ResultBody extends AbstractBody implements Body { - - private final Response response; - private boolean onIO = false; - private OnCallback onProcess; - private long stepBytes = 0; - private double stepRate = -1; - private boolean rangeIgnored = false; - private HttpTask httpTask; - private boolean cached = false; - private byte[] data; - - ResultBody(HttpTask httpTask, Response response, TaskExecutor taskExecutor) { - super(taskExecutor, httpTask.charset(response)); - this.httpTask = httpTask; - this.response = response; - } - - - @Override - public MediaType getType() { - ResponseBody body = response.body(); - if (body != null) { - return body.contentType(); - } - return null; - } - - @Override - public long getLength() { - ResponseBody body = response.body(); - if (body != null) { - return body.contentLength(); - } - return 0; - } - - @Override + + private final Response response; + private boolean onIO = false; + private OnCallback onProcess; + private long stepBytes = 0; + private double stepRate = -1; + private boolean rangeIgnored = false; + private HttpTask httpTask; + private boolean cached = false; + private byte[] data; + + ResultBody(HttpTask httpTask, Response response, TaskExecutor taskExecutor) { + super(taskExecutor, httpTask.charset(response)); + this.httpTask = httpTask; + this.response = response; + } + + + @Override + public MediaType getType() { + ResponseBody body = response.body(); + if (body != null) { + return body.contentType(); + } + return null; + } + + @Override + public long getLength() { + ResponseBody body = response.body(); + if (body != null) { + return body.contentLength(); + } + return 0; + } + + @Override public Body nextOnIO() { - onIO = true; - return this; + onIO = true; + return this; + } + + @Override + public Body setOnProcess(OnCallback onProcess) { + if (taskExecutor == null) { + throw new IllegalStateException("没有 taskExecutor,不可设置下载进度回调!"); + } + if (cached) { + throw new IllegalStateException("开启缓存后,不可设置下载进度回调!"); + } + this.onProcess = onProcess; + return this; + } + + @Override + public Body stepBytes(long stepBytes) { + this.stepBytes = stepBytes; + return this; + } + + @Override + public Body stepRate(double stepRate) { + this.stepRate = stepRate; + return this; + } + + @Override + public Body setRangeIgnored() { + this.rangeIgnored = true; + return this; + } + + @Override + public InputStream toByteStream() { + InputStream input; + if (cached) { + input = new ByteArrayInputStream(cacheBytes()); + } else { + ResponseBody body = response.body(); + if (body != null) { + input = body.byteStream(); + } else { + input = new ByteArrayInputStream(new byte[0]); + } + } + if (onProcess != null) { + long rangeStart = getRangeStart(); + long totalBytes = getLength(); + if (!rangeIgnored) { + totalBytes += rangeStart; + } + if (stepRate > 0 && stepRate <= 1) { + stepBytes = (long) (totalBytes * stepRate); + } + if (stepBytes <= 0) { + stepBytes = Process.DEFAULT_STEP_BYTES; + } + return new ProcessInputStream(input, onProcess, totalBytes, stepBytes, + rangeIgnored ? 0 : rangeStart, taskExecutor.getExecutor(onIO)); + } + return input; + } + + @Override + public byte[] toBytes() { + if (cached) { + return cacheBytes(); + } + return bodyToBytes(); + } + + @Override + public Reader toCharStream() { + if (cached || onProcess != null) { + return new InputStreamReader(toByteStream()); + } + ResponseBody body = response.body(); + if (body != null) { + return body.charStream(); + } + return new CharArrayReader(new char[]{}); + } + + @Override + public String toString() { + if (cached || onProcess != null) { + return new String(toBytes(), charset); + } + try { + ResponseBody body = response.body(); + if (body != null) { + return new String(body.bytes(), charset); + } + } catch (IOException e) { + throw new HttpException("报文体转化字符串出错", e); + } + return null; + } + + @Override + public ByteString toByteString() { + return ByteString.of(toBytes()); } - @Override - public Body setOnProcess(OnCallback onProcess) { - if (taskExecutor == null) { - throw new IllegalStateException("没有 taskExecutor,不可设置下载进度回调!"); - } - if (cached) { - throw new IllegalStateException("开启缓存后,不可设置下载进度回调!"); - } - this.onProcess = onProcess; - return this; - } - - @Override - public Body stepBytes(long stepBytes) { - this.stepBytes = stepBytes; - return this; - } - - @Override - public Body stepRate(double stepRate) { - this.stepRate = stepRate; - return this; - } - - @Override - public Body setRangeIgnored() { - this.rangeIgnored =true; - return this; - } - - @Override - public InputStream toByteStream() { - InputStream input; - if (cached) { - input = new ByteArrayInputStream(cacheBytes()); - } else { - ResponseBody body = response.body(); - if (body != null) { - input = body.byteStream(); - } else { - input = new ByteArrayInputStream(new byte[0]); - } - } - if (onProcess != null) { - long rangeStart = getRangeStart(); - long totalBytes = getLength(); - if (!rangeIgnored) { - totalBytes += rangeStart; - } - if (stepRate > 0 && stepRate <= 1) { - stepBytes = (long) (totalBytes * stepRate); - } - if (stepBytes <= 0) { - stepBytes = Process.DEFAULT_STEP_BYTES; - } - return new ProcessInputStream(input, onProcess, totalBytes, stepBytes, - rangeIgnored ? 0 : rangeStart, taskExecutor.getExecutor(onIO)); - } - return input; - } - - @Override - public byte[] toBytes() { - if (cached) { - return cacheBytes(); - } - return bodyToBytes(); - } - - @Override - public Reader toCharStream() { - if (cached || onProcess != null) { - return new InputStreamReader(toByteStream()); - } - ResponseBody body = response.body(); - if (body != null) { - return body.charStream(); - } - return new CharArrayReader(new char[]{}); - } - - @Override - public String toString() { - if (cached || onProcess != null) { - return new String(toBytes(), charset); - } - try { - ResponseBody body = response.body(); - if (body != null) { - return new String(body.bytes(), charset); - } - } catch (IOException e) { - throw new HttpException("报文体转化字符串出错", e); - } - return null; - } - - @Override - public ByteString toByteString() { - return ByteString.of(toBytes()); - } - - @Override - public Download toFile(String filePath) { - return toFile(new File(filePath)); - } - - @Override - public Download toFile(File file) { - if (taskExecutor == null) { - throw new IllegalStateException("没有 taskExecutor, 不可进行下载操作!"); - } - if (!file.exists()) { - try { - File parent = file.getParentFile(); - if (!parent.exists()) { - parent.mkdirs(); - } - file.createNewFile(); - } catch (IOException e) { - response.close(); - throw new HttpException( - "Cannot create file [" + file.getAbsolutePath() + "]", e); - } - } - return taskExecutor.download(httpTask, file, toByteStream(), - getRangeStart()); - } - - @Override - public Download toFolder(String dirPath) { - String fileName = resolveFileName(); - String filePath = resolveFilePath(dirPath, fileName); - int index = 0; - File file = new File(filePath); - while (file.exists()) { - String indexFileName = indexFileName(fileName, index++); - filePath = resolveFilePath(dirPath, indexFileName); - file = new File(filePath); - } - return toFile(file); - } - - @Override - public Download toFolder(File dir) { - if (dir.exists() && !dir.isDirectory()) { - response.close(); - throw new HttpException("文件下载失败:文件[" + dir.getAbsolutePath() + "]已存在,并且不是一个目录!"); - } - if (!dir.exists()) { - dir.mkdirs(); - } - return toFolder(dir.getAbsolutePath()); - } - - @Override - public Body cache() { - if (onProcess != null) { - throw new IllegalStateException("设置了下载进度回调,不可再开启缓存!"); - } - cached = true; - return this; - } - - @Override - public Body close() { - response.close(); - data = null; - return this; - } - - private byte[] cacheBytes() { - synchronized (response) { - if (data == null) { - data = bodyToBytes(); - } - } - return data; - } - - private byte[] bodyToBytes() { - if (onProcess != null) { - try (Buffer buffer = new Buffer()) { - return buffer.readFrom(toByteStream()).readByteArray(); - } catch (IOException e) { - throw new HttpException("报文体转化字节数组出错", e); - } finally { - response.close(); - } - } - ResponseBody body = response.body(); - if (body != null) { - try { - return body.bytes(); - } catch (IOException e) { - throw new HttpException("报文体转化字节数组出错", e); - } - } - return new byte[0]; - } - - private long getRangeStart() { - long rangeStart = 0; - if (response.code() != HttpURLConnection.HTTP_PARTIAL) { - return rangeStart; - } - String range = response.header("Content-Range"); - if (range != null && range.startsWith("bytes")) { - int index = range.indexOf('-'); - if (index > 5) { - String start = range.substring(5, index).trim(); - try { - rangeStart = Long.parseLong(start); - } catch (Exception ignore) {} - } - } - return rangeStart; - } - - private String resolveFilePath(String dirPath, String fileName) { - if (dirPath.endsWith("\\") || dirPath.endsWith("/")) { - return dirPath + fileName; - } - return dirPath + "\\" + fileName; - } - - private String indexFileName(String fileName, int index) { - int i = fileName.lastIndexOf('.'); - if (i < 0) { - return fileName + "(" + index + ")"; - } - String ext = fileName.substring(i); - if (i > 0) { - String name = fileName.substring(0, i); - return name + "(" + index + ")" + ext; - } - return "(" + index + ")" + ext; - } - - private String resolveFileName() { - String fileName = response.header("Content-Disposition"); + @Override + public Download toFile(String filePath) { + return toFile(new File(filePath)); + } + + @Override + public Download toFile(File file) { + if (taskExecutor == null) { + throw new IllegalStateException("没有 taskExecutor, 不可进行下载操作!"); + } + if (!file.exists()) { + try { + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + parent.mkdirs(); + } + file.createNewFile(); + } catch (IOException e) { + response.close(); + throw new HttpException( + "Cannot create file [" + file.getAbsolutePath() + "]", e); + } + } + return taskExecutor.download(httpTask, file, toByteStream(), + getRangeStart()); + } + + @Override + public Download toFolder(String dirPath) { + String fileName = resolveFileName(); + String filePath = resolveFilePath(dirPath, fileName); + int index = 0; + File file = new File(filePath); + while (file.exists()) { + String indexFileName = indexFileName(fileName, index++); + filePath = resolveFilePath(dirPath, indexFileName); + file = new File(filePath); + } + return toFile(file); + } + + @Override + public Download toFolder(File dir) { + if (dir.exists() && !dir.isDirectory()) { + response.close(); + throw new HttpException("文件下载失败:文件[" + dir.getAbsolutePath() + "]已存在,并且不是一个目录!"); + } + if (!dir.exists()) { + dir.mkdirs(); + } + return toFolder(dir.getAbsolutePath()); + } + + @Override + public Body cache() { + if (onProcess != null) { + throw new IllegalStateException("设置了下载进度回调,不可再开启缓存!"); + } + cached = true; + return this; + } + + @Override + public Body close() { + response.close(); + data = null; + return this; + } + + private byte[] cacheBytes() { + synchronized (response) { + if (data == null) { + data = bodyToBytes(); + } + } + return data; + } + + private byte[] bodyToBytes() { + if (onProcess != null) { + try (Buffer buffer = new Buffer()) { + return buffer.readFrom(toByteStream()).readByteArray(); + } catch (IOException e) { + throw new HttpException("报文体转化字节数组出错", e); + } finally { + response.close(); + } + } + ResponseBody body = response.body(); + if (body != null) { + try { + return body.bytes(); + } catch (IOException e) { + throw new HttpException("报文体转化字节数组出错", e); + } + } + return new byte[0]; + } + + private long getRangeStart() { + long rangeStart = 0; + if (response.code() != HttpURLConnection.HTTP_PARTIAL) { + return rangeStart; + } + String range = response.header("Content-Range"); + if (range != null && range.startsWith("bytes")) { + int index = range.indexOf('-'); + if (index > 5) { + String start = range.substring(5, index).trim(); + try { + rangeStart = Long.parseLong(start); + } catch (Exception ignore) { + } + } + } + return rangeStart; + } + + private String resolveFilePath(String dirPath, String fileName) { + if (dirPath.endsWith("\\") || dirPath.endsWith("/")) { + return dirPath + fileName; + } + return dirPath + "\\" + fileName; + } + + private String indexFileName(String fileName, int index) { + int i = fileName.lastIndexOf('.'); + if (i < 0) { + return fileName + "(" + index + ")"; + } + String ext = fileName.substring(i); + if (i > 0) { + String name = fileName.substring(0, i); + return name + "(" + index + ")" + ext; + } + return "(" + index + ")" + ext; + } + + private String resolveFileName() { + String fileName = response.header("Content-Disposition"); // 通过Content-Disposition获取文件名,这点跟服务器有关,需要灵活变通 if (fileName == null || fileName.length() < 1) { - fileName = response.request().url().encodedPath(); + fileName = response.request().url().encodedPath(); fileName = fileName.substring(fileName.lastIndexOf("/") + 1); } else { try { - fileName = URLDecoder.decode(fileName.substring( - fileName.indexOf("filename=") + 9), "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new HttpException("解码文件名失败", e); - } + fileName = URLDecoder.decode(fileName.substring( + fileName.indexOf("filename=") + 9), "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new HttpException("解码文件名失败", e); + } // 有些文件名会被包含在""里面,所以要去掉,不然无法读取文件后缀 fileName = fileName.replaceAll("\"", ""); } return fileName; - } + } } -- Gitee From 29414f1bf071a596acd47d4b3246ab865c569bbb Mon Sep 17 00:00:00 2001 From: aohanhongzhi Date: Wed, 23 Dec 2020 14:44:42 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=E5=BD=93=E7=88=B6=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E6=97=B6=E5=80=99=E4=BC=9A?= =?UTF-8?q?=E6=8A=9B=E5=87=BA=E7=A9=BA=E6=8C=87=E9=92=88=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../okhttps/test/OkhttpsDownload.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 okhttps-test/src/main/java/com/ejlchina/okhttps/test/OkhttpsDownload.java diff --git a/okhttps-test/src/main/java/com/ejlchina/okhttps/test/OkhttpsDownload.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/OkhttpsDownload.java new file mode 100644 index 0000000..cce16f9 --- /dev/null +++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/OkhttpsDownload.java @@ -0,0 +1,60 @@ +package com.ejlchina.okhttps.test; + +import com.ejlchina.okhttps.OkHttps; + + +import java.io.File; + +import static java.lang.Thread.sleep; + +/** + * @author eric + * @program bytecode + * @description 下载 + * @date 2020/12/23 + */ +public class OkhttpsDownload { + + static String url = "https://typora.io/windows/typora-setup-x64.exe"; + + public static void main(String[] args) { + System.out.println("程序开始了"); + + long totalSize = OkHttps.sync(url).get() +// .getBody() + .close() // 因为这次请求只是为了获得文件大小,不消费报文体,所以直接关闭 + .getContentLength(); // 获得待下载文件的大小(由于未消费报文体,所以该请求不会消耗下载报文体的时间和网络流量) + + download(totalSize, 0); // 从第 0 块开始下载 + System.out.println("download跑完了"); + + try { + sleep(50000); // 等待下载完成(不然本例的主线程就结束啦) + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("程序跑完了"); + + } + + static void download(long totalSize, int index) { + System.out.println("===>"+index); + + long size = 3 * 1024 * 1024; // 每块下载 3M + long start = index * size; + long end = Math.min(start + size, totalSize); + OkHttps.sync(url) + .setRange(start, end) // 设置本次下载的范围 + .get().getBody() + .toFile("D:/download/typora-setup-x64.exe") // 下载到同一个文件里 + .setAppended() // 开启文件追加模式 + .setOnSuccess((File file) -> { + if (end < totalSize) { // 若未下载完,则继续下载下一块 + download(totalSize, index + 1); + } else { + System.out.println("下载完成"); + } + }) + .start(); + } +} -- Gitee From ec3ba24fcb876f17931c5029186ccd647505d76c Mon Sep 17 00:00:00 2001 From: aohanhongzhi Date: Thu, 24 Dec 2020 09:30:06 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=E5=BD=93=E7=88=B6=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E6=97=B6=E5=80=99=E4=BC=9A?= =?UTF-8?q?=E6=8A=9B=E5=87=BA=E7=A9=BA=E6=8C=87=E9=92=88=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ejlchina/okhttps/test/eric/Download2.java | 60 +++++++++++++++++++ .../test/{ => eric}/OkhttpsDownload.java | 7 ++- 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 okhttps-test/src/main/java/com/ejlchina/okhttps/test/eric/Download2.java rename okhttps-test/src/main/java/com/ejlchina/okhttps/test/{ => eric}/OkhttpsDownload.java (89%) diff --git a/okhttps-test/src/main/java/com/ejlchina/okhttps/test/eric/Download2.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/eric/Download2.java new file mode 100644 index 0000000..3c17f70 --- /dev/null +++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/eric/Download2.java @@ -0,0 +1,60 @@ +package com.ejlchina.okhttps.test.eric; + +import com.ejlchina.okhttps.OkHttps; + +import java.io.File; + +import static java.lang.Thread.sleep; + +/** + * @author eric + * @program okhttps-parent + * @description + * @date 2020/12/24 + */ +public class Download2 { + static String url = "https://typora.io/windows/typora-setup-x64.exe"; + + public static void main(String[] args) { + System.out.println("程序开始了"); + + long totalSize = OkHttps.sync(url).get() +// .getBody() + .close() // 因为这次请求只是为了获得文件大小,不消费报文体,所以直接关闭 + .getContentLength(); // 获得待下载文件的大小(由于未消费报文体,所以该请求不会消耗下载报文体的时间和网络流量) + download(totalSize, 0); // 从第 0 块开始下载 + System.out.println("download跑完了"); + System.out.println("线程开始沉睡"); + + try { + sleep(50000); // 等待下载完成(不然本例的主线程就结束啦) + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("程序跑完了"); + + } + + + + static void download(long totalSize, int index) { + System.out.println("===>" + index); + + long size = 3 * 1024 * 1024; // 每块下载 3M + long start = index * size; + long end = Math.min(start + size, totalSize); + OkHttps.sync(url) + .setRange(start, end) // 设置本次下载的范围 + .get().getBody() + .toFile("D:/download/typora-setup-x64-5.exe") // 下载到同一个文件里 + .setAppended() // 开启文件追加模式 + .setOnSuccess((File file) -> { + if (end < totalSize) { // 若未下载完,则继续下载下一块 + download(totalSize, index + 1); + } else { + System.out.println("下载完成"); + } + }) + .start(); + } +} diff --git a/okhttps-test/src/main/java/com/ejlchina/okhttps/test/OkhttpsDownload.java b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/eric/OkhttpsDownload.java similarity index 89% rename from okhttps-test/src/main/java/com/ejlchina/okhttps/test/OkhttpsDownload.java rename to okhttps-test/src/main/java/com/ejlchina/okhttps/test/eric/OkhttpsDownload.java index cce16f9..5c56968 100644 --- a/okhttps-test/src/main/java/com/ejlchina/okhttps/test/OkhttpsDownload.java +++ b/okhttps-test/src/main/java/com/ejlchina/okhttps/test/eric/OkhttpsDownload.java @@ -1,4 +1,4 @@ -package com.ejlchina.okhttps.test; +package com.ejlchina.okhttps.test.eric; import com.ejlchina.okhttps.OkHttps; @@ -27,6 +27,7 @@ public class OkhttpsDownload { download(totalSize, 0); // 从第 0 块开始下载 System.out.println("download跑完了"); + System.out.println("线程开始沉睡"); try { sleep(50000); // 等待下载完成(不然本例的主线程就结束啦) @@ -38,7 +39,7 @@ public class OkhttpsDownload { } static void download(long totalSize, int index) { - System.out.println("===>"+index); + System.out.println("===>" + index); long size = 3 * 1024 * 1024; // 每块下载 3M long start = index * size; @@ -46,7 +47,7 @@ public class OkhttpsDownload { OkHttps.sync(url) .setRange(start, end) // 设置本次下载的范围 .get().getBody() - .toFile("D:/download/typora-setup-x64.exe") // 下载到同一个文件里 + .toFile("D:/download/typora-setup-x64-2.exe") // 下载到同一个文件里 .setAppended() // 开启文件追加模式 .setOnSuccess((File file) -> { if (end < totalSize) { // 若未下载完,则继续下载下一块 -- Gitee