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

news/2024/10/4 21:36:37/文章来源:https://www.cnblogs.com/cyqdeshenluo/p/18274807

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

方案:这里通过文件的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中

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/733478.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt开发笔记:Qt3D三维开发笔记(一):Qt3D三维开发基础概念介绍

前言Qt3D是qt的三维,Q3D是Qt的三维图表,Qt3D是qt的自带的三维开发框架,Qt的3D开发分为opengl、Qt3D然后是第三方三维框架(OSG、vtk等等)多个技术流。  本篇描述Qt3D的基础概念,有一个基本知识。 个人经验,仅供参考(持续更新)通过深入研究和实践,从中长期看采取第三方…

VuePress日常使用

本篇来讲解下更多关于 VuePress 的基本用法本篇来讲解下更多关于 VuePress 的基本用法 ‍ 配置首页 现在的页面太简单了,我们可以对项目首页进行配置,修改 docs/README.md (这些配置是什么后面会说): --- home: true heroImage: https://s3.bmp.ovh/imgs/2022/12/02/bc742…

win10系统新建文件夹需刷新才能显示?原因及解决方法

在Win10操作系统中,一些用户可能会遇到这样一个问题:新建的文件夹在资源管理器中不会立即显示,需要刷新后才能看到。这给用户的日常操作带来了一定的困扰。接下来,系统世界官网将为您解析这一问题的原因以及相应的解决方法。一、原因分析1. 资源管理器缓存问题:在Win10系统…

【YOLOv8改进-损失函数】SlideLoss损失函数,解决样本不平衡问题

YOLO-FaceV2是基于YOLOv5的实时人脸检测模型,采用RFE模块增强小人脸检测,NWD损失处理定位偏差,SEAM注意力模块应对遮挡,Slide Loss解决样本不平衡,提升对难样本的关注。在WiderFace数据集上超越YOLO系列。论文和代码已公开。Slide Loss通过IoU加权,优化边界样本,提高模型…

使用Device Mapper创建线性阵列

​ 在之前的文章:《QEMU/KVM启动物理分区的Windows并调优》中笔者使用mdadm创建线性阵列,使VM启动物理硬盘分区上的Windows系统。这个做法思路清晰且具有实操性,但根据这个issue,Linux内核上游已将CONFIG_MD_LINEAR编译参数弃置了,这意味着在6.8及以后的内核中将无法使用m…

【YOLOv8改进-卷积Conv】DualConv( Dual Convolutional):用于轻量级深度神经网络的双卷积核

**摘要:**我们提出DualConv,一种融合$3\times3$和$1\times1$卷积的轻量级DNN技术,适用于资源有限的系统。它通过组卷积结合两种卷积核,减少计算和参数量,同时增强准确性。在MobileNetV2上,参数减少54%,CIFAR-100精度仅降0.68%。在YOLOv3中,DualConv提升检测速度并增4.4…

达梦数据库图形化安装

图形化安装(官网https://eco.dameng.com/document/dm/zh-cn/start/dm-instance-linux.html)启用图形化安装界面前需要通过如下命令将图形界面权限放开: Copy[root@localhost mnt]# xhost + access control disabled, clients can connect from any host [root@localhost mnt…

【YOLOv8改进-卷积Conv】 OREPA(Online Convolutional Re-parameterization):在线卷积重参数化

**OREPA**是在线卷积重参数化的缩写,它提出了一种两阶段流程来减少深度模型训练的开销。该方法通过线性缩放层优化复杂训练块,并在训练完成后将其压缩为单个卷积层,降低内存使用和提高训练速度。与现有技术相比,OREPA能减少约70%的训练内存开销,提升2倍训练速度,并在Imag…

【YOLOv8改进】 RFB (Receptive Field Block):多分支卷积块

**RFB Net是针对目标检测的轻量级解决方案,它通过设计灵感来自人眼感受野的模块提升特征表示。RFB块包含多分支卷积,模拟不同尺度和偏心率,增强轻量模型如SSD的性能。在保持实时速度的同时,RFB Net在准确性上媲美深度检测器。代码可在GitHub找到。**介绍摘要 当前表现最好的…

BUUCTF---天干地址+甲子

题目直接参考天干地支表作结,转ASCII flag{Goodjob}

BUUCTF---古典密码知多少

题目知识 一共给出四种古典密码,分别是:猪圈密码、圣堂武士密码、标准银河字母、栅栏密码 猪圈之前有介绍 圣:标准银河字母更多加密方式 解题 对照解密 FGCPFLIRTUASYON 再使用栅栏 FLAGISCRYPTOFUN flag{CRYPTOFUN}

mysql 查询,字符串带着空格也能匹配上

1.说明有空格,这些数据其实是不规范的数据,但是仍然能查询出来2.注意id是一样的,但是查询出来的数据自动trim了。3.甚至输入数字也能查出来,之前知道可以自动转型,但是没想到可以自动转型+trim 4.带着前导0的整型 也能匹配上5.带着前导0的字符肯定匹配不上6.空格在前面也…