c#实现定时从外部服务器获取文件并查重(MD5)

需求:需要定时去请求外部服务器的文件,看看每天是否有新的文件上传,如果有就下载到本地服务器,并记录数据。原来的文件重命名。

方案:这里通过文件的MD5和其他条件来判断文件是否存在。因为文件量过大,所以批量下载的时候有时候会出现部分文件没能下载成功,但是数据入库了,所以这里也做了判断,没能下载成功的文件会再次下载但是数据不会入库

注意:MD5与文件名称没有关系,和文件内容有关,文件内容不同则生成的MD5不同

  1   1  public class FileTimerHelper
  2   2     {
  3   3 
  4   4         private static string wwwRootPath = FilePath.RootPath;
  5   5         private static Timer _dailyTaskTimer;
  6   6 
  7   7 
  8   8         public static void TimerInit()
  9   9         {
 10  10             Console.WriteLine("正在初始化每日任务定时器...");
 11  11             // 初始化定时器
 12  12             _dailyTaskTimer = new Timer();
 13  13             _dailyTaskTimer.Elapsed += new ElapsedEventHandler(OnDailyTaskTimer);
 14  14             _dailyTaskTimer.Interval = GeUntilNext8AM();
 15  15             _dailyTaskTimer.AutoReset = true; // 每天执行
 16  16             _dailyTaskTimer.Enabled = true;
 17  17             Console.WriteLine("每日任务定时器已启动,将于每天8点执行。");
 18  18             //_dailyTaskTimer = new Timer();
 19  19             //_dailyTaskTimer.Elapsed += new ElapsedEventHandler(OnDailyTaskTimerElapsed);
 20  20             //_dailyTaskTimer.Interval = TimeSpan.FromMinutes(3).TotalMilliseconds; // 3分钟
 21  21             //_dailyTaskTimer.AutoReset = false; // 只执行一次
 22  22             //_dailyTaskTimer.Enabled = true;
 23  23             //Console.WriteLine("每日任务定时器已启动,将于3分钟后执行。");
 24  24 
 25  25 
 26  26         }
 27  27         public static void ExecuteDailyTask()
 28  28         {
 29  29             try
 30  30             {
 31  31                 string phpFileUrl = $"{ServerConfig.DocUrl}/xxx.php";
 32  32                 string folderPath = Path.Combine(wwwRootPath, "File", "保存文件的文件夹名称");
 33  33                 Directory.CreateDirectory(folderPath);
 34  34                 var requestData = new Dictionary<string, dynamic> { { "请求参数", "XXX" } };
 35  35                 var responseContent = HttpServer.Post(phpFileUrl, requestData);
 36  36                 var json = JsonConvert.DeserializeObject<ErpDoc>(responseContent);
 37  37 
 38  38                 var details = new List<ProductionDocument>();//待入库文件数据,productionDocument是实体类
 39  39                 var fileUrls = new List<FileUrls>();//待下载文件列表
 40  40                 foreach (var row in json.Rows)
 41  41                 {
 42  42                     string fileUrl = $"{ServerConfig.DocUrl}/" + row.File;
 43  43 
 44  44                     using (var client = new System.Net.Http.HttpClient())
 45  45                     {
 46  46                         client.Timeout = TimeSpan.FromSeconds(60);
 47  47                         using (var response = client.GetAsync(fileUrl).Result) // 更改为Get并使用.Result等待完成
 48  48                         {
 49  49                             response.EnsureSuccessStatusCode();
 50  50                             byte[] fileBytes = response.Content.ReadAsByteArrayAsync().Result; // 使用.Result等待完成
 51  51                             string fileBase64 = Convert.ToBase64String(fileBytes);
 52  52                             string fileMD5 = fileBase64.GetMd5Hash();
 53  53 
 54  54                             string relativePath = Path.Combine(folderPath, string.Join("/", row.File.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).Take(row.File.Split('/').Length - 2)));
 55  55                             if (!FileExistsInDatabaseAsync(row, relativePath, fileMD5))
 56  56                             {
 57  57 
 58  58                                 Directory.CreateDirectory(relativePath);
 59  59                                 string fileName = Path.GetFileName(row.File);
 60  60                                 string destinationFile = Path.Combine(relativePath, fileName);
 61  61                                 string databasePath = destinationFile.Substring(wwwRootPath.Length).TrimStart(Path.DirectorySeparatorChar).Replace(Path.DirectorySeparatorChar, '/');
 62  62 
 63  63                                 details.Add(new ProductionDocument
 64  64                                 {
 65  65                                     CreateUserId = "admin",
 66  66                                     MarkedDateTime = DateTime.UtcNow,
 67  67                                     WorkshopId = 1,
 68  68                                     Level = row.Jb,
 69  69                                     Unit = row.Bm,
 70  70                                     Number = row.Bh,
 71  71                                     Name = row.Fullname,
 72  72                                     File = row.File,
 73  73                                     FileNew = databasePath,
 74  74                                     AddTime = DateTime.UtcNow,
 75  75                                     MD5 = fileMD5
 76  76                                 });
 77  77 
 78  78                                 fileUrls.Add(new FileUrls { GetFileUrl = fileUrl, TarGetFileUrl = destinationFile });
 79  79                             }
 80  80                         }
 81  81                     }
 82  82                 }
 83  83 
 84  84                 // 使用 ParallelOptions 来限制并发数量
 85  85                 var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
 86  86                 Parallel.ForEach(fileUrls, parallelOptions, fileUrl =>
 87  87                 {
 88  88                     try
 89  89                     {
 90  90                         DownloadFileAsync(fileUrl);
 91  91 
 92  92                     }
 93  93                     catch (Exception ex)
 94  94                     {
 95  95                         // 记录下载失败的错误信息
 96  96                         Console.WriteLine($"文件下载失败: {fileUrl.GetFileUrl}: {ex.Message}");
 97  97                     }
 98  98                 });
 99  99 
100 100 
101 101                 ProductionDocumentHelper.Instance.Add<ProductionDocument>(details);
102 102 
103 103             }
104 104             catch (Exception ex)
105 105             {
106 106                 Console.WriteLine(ex.Message);
107 107             }
108 108         }
109 109 
110 110         public static async void DownloadFileAsync(FileUrls fileUrls)
111 111         {
112 112             // 下载文件并保存到指定路径
113 113             using (var client = new System.Net.Http.HttpClient())
114 114             {
115 115                 client.Timeout = TimeSpan.FromSeconds(60);
116 116                 using (HttpResponseMessage response = await client.GetAsync(fileUrls.GetFileUrl))
117 117                 {
118 118                     response.EnsureSuccessStatusCode();
119 119                     using (FileStream fileStream = new FileStream(fileUrls.TarGetFileUrl, FileMode.Create, FileAccess.Write, FileShare.None))
120 120                     {
121 121                         await response.Content.CopyToAsync(fileStream);
122 122                     }
123 123 
124 124                 }
125 125             }
126 126 
127 127 
128 128         }
129 129 
130 130         private static bool FileExistsInDatabaseAsync(RowData row, string relativePath, string MD5)
131 131         {
132 132 
133 133             string fileUrl = $"{ServerConfig.DocUrl}/" + row.File;
134 134             // 检查数据库中是否已存在该文件记录
135 135             Directory.CreateDirectory(relativePath);
136 136             var docList = ProductionDocumentHelper.Instance.Gets(row.Jb, row.Bm);//含删除
137 137             var ifOther = docList.Where(e => e.Number == row.Bh && e.Name.Contains(row.Fullname));
138 138             string destinationFile = Path.Combine(relativePath, Path.GetFileName(row.File));
139 139 
140 140             if (ifOther.Count() > 0)
141 141             {
142 142                 var ifAnyMd5 = ifOther.Where(e => e.MD5 == MD5);
143 143                 if (ifAnyMd5.Count() > 0)
144 144                 {   //如果该文件原来有旧数据已经删除,则不重新下载
145 145                     var delAny = ifAnyMd5.Where(e => e.MarkedDelete == true);
146 146                     if (delAny.Any())
147 147                     {
148 148                         return true;
149 149                     }
150 150                     else
151 151                     {
152 152                         if (!System.IO.File.Exists(destinationFile))
153 153                         {
154 154 
155 155                             FileUrls fileUrls = new FileUrls { GetFileUrl = fileUrl, TarGetFileUrl = destinationFile };
156 156                             //批量下载文件有时候会出现文件未成功下载的问题,如果检测到有数据未下载,重新下载文件
157 157                             DownloadFileAsync(fileUrls);
158 158 
159 159                         }
160 160                     }
161 161                     return true;
162 162                 }
163 163 
164 164                 else
165 165                 {  //如果部门-级别-编号-文件名都一致但是文件内容(MD5)不一致,删除原来的数据,保留最新的
166 166                     var delFirst = ifOther.Where(e => e.MarkedDelete == false).FirstOrDefault();
167 167                     ProductionDocumentHelper.Instance.Delete(delFirst.Id);
168 168 
169 169                     // 重命名文件,如果存在同名文件
170 170                     string extension = Path.GetExtension(Path.GetFileName(row.File));
171 171                     string baseName = Path.GetFileNameWithoutExtension(Path.GetFileName(row.File));
172 172                     int i = 1;
173 173                     while (File.Exists(destinationFile))
174 174                     {
175 175                         // 生成新的文件名
176 176                         string newFileName = $"{baseName}({i}){extension}";
177 177                         string newFileFullPath = Path.Combine(relativePath, newFileName);
178 178                         if (!File.Exists(newFileFullPath))
179 179                         {
180 180                             // 重命名文件
181 181                             File.Move(destinationFile, newFileFullPath);
182 182                             // 移动文件
183 183 
184 184                             // 更新文件路径为新的文件名
185 185                             destinationFile = newFileFullPath;
186 186                             break;
187 187                         }
188 188                         i++;
189 189                     }
190 190 
191 191                     return false;
192 192                 }
193 193             }
194 194             else
195 195             {
196 196 
197 197                 return false;
198 198             }
199 199         }
200 200 
201 201 
202 202 
203 203         private static void OnDailyTaskTimer(object source, ElapsedEventArgs e)
204 204         {
205 205             try
206 206             {
207 207                 Console.WriteLine("定时任务开始执行...");
208 208                 FileTimerHelper.ExecuteDailyTask();
209 209                 Console.WriteLine("定时任务执行完毕。");
210 210             }
211 211             catch (Exception ex)
212 212             {
213 213                 // 处理异常
214 214                 Console.WriteLine($"定时任务执行过程中发生错误: {ex.Message}");
215 215             }
216 216         }
217 217         // 计算到下一个8点的间隔时间
218 218         private static double GeUntilNext8AM()
219 219         {
220 220             var now = DateTime.Now;
221 221             var tomorrow = now.Date.AddDays(1);
222 222             var next8AM = new DateTime(tomorrow.Year, tomorrow.Month, tomorrow.Day, 8, 0, 0);
223 223 
224 224             return (next8AM - now).TotalMilliseconds;
225 225         }
226 226 
227 227         // 在应用程序关闭时,确保释放定时器资源
228 228         public static void OnApplicationShutdown()
229 229         {
230 230             _dailyTaskTimer?.Dispose();
231 231         }
232 232 
233 233 
234 234 
235 235     }
实现
 1   public class ServerConfig
 2     {
 3         public static DataBase ApiDb;
 4         public static string DocUrl;
 5 
 6         public static void Init(IConfiguration configuration)
 7         {
 8             ApiDb = new DataBase(configuration.GetConnectionString("ApiDb"));
 9 
10             DocUrl = configuration.GetAppSettings<string>("DocUrl");
11             FileTimerHelper.TimerInit();
12         }
13    
14     }
ServerConfig
 1 (HTTpServer 和HttpClient都是自定义的,仅供参考    )
 2 public static string Post(string url, Dictionary<string, dynamic> data)
 3         {
 4             try
 5             {
 6                 var httpClient = new HttpClient(url) { Verb = HttpVerb.POST };
 7                 foreach (var dt in data)
 8                 {
 9                     httpClient.PostingData.Add(dt.Key, dt.Value.ToString());
10                 }
11 
12                 var result = httpClient.GetString();
13 
14                 return result;
15             }
16             catch (Exception e)
17             {
18                 if (url.Contains("XXX"))
19                 {
20                     Log.Error($"请求服务器异常 Post Form:{url},{data.ToJSON()},{e}");
21                 }
22                 else
23                 {
24                     Log.Error($"请求服务器异常 Post Form:{url},{e}");
25                 }
26                 return "fail";
27             }
28         }
HttpServer

 

Startup.cs中

 

posted @ 2024-06-29 10:35  苏苏苏en  阅读(12)  评论(0编辑  收藏  举报