diff --git a/min/FileBPRenewal.properties b/min/FileBPRenewal.properties new file mode 100644 index 0000000..369c985 --- /dev/null +++ b/min/FileBPRenewal.properties @@ -0,0 +1,5 @@ +#commit changes +#Fri Nov 06 17:19:27 CST 2020 +filePoint-2879941E9BB27B30BDC1235CC3B80CEC5A66153C5D117A18A129A9A40C9EA4453B8ADC1001EB791D6763A5CC72B5B58F5E712434666FE889F569CC44E05BC68B38CEA774067E8FA17346D5A1B2771B0551C8881DC90A978ED404134D87D5D2433F3ECCBFDDCF07C7C959369553543F441169D7A23CFFA50F69DAE85ECCBFACCB854776C82E54FDFF19B63213373583184C5AC3F61F7E4CD78AABA4D7CF794866A887F99432A67B81A86D2456E023720707366C175BEA530CC13DEA961E62244C821549B5C7730F20BD93429070CDD1C61A2165A39268318A742AA9B109B3A3BE6DDB36C4352D2F738188EFFDE41B6123=B8BBF8A24FA481E4A861C3CC610F57A6 +fileServerPath-2879941E9BB27B30BDC1235CC3B80CEC5A66153C5D117A18A129A9A40C9EA4453B8ADC1001EB791D6763A5CC72B5B58F5E712434666FE889F569CC44E05BC68B38CEA774067E8FA17346D5A1B2771B0551C8881DC90A978ED404134D87D5D2433F3ECCBFDDCF07C7C959369553543F441169D7A23CFFA50F69DAE85ECCBFACCB854776C82E54FDFF19B63213373583184C5AC3F61F7E4CD78AABA4D7CF794866A887F99432A67B81A86D2456E023720707366C175BEA530CC13DEA961E62244C821549B5C7730F20BD93429070CDD1C61A2165A39268318A742AA9B109B3A3BE6DDB36C4352D2F738188EFFDE41B6123=24B14C90089CD398802AD5610E3E6A22 +fileName-2879941E9BB27B30BDC1235CC3B80CEC5A66153C5D117A18A129A9A40C9EA4453B8ADC1001EB791D6763A5CC72B5B58F5E712434666FE889F569CC44E05BC68B38CEA774067E8FA17346D5A1B2771B0551C8881DC90A978ED404134D87D5D2433F3ECCBFDDCF07C7C959369553543F441169D7A23CFFA50F69DAE85ECCBFACCB854776C82E54FDFF19B63213373583184C5AC3F61F7E4CD78AABA4D7CF794866A887F99432A67B81A86D2456E023720707366C175BEA530CC13DEA961E62244C821549B5C7730F20BD93429070CDD1C61A2165A39268318A742AA9B109B3A3BE6DDB36C4352D2F738188EFFDE41B6123=3B35BD05A292F4C18EFE1F8C5AC312F349DF5188BBA8183ED8C96ED7CB946855EF95C39E8B8C29DEFCC82B690256C74F diff --git a/min/log.txt b/min/log.txt index eff87e6..24b1922 100644 --- a/min/log.txt +++ b/min/log.txt @@ -20,3 +20,12 @@ 文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/20200822-%E5%91%A8%E6%8A%A5-%E5%88%98%E6%B6%9B.pptx 文件操作:下载 文件耗时:525ms 文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/ppov%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95-8.21(1).docx 文件操作:下载 文件耗时:263ms 文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/20200822-%E5%91%A8%E6%8A%A5-%E5%88%98%E6%B6%9B.pptx 文件操作:下载 文件耗时:433ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/%E5%91%A8%E6%8A%A5-%E9%98%99%E5%BB%BA%E6%98%8E-2020.08.22.pdf 文件操作:下载 文件耗时:581ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/%E8%82%96%E6%8C%AF%E5%A8%81%E5%91%A8%E6%8A%A5-20200821.pptx 文件操作:下载 文件耗时:723ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/%E8%82%96%E6%8C%AF%E5%A8%81%E5%91%A8%E6%8A%A5-20200821.pptx 文件操作:下载 文件耗时:342ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/%E5%90%B4%E6%94%BF%E7%90%AA%E5%91%A8%E6%8A%A5-20200821(1).pptx 文件操作:下载 文件耗时:9323ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/upupoo%E5%8D%95%E6%9C%BA%E7%89%8820200119.exe 文件操作:下载 文件耗时:30741ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/upupoo%E5%8D%95%E6%9C%BA%E7%89%8820200119.exe 文件操作:下载 文件耗时:73358ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/%E9%9F%A6%E5%9B%BD%E5%8D%8E%E5%91%A8%E6%8A%A5-20200822.pptx 文件操作:下载 文件耗时:388ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/upupoo%E5%8D%95%E6%9C%BA%E7%89%8820200119.exe 文件操作:下载 文件耗时:34951ms +文件名:/MIN/Nginx/test2/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/%E4%BF%A1%E6%81%AF%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%BA%94%E7%94%A8%E6%8A%80%E6%9C%AF/A218/upupoo%E5%8D%95%E6%9C%BA%E7%89%8820200119.exe 文件操作:下载 文件耗时:11545ms diff --git a/min/settings.properties b/min/settings.properties index 276e1e6..b542824 100644 --- a/min/settings.properties +++ b/min/settings.properties @@ -1,6 +1,6 @@ #\u4FEE\u6539\u914D\u7F6E\u6587\u4EF6 -#Sun Nov 01 18:58:43 CST 2020 -ServerIPAddress=121.15.171.92 +#Fri Nov 06 15:29:27 CST 2020 +ServerIPAddress=192.168.25.25 MIS_PORT=6363 DataPackagePrefix=/MIN/Nginx/test2 ServerPortAddress=6363 diff --git a/src/main/java/cn/minbrowser/MiniMinData/FileTransfer/DownLoadClientBasedFacePool.java b/src/main/java/cn/minbrowser/MiniMinData/FileTransfer/DownLoadClientBasedFacePool.java index dcf9c2c..a2a5f91 100644 --- a/src/main/java/cn/minbrowser/MiniMinData/FileTransfer/DownLoadClientBasedFacePool.java +++ b/src/main/java/cn/minbrowser/MiniMinData/FileTransfer/DownLoadClientBasedFacePool.java @@ -1,10 +1,7 @@ package cn.minbrowser.MiniMinData.FileTransfer; import cn.minbrowser.MiniMinData.KeyManager; -import cn.minbrowser.MiniMinData.util.FacePool; -import cn.minbrowser.MiniMinData.util.FileLengthUtil; -import cn.minbrowser.MiniMinData.util.FilePathUtil; -import cn.minbrowser.MiniMinData.util.OrderIPrefixUtil; +import cn.minbrowser.MiniMinData.util.*; import net.named_data.jndn.*; import net.named_data.jndn.security.KeyChain; import net.named_data.jndn.security.SecurityException; @@ -63,6 +60,15 @@ public class DownLoadClientBasedFacePool { private AtomicBoolean isCancelFileTransferFlag=new AtomicBoolean(false); private Integer sliceSize; + // 断点续传:此偏移量/序号之前的文件部分已经全部传输成功 + private AtomicLong successPoint=new AtomicLong(1); + // 断点续传:point及其之后的兴趣包,已经传输成功的兴趣包序号 + private Map successList = new ConcurrentHashMap<>(); + // 断点续传:当前文件哈希值/其它可以唯一标识该文件的String + private String fileHashString; + // 是否开启断点续传 + private boolean BPRswitch=true; + /** * 文件传输构造器 * @param filename 要下载的文件在linux上的相对路径 @@ -85,6 +91,7 @@ public class DownLoadClientBasedFacePool { this.facePool=new FacePool(facepoolnumber); this.facePool.start(minServerIpString,minServerPortInteger); System.out.println("***********FacePool中并发数:"+facepoolnumber+"***********"); + fileHashString=filename+"_"+sliceNumber; // 先初始化一个本地文件 try { String localName= FilePathUtil.getPureFileNameFromLinux(filename); @@ -95,6 +102,65 @@ public class DownLoadClientBasedFacePool { } } + /** 断点续传: + * 传入一个刚被后台成功响应的兴趣包序号, + * 判断[point,current]之间的兴趣包序号是否全部被成功响应 + */ + private boolean isAllOK(Long point,Long currentNo){ + for(Long i=point;i<=currentNo;i++){ + if(!successList.containsKey(i)){ + return false; + } + } + return true; + } + + /** 断点续传: + * 移除successList中已经成功发送的部分,减少内存占用 + */ + private void mvSuccessNum(Long fromNo,Long toNo){ + for(Long i=fromNo;i<=toNo;i++){ + successList.remove(i); + } + } + + /** 断点续传: + * 对每个成功收到200应答的兴趣包执行如下程序,以维持断点续传的功能 + * @param sliceNo + */ + private void refreshSuccessPoint(Long sliceNo){ + // 当前断点 + Long point=successPoint.get(); + // 加入successList + successList.put(sliceNo,true); + // 如果当前断点到新收到数据包之间的兴趣包全部成功响应, + // 更新断点,并清理内存 + if(isAllOK(point,sliceNo)){ + successPoint.getAndSet(sliceNo+1); + mvSuccessNum(point,sliceNo); + } + } + + /** 断点续传: + * 将本次传输的断点信息保存到本地 + */ + public void setPointInfo(){ + String fileName=FilePathUtil.getPureFileNameFromLinux(filename); + FileBPRUtil.setUploadBreakPointInfo( + fileHashString,fileName,localDir,successPoint.get()); + System.out.println("保存断点信息成功!!!"); + } + + /** 断点续传: + * 移除已经上传成功的文件断点信息 + */ + private void rmPointInfo(){ + if(FileBPRUtil.isHaveUploadBreakPointInfo(fileHashString)){ + FileBPRUtil.deleteUploadBreakPointInfo(fileHashString); + } + } + + /** * 判断是否含有超时次数超过阈值的 * @return @@ -136,10 +202,31 @@ public class DownLoadClientBasedFacePool { * @return */ public boolean downloadData() { - // flag: 标志传输结束状态。0-尚未传输,1-全部传输完成;2-主动中断下载;3-网络状况不佳 Integer transferFlag=0; + /** + * 断点续传:判断是否有断点续传记录 + */ + if(FileBPRUtil.isHaveUploadBreakPointInfo(fileHashString)&&BPRswitch){ + // 有记录,则判断文件名和服务器地址是否一致 + FileBPRUtil.BPRInfo bprInfo=FileBPRUtil.getUploadBreakPointInfo(fileHashString); + String fileName=FilePathUtil.getPureFileNameFromLinux(filename); + if((!(bprInfo==null)) + &&bprInfo.getFileName().equals(fileName) + &&bprInfo.getFileLocator().equals(localDir)){ + // 都一致,则更新recvCount\currentOffset\successPoint + System.out.println("即将开始断点续传..."); + recvCount.getAndSet(bprInfo.getPoint()); + currentSliceNo=(int)recvCount.get(); + successPoint.getAndSet(bprInfo.getPoint()); + }else{ + System.out.println("即将开始文件下载..."); + } + }else { + System.out.println("即将开始文件下载..."); + } + while (true) { //判断是否已经上传安成 if (recvCount.longValue()>=this.sliceNumber) { @@ -206,8 +293,14 @@ public class DownLoadClientBasedFacePool { } // 如果文件传输正常完成,就返回true if(transferFlag==1){ + if(BPRswitch){ + rmPointInfo(); + } return true; }else{ + if(BPRswitch){ + setPointInfo(); + } return false; } } @@ -288,6 +381,9 @@ public class DownLoadClientBasedFacePool { // System.out.println("interest: "+interest.getName().toString()); // System.out.println("data: "+data.getContent().toString()); System.out.println("写入文件数据分片完毕:" + localDir + localName); + if(BPRswitch){ + refreshSuccessPoint((long) sliceNo); + } } } catch (IOException e) { // TODO Auto-generated catch block diff --git a/src/main/java/cn/minbrowser/MiniMinData/util/FacePool.java b/src/main/java/cn/minbrowser/MiniMinData/util/FacePool.java index 09e0f6d..7ff4423 100644 --- a/src/main/java/cn/minbrowser/MiniMinData/util/FacePool.java +++ b/src/main/java/cn/minbrowser/MiniMinData/util/FacePool.java @@ -2,9 +2,9 @@ package cn.minbrowser.MiniMinData.util; import net.named_data.jndn.Face; import net.named_data.jndn.encoding.EncodingException; +import net.named_data.jndn.transport.UdpTransport; import java.io.IOException; -import java.util.ArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; @@ -18,36 +18,43 @@ public class FacePool { // 采用阻塞队列来记录任务 private LinkedBlockingQueue faceLinkedBlockingQueue; - private ArrayList faces; - private ExecutorService processEventThreadPool; private ExecutorService faceDealThreadPool; public FacePool(int poolSize) { this.poolSize = poolSize; - faces = new ArrayList<>(); processEventThreadPool = Executors.newFixedThreadPool(poolSize); faceDealThreadPool = Executors.newFixedThreadPool(poolSize); faceLinkedBlockingQueue = new LinkedBlockingQueue<>(); } - public FacePool start(String host, int port) { + public FacePool start(String host, int port, boolean udp) { for (int i = 0; i < poolSize; i++) { - faces.add(new Face(host, port)); - final int finalI = i; - ProcessEventTask processEventTask = new ProcessEventTask(host, port, faces.get(i), i, task -> { + Face face; + if (udp) { + face = new Face(new UdpTransport(), new UdpTransport.ConnectionInfo(host, port)); + System.out.println("use udp"); + } else { + System.out.println("use tcp"); + face = new Face(host, port); + } + ProcessEventTask processEventTask = new ProcessEventTask(host, port, face, i, task -> { // 发生错误则自动重新创建face,建立连接,然后将processEvent任务提交到线程池当中 processEventThreadPool.submit(task); - faces.set(finalI, task.getFace()); + faceLinkedBlockingQueue.add(task.getFace()); }); processEventThreadPool.submit(processEventTask); // 初始时Face池里所有的Face都是可用的 - faceLinkedBlockingQueue.add(faces.get(i)); + faceLinkedBlockingQueue.add(face); } return this; } + public FacePool start(String host, int port) { + return start(host, port, false); + } + public FacePool submit(AsyncUseFaceCallback asyncUseFaceCallback) { faceDealThreadPool.submit(() -> { try { @@ -139,15 +146,13 @@ public class FacePool { @Override public void run() { -// System.out.println("faceId: " + id + "(host: " + host + ", port: " + port + ") -> start"); try { while (true) { face.processEvents(); -// System.out.println("faceId: " + id + " -> processEvent"); Thread.sleep(1); } } catch (IOException | EncodingException | InterruptedException e) { - System.out.println(e.getMessage()); + e.printStackTrace(); this.face = new Face(this.host, this.port); if (this.statusCallback != null) { this.statusCallback.onError(this); diff --git a/src/main/java/cn/minbrowser/MiniMinData/util/FileBPRUtil.java b/src/main/java/cn/minbrowser/MiniMinData/util/FileBPRUtil.java new file mode 100644 index 0000000..720e6b4 --- /dev/null +++ b/src/main/java/cn/minbrowser/MiniMinData/util/FileBPRUtil.java @@ -0,0 +1,265 @@ +package cn.minbrowser.MiniMinData.util; + +import cn.minbrowser.util.Encryption.EncryptionUtil; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Properties; + +// 文件断点续传支持类 +// 功能:存储和移除传输失败的文件信息 +public class FileBPRUtil { + + public static String fileBPRDir="." + File.separator + "min" + File.separator + "FileBPRenewal.properties"; + + // 判断某md5哈希值是否在本地存储条目中 + public static boolean isHaveUploadBreakPointInfo(String hashString) { + // 加密 + hashString=EncryptionUtil.encryptBasedAES(hashString); + InputStream inputStream = null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream = new BufferedInputStream(new FileInputStream(fileBPRDir)); + if (inputStream == null) { + System.out.println("没有找到断点续传配置文件..."); + return false; + } + BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + Properties settingProperties = new Properties(); + settingProperties.load(bf); + String filename=settingProperties.getProperty("fileName-"+hashString); + System.out.println(hashString+" : "+filename); + if(filename==null){ + return false; + }else{ + System.out.println("本地存在该文件的断点信息:"+hashString); + return true; + } + } catch (IOException e) { +// e.printStackTrace(); + return false; + } finally { + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +// public static boolean isHaveDownloadBreakPointInfo(String fileUrlString) { +// return isHaveUploadBreakPointInfo(fileUrlString); +// } + + + // 存储上传文件断点信息到本地 + public static void setUploadBreakPointInfo(String hashString, + String pureFileName, + String serverPath, + Long point){ + // 加密 + hashString=EncryptionUtil.encryptBasedAES(hashString); + pureFileName=EncryptionUtil.encryptBasedAES(pureFileName); + serverPath=EncryptionUtil.encryptBasedAES(serverPath); + String pointString=EncryptionUtil.encryptBasedAES(point.toString()); + InputStream inputStream = null; + OutputStream outputStream=null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream=new BufferedInputStream(new FileInputStream(fileBPRDir)); + if (inputStream == null) { + System.out.println("没有找到断点续传配置文件..."); + } + BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + Properties settingProperties = new Properties(); + settingProperties.load(bf); + settingProperties.setProperty("fileName-"+hashString, pureFileName); + settingProperties.setProperty("fileServerPath-"+hashString,serverPath); + settingProperties.setProperty("filePoint-"+hashString, pointString); + outputStream=new BufferedOutputStream(new FileOutputStream(fileBPRDir)); + BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); + settingProperties.store(bw,"commit changes"); + } catch (IOException e) { + e.printStackTrace(); + }finally{ + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + //关闭输出流 + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + // 移除上传文件的断点信息 + public static void deleteUploadBreakPointInfo(String hashString){ + // 加密 + hashString=EncryptionUtil.encryptBasedAES(hashString); + InputStream inputStream = null; + OutputStream outputStream=null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream=new BufferedInputStream(new FileInputStream(fileBPRDir)); + if (inputStream == null) { + System.out.println("没有找到断点续传配置文件..."); + } + BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + Properties settingProperties = new Properties(); + settingProperties.load(bf); + settingProperties.remove("fileName-"+hashString); + settingProperties.remove("fileServerPath-"+hashString); + settingProperties.remove("filePoint-"+hashString); + outputStream=new BufferedOutputStream(new FileOutputStream(fileBPRDir)); + BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); + settingProperties.store(bw,"commit changes"); + } catch (IOException e) { + e.printStackTrace(); + }finally{ + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + //关闭输出流 + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + +// public static void setDownloadBreakPointInfo(String fileUrlString, +// String pureFileName, +// String localPath, +// Long point){ +// setUploadBreakPointInfo(fileUrlString,pureFileName,localPath,point); +// } +// +// public static void deleteDownloadBreakPointInfo(String fileUrlString){ +// deleteUploadBreakPointInfo(fileUrlString); +// } + + // 取出上传文件断点信息到本地 + public static BPRInfo getUploadBreakPointInfo(String hashString) { + // 加密 + hashString=EncryptionUtil.encryptBasedAES(hashString); + InputStream inputStream = null; + try { + //如果 classPath 不存在,则获取的输入流会为 null + inputStream = new BufferedInputStream(new FileInputStream(fileBPRDir)); + if (inputStream == null) { + System.out.println("没有找到断点续传配置文件..."); + } + BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + Properties settingProperties = new Properties(); + settingProperties.load(bf); + BPRInfo bprInfo=new BPRInfo(); + bprInfo.setFileId(hashString); + bprInfo.setFileName(EncryptionUtil.decryptBasedAES(settingProperties.getProperty("fileName-"+hashString))); + bprInfo.setFileLocator(EncryptionUtil.decryptBasedAES(settingProperties.getProperty("fileServerPath-"+hashString))); + bprInfo.setPoint(Long.parseLong(EncryptionUtil.decryptBasedAES(settingProperties.getProperty("filePoint-"+hashString)))); + System.out.println("util-文件名:"+bprInfo.getFileName()); + System.out.println("util-文件断点:"+bprInfo.getPoint()); + System.out.println("util-文件路径:"+bprInfo.getFileLocator()); + if((bprInfo.getFileName()==null)||(bprInfo.getPoint()==null)||(bprInfo.getFileLocator()==null)){ + return null; + } + return bprInfo; + } catch (IOException e) { + e.printStackTrace(); + } finally { + //关闭输入流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + } + + public static class BPRInfo { + + // 文件唯一标识:上传中指的是哈希值,下载中指的是文件服务器URL + // 现在上传和下载的该数值全部定义为:纯文件名_文件长度 + private String fileId; + // 文件名称 + private String fileName; + // 文件位置:上传中指的是文件服务器位置,下载中指的是文件本地位置 + private String fileLocator; + // 断点续传位置 + private Long point; + + public BPRInfo(){ + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getFileLocator() { + return fileLocator; + } + + public void setFileLocator(String fileLocator) { + this.fileLocator = fileLocator; + } + + public Long getPoint() { + return point; + } + + public void setPoint(Long point) { + this.point = point; + } + } + +} + + +//1. 上传文件 +// 1.1 如果上传成功,且该次上传是续传,则移除该文件哈希值对应的本地存储条目; +// 1.2 如果上传失败,则将文件断点信息存到本地:md5哈希值、纯文件名、服务器路径、断点 +// 1.3 每次上传文件,都要计算一下md5哈希值,然后查表,看本地有没有这个哈希值。 +// 如果有,就取文件名、要传的服务器路径,对比一下,全部都对的上,就从断点位置继续传该文件;如果没该哈希值,或文件名、路径不一致,则从0开始上传。 +// +//2. 下载文件 +// 2.1 如果下载成功,且该次下载是续传,则移除该次下载的文件对应的服务器url所对应的本地存储条目; +// 2.2 如果下载失败,则将文件断点信息保存到本地:文件对应的服务器url(如:/a/b.txt)、纯文件名、本地目录、断点 +// 2.3 每次下载文件,都查看要下载的文件的服务器url是否在本地存储中。如果在,就取纯文件名、本地目录对比一下,如果全部都对的上,就从断点位置继续传该文件;如果没该服务器url,或文件名、路径不一致,则从0开始下载。 +//3. 问题: +// 1. 由于上述断点全部存储在客户端,那么对于电脑突然死机或用户直接关闭客户端的情况,是无法将断点信息保存到本地的,也就无法续传; +// 2. 上述下载中,所谓文件服务器URL,并不是文件唯一标识,如果出现文件错判,续传之后的文件将可能是两个不同文件的结合体。 + diff --git a/src/main/java/cn/minbrowser/util/FileTransferProgressBarUtil.java b/src/main/java/cn/minbrowser/util/FileTransferProgressBarUtil.java index de33b3d..d54ab2a 100644 --- a/src/main/java/cn/minbrowser/util/FileTransferProgressBarUtil.java +++ b/src/main/java/cn/minbrowser/util/FileTransferProgressBarUtil.java @@ -56,6 +56,8 @@ public class FileTransferProgressBarUtil { Task copyWorker; // 进度监听线程 private Thread listenThread; + // 进度条监听线程是否已经开始监听/被创建 + private boolean isThreadListenning=false; // 下载文件进度条stage private Stage downloadFileDialogStage; // 文件下载类 @@ -222,9 +224,10 @@ public class FileTransferProgressBarUtil { downLoadClientBasedFacePool.cancelFileTransfer(); // 关闭该次传输 downLoadClientBasedFacePool.closeSelf(); - // 关闭进度条监听线程:再new一下是为了避免线程还没被创建 - listenThread =new Thread(); - listenThread.interrupt(); + // 关闭进度条监听线程 + if(isThreadListenning){ + listenThread.interrupt(); + } // 弹窗关闭 downloadFileDialogStage.close(); } @@ -288,6 +291,7 @@ public class FileTransferProgressBarUtil { } } }); + isThreadListenning=true; listenThread.start(); // 开始下载文件 boolean res = downLoadClientBasedFacePool.downloadData(); diff --git a/src/main/java/cn/minbrowser/util/GenerateSettingFiles.java b/src/main/java/cn/minbrowser/util/GenerateSettingFiles.java index f7afaee..83be708 100644 --- a/src/main/java/cn/minbrowser/util/GenerateSettingFiles.java +++ b/src/main/java/cn/minbrowser/util/GenerateSettingFiles.java @@ -1,6 +1,8 @@ package cn.minbrowser.util; // 生成配置文件 +import cn.minbrowser.MiniMinData.util.FileBPRUtil; + import java.io.*; import java.nio.charset.StandardCharsets; import java.util.Properties; @@ -12,6 +14,7 @@ public class GenerateSettingFiles { generateUserHomeNDNDir(); generateFilecacheDir(); generateSettingFile(); + generateBPRFile(); // 如果配置文件中有信息缺失,提示用户补全信息后重启APP if(!SettingPropertyUtil.isAllSetting()){ System.out.println("配置信息不全,请补全后重启APP"); @@ -83,7 +86,7 @@ public class GenerateSettingFiles { } public static void generateBPRFile() { - String path = "." + File.separator + "min" + File.separator + "FileBPRenewal.properties"; + String path = FileBPRUtil.fileBPRDir; generateBPRFiles(path); } diff --git a/src/main/java/cn/minbrowser/view/NavigationBarController.java b/src/main/java/cn/minbrowser/view/NavigationBarController.java index 8588297..0ded79f 100644 --- a/src/main/java/cn/minbrowser/view/NavigationBarController.java +++ b/src/main/java/cn/minbrowser/view/NavigationBarController.java @@ -62,6 +62,7 @@ public class NavigationBarController implements Initializable { this.userPhoto.setImage(new Image("file:resources/images/user.png")); this.settingPhoto.setImage(new Image("file:resources/images/3dot.png")); // 设置tabpane中tab的最大宽度 + tabPane.setTabMinWidth(tabHeaderWidth); tabPane.setTabMaxWidth(tabHeaderWidth); // 加载标签 iniTab(); @@ -74,7 +75,7 @@ public class NavigationBarController implements Initializable { */ private void iniTab(){ tabPane.getTabs().add(new MiniTab(this)); - AnchorPane.setLeftAnchor(addTabButton,175D); + AnchorPane.setLeftAnchor(addTabButton,tabHeaderWidth+24D); addTabButton.setOnAction((event) -> { MiniTab mt = new MiniTab(this); tabPane.getTabs().add(mt);