Fork me on GitHub
文件下载+断点续传

工具开发系列之:文件下载+断点续传

2013-12-12 18:01 by Turbo Zhang, 325 阅读, 1 评论, 收藏编辑

日常开发中总会遇到大量琐碎文件的Copy处理的问题,而如果文件较大的情况下,可能会遇到断电,远程Server崩溃等问题,于是断点续传问题就会提到议事上来。

在这里分享一个自己用的DownLoad Tool 虽然细节有待商讨,暂起抛砖引玉之意:

  1. 新建控制台程序作为tool主程:
    1. 复制代码
      static void Main(string[] args) {
                  Console.WriteLine("{0:HH:mm:ss} Download tool start......",DateTime.Now);
                  DownLoadFunction.StartDownload();
                  Console.WriteLine("{0:HH:mm:ss} Download finished! Press <Enter> to exit.",DateTime.Now);
                  Console.ReadLine();
              }
      复制代码


       

  2. 相关Code:

       DownLoadFunction 作为下载主要类,实现下载功能,后续提供的FTP,HTTP等下载方式以工厂方式提供:

复制代码
        public static Boolean StartDownload() {
            String srcPath = System.Configuration.ConfigurationManager.AppSettings["SourcePath"];
            String aimPath = System.Configuration.ConfigurationManager.AppSettings["TargetPath"];
            try {
                IOHelper.WriteToXml(srcPath,aimPath);
                LoadFile(srcPath, aimPath);
                IOHelper.XmlDelete();
                return true;
            } catch (Exception ex) {
                Console.WriteLine("{0:HH:mm:ss} error:" + ex,DateTime.Now);
            }
            return false;
        }
复制代码

下面的方法为核心方法,首先建立远程下载目录文件,下载工程依次修改此文件相关条目状态。

下载完成,相关条目状态设置为100%;
文件夹下文件以递归方式实现(此处为出现性能问题的地区);

如果下载过程中由于异常程序终止,下次下载时,程序发现上次记录过此目录,进行下载条目检查,状态未成100%的,则由此次进行下载,以实现断点下载。

(如果想更加精细的实现“断点”,需要操作到file本身的属性,md5等各种校验)

Code如下:

复制代码
        #region private method

        private static void LoadFile(String srcPath, String aimPath) {
            Console.WriteLine("[Enter Path]: {0}",srcPath);
            try {
                if (aimPath[aimPath.Length - 1] != System.IO.Path.DirectorySeparatorChar) {
                    aimPath += System.IO.Path.DirectorySeparatorChar;
                }
                if (!System.IO.Directory.Exists(aimPath)) {
                    System.IO.Directory.CreateDirectory(aimPath);
                }

                String[] fileList = System.IO.Directory.GetFileSystemEntries(srcPath);

                foreach (String file in fileList) {
                    if (System.IO.Directory.Exists(file)) {
                        Console.WriteLine("[Enter Path]: {0}",file);
                        LoadFile(file, aimPath + System.IO.Path.GetFileName(file));
                    } else {
                        if (IOHelper.CheckDownloadState(file) != DownloadState.Finished) {
                            Console.WriteLine("[Download file]: {0}", file);
                            System.IO.File.Copy(file, aimPath + System.IO.Path.GetFileName(file), true);
                            IOHelper.UpdateDownlPer(file);
                        }
                    }
                }
            } catch (Exception e) {
                Console.WriteLine("{0:HH:mm:ss} error:" + e, DateTime.Now);
            }

        }

        #endregion
复制代码

对于下载条目文件的操作:

复制代码
 public class IOHelper {

        #region Create directory

        public static void DirectoryCreate(String directoryName) {
            String createPath = Path.GetDirectoryName(directoryName);
            try {
                if (!Directory.Exists(createPath)) { Directory.CreateDirectory(createPath); }
                Console.WriteLine("{0:HH:mm:ss} directory {0} create successful!",directoryName);
            } catch (Exception ex) {
                Console.WriteLine("{0:HH:mm:ss} Create directory error! message:"+ex);
            }
        }

        #endregion

        #region Config operate
        static StringBuilder sbXml = new StringBuilder();
        static readonly String xmlTargetPath = System.Configuration.ConfigurationManager.AppSettings["xmlPath"];


        public static void WriteToXml(String srcPath, String aimPath) {
            if (File.Exists(xmlTargetPath)) return;

            try {
                if (aimPath[aimPath.Length - 1] != System.IO.Path.DirectorySeparatorChar) {
                    aimPath += System.IO.Path.DirectorySeparatorChar;
                }
                if (!System.IO.Directory.Exists(aimPath)) {
                    System.IO.Directory.CreateDirectory(aimPath);
                }

                String[] fileList = System.IO.Directory.GetFileSystemEntries(srcPath);

                foreach (String file in fileList) {
                    if (System.IO.Directory.Exists(file)) {
                        WriteToXml(file, aimPath + System.IO.Path.GetFileName(file));
                    } else {
                        sbXml.AppendLine(file+"->0%");
                    }
                }

                File.WriteAllText(xmlTargetPath,sbXml.ToString(),Encoding.UTF8);
            } catch (Exception e) {
                Console.WriteLine("{0:HH:mm:ss} write to xml error:" + e, DateTime.Now);
            }

        }

        public static void UpdateDownlPer(String line) {
            String[] lines = File.ReadAllLines(xmlTargetPath);
            for (int i = 0; i < lines.Length; i++) {
                if (line == lines[i].Substring(0, lines[i].LastIndexOf("->"))) {
                    lines[i] = lines[i].Substring(0,lines[i].LastIndexOf("->")+2)+"100%";
                    break;
                }
            }
            File.WriteAllLines(xmlTargetPath,lines,Encoding.UTF8);
        }

        public static DownloadState CheckDownloadState(String line) {
            DownloadState state=DownloadState.Start;

            String[] lines = File.ReadAllLines(xmlTargetPath);
            for (int i = 0; i < lines.Length; i++) {
                if (line == lines[i].Substring(0, lines[i].LastIndexOf("->"))) {
                    if (lines[i].Substring(lines[i].LastIndexOf("->") + 2) == "100%") state = DownloadState.Finished;
                    else state = DownloadState.Start;
                    break;
                }
            }

            return state;
        }

        public static void XmlDelete() {
            File.Delete(xmlTargetPath);
        }
        #endregion
    }
复制代码
 public enum TaskState {
        Create, Processing, Error, Finished
    }

XML:

复制代码
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="xmlPath" value="d:\dbCopy\configXml.txt"/>
    <add key="SourcePath" value="D:\TestFile\"/>
    <add key="TargetPath" value="D:\dbCopy\"/>
  </appSettings>
</configuration>
复制代码

 

3.执行结果:

下载条目列表:

 程序结果:

posted on 2013-12-12 22:57  HackerVirus  阅读(350)  评论(0编辑  收藏  举报