FtpUploader.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. using System.IO.Compression;
  2. using Newtonsoft.Json;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using TeamAAS_VP.Models;
  12. namespace TeamAAS_VP.Core
  13. {
  14. public class FtpUploader
  15. {
  16. //private readonly Timer _timer;
  17. //private static readonly Timer _cleanupTimer = new Timer();
  18. private ConfigFtp _config;
  19. public FtpUploader()
  20. {
  21. try
  22. {
  23. string configFilePath = "..//Config//FtpConfig.cfg";
  24. //加载配置文件
  25. _config = new ConfigFtp();
  26. _config = LoadConfiguration(configFilePath);
  27. //设置上传定时器
  28. //_timer = new Timer(_config.IntervalMinutes * 60 * 1000);
  29. //_timer.Elapsed += (s, e) => UploadAllFolders();
  30. //_timer.AutoReset = true;
  31. //// 设置清理定时器
  32. //_cleanupTimer.Interval = _config.CleanupIntervalMinutes * 60 * 1000;
  33. //_cleanupTimer.Elapsed += (sender, e) => CleanupOldFilesOnFtp();
  34. //_cleanupTimer.AutoReset = true;
  35. }
  36. catch (Exception ex)
  37. {
  38. }
  39. }
  40. public void Start()
  41. {
  42. if (_config.Open)
  43. {
  44. Task.Run(async () =>
  45. {
  46. while (true)
  47. {
  48. try
  49. {
  50. //_timer.Start();
  51. //SendMessage.SendInfo("启动Ftp上传服务...", Color.Black);
  52. //立即执行一次
  53. UploadAllFolders();
  54. }
  55. catch (Exception ex)
  56. {
  57. }
  58. finally
  59. {
  60. await Task.Delay(_config.IntervalMinutes * 60 * 1000);
  61. }
  62. }
  63. });
  64. }
  65. }
  66. public void Stop()
  67. {
  68. //_timer.Stop();
  69. //SendMessage.SendInfo("Ftp上传服务已停止", Color.Black);
  70. }
  71. private ConfigFtp LoadConfiguration(string configFilePath)
  72. {
  73. try
  74. {
  75. string json = File.ReadAllText(configFilePath);
  76. return JsonConvert.DeserializeObject<ConfigFtp>(json);
  77. }
  78. catch (Exception ex)
  79. {
  80. //SendMessage.SendInfo($"加载配置文件失败:{ex.Message}", Color.Red);
  81. return null;
  82. }
  83. }
  84. /// <summary>
  85. /// 开始上传文件
  86. /// </summary>
  87. public void UploadAllFolders()
  88. {
  89. Task.Run(() =>
  90. {
  91. foreach (var localFolder in _config.LocalFolders)
  92. {
  93. try
  94. {
  95. if (!Directory.Exists(localFolder))
  96. {
  97. //文件夹不存在
  98. continue;
  99. }
  100. var files = Directory.GetFiles(localFolder).ToList();
  101. // if (!files.Any())
  102. // {
  103. //string path1 = localFolder + $"\\{DateTime.Now.ToString("yyyy-MM")}";
  104. string path2 = localFolder + $"\\{DateTime.Now.ToString("yyyy-MM")}\\{DateTime.Now.ToString("MM-dd")}\\OK";
  105. string path3 = localFolder + $"\\{DateTime.Now.ToString("yyyy-MM")}\\{DateTime.Now.ToString("MM-dd")}\\NG";
  106. string path4 = localFolder;
  107. //if (Directory.Exists(path1))
  108. //{
  109. // files = Directory.GetFiles(path1).ToList();
  110. // string str1 = string.Join("/", path1.Split('\\').Skip(2));
  111. // EnsureFtpDirectoryExists(str1);
  112. //}
  113. if (Directory.Exists(path2))
  114. {
  115. var files1 = Directory.GetFiles(path2).ToList();
  116. if (Directory.Exists(path3))
  117. {
  118. var files2 = Directory.GetFiles(path3).ToList();
  119. foreach (var item in files2)
  120. {
  121. files1.Add(item);
  122. }
  123. }
  124. files = files1;
  125. string str2 = string.Join("/", path2.Split('\\').Skip(2));
  126. EnsureFtpDirectoryExists(str2);
  127. string str3 = string.Join("/", path3.Split('\\').Skip(2));
  128. EnsureFtpDirectoryExists(str3);
  129. }
  130. else if (Directory.Exists(path3))
  131. {
  132. var files1 = Directory.GetFiles(path3).ToList();
  133. files = files1;
  134. string str3 = string.Join("/", path3.Split('\\').Skip(2));
  135. EnsureFtpDirectoryExists(str3);
  136. }
  137. else if (Directory.Exists(path4))
  138. {
  139. files = Directory.GetFiles(path4).ToList();
  140. string str4 = string.Join("/", path4.Split('\\').Skip(2));
  141. EnsureFtpDirectoryExists(str4);
  142. }
  143. else
  144. {
  145. // SendMessage.SendInfo($"没有找到可上传文件:{localFolder}", Color.Black);
  146. continue;
  147. }
  148. // }
  149. foreach (var file in files)
  150. {
  151. UploadFile(file);
  152. //CleanupOldFilesOnFtp(file);
  153. }
  154. files.Clear();
  155. Thread.Sleep(500);
  156. }
  157. catch (Exception ex)
  158. {
  159. LogHelper.WriteLogError($"处理文件夹{localFolder}时出错", ex);
  160. }
  161. }
  162. });
  163. }
  164. private void UploadFile(string localFilePath)
  165. {
  166. if (_config.Open)
  167. {
  168. string str = string.Join("/", localFilePath.Split('\\').Skip(2));
  169. string fileName = Path.GetFileName(localFilePath);
  170. string ftpUri = $"{_config.FtpServer}/{_config.RemotePath}/{str}";
  171. try
  172. {
  173. FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpUri);
  174. request.Method = WebRequestMethods.Ftp.UploadFile;
  175. request.Credentials = new NetworkCredential(_config.Username, _config.Password);
  176. using (var fileStream = File.OpenRead(localFilePath))
  177. using (Stream ftpStream = request.GetRequestStream())
  178. {
  179. fileStream.CopyTo(ftpStream);
  180. }
  181. }
  182. catch (Exception ex)
  183. {
  184. LogHelper.WriteLogError($"上传{fileName}失败", ex);
  185. }
  186. }
  187. }
  188. private void EnsureFtpDirectoryExists(string ftpSubDirectory)
  189. {
  190. if (_config.Open)
  191. {
  192. string ftpUri = $"{_config.FtpServer}/{_config.RemotePath}/{ftpSubDirectory}";
  193. try
  194. {
  195. FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpUri);
  196. request.Method = WebRequestMethods.Ftp.MakeDirectory;
  197. request.Credentials = new NetworkCredential(_config.Username, _config.Password);
  198. using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
  199. {
  200. //SendMessage.SendInfo($"创建Ftp目录:{ftpSubDirectory}", Color.Black);
  201. }
  202. }
  203. catch (Exception ex)
  204. {
  205. //SendMessage.SendInfo($"创建目录{ftpSubDirectory}失败:{ex.Message}", Color.Red);
  206. }
  207. }
  208. }
  209. /// <summary>
  210. /// 上传文件到ftp
  211. /// </summary>
  212. /// <param name="path"></param>
  213. public async void UploadToFtp(string path)
  214. {
  215. if (_config.Open)
  216. {
  217. try
  218. {
  219. await Task.Run(() =>
  220. {
  221. List<string> files = new List<string>();
  222. if (Directory.Exists(path))
  223. {
  224. files = Directory.GetFiles(path).ToList();
  225. string str = string.Join("/", path.Split('\\').Skip(2));
  226. EnsureFtpDirectoryExists(str);
  227. }
  228. foreach (var file in files)
  229. {
  230. UploadFile(file);
  231. }
  232. files.Clear();
  233. });
  234. }
  235. catch (Exception ex)
  236. {
  237. LogHelper.WriteLogError($"上传FTP文件{path}时出错", ex);
  238. }
  239. }
  240. }
  241. #region 清理
  242. public void CleanupOldFilesOnFtp(string localFilePath)
  243. {
  244. //Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - 开始执行FTP文件清理任务");
  245. var cutoffDate = DateTime.Now.AddDays(-_config.DeleteDay);
  246. //foreach (var folder in _config.LocalFolders)
  247. //{
  248. //string remoteDir = string.Join("/", localFilePath.Split('\\').Skip(2));
  249. string fileName = Path.GetFileName(localFilePath);
  250. //var remoteDir = $"{_config.RemotePath}{folderName}/";
  251. string remoteDir = "";
  252. ////截取地址中前两个\\保留后面内容
  253. //int firstSlashIndex = folder.IndexOf('\\');
  254. //int secondSlashIndex = folder.IndexOf('\\', firstSlashIndex + 1);
  255. //if (secondSlashIndex >= 0)
  256. //{
  257. // string result = folder.Substring(secondSlashIndex + 1);
  258. // remoteDir = $"{_config.FtpServer}/{_config.RemotePath}/{result}";
  259. //}
  260. //去掉前两个//,并且去掉后面文件名和格式
  261. string[] parts = localFilePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
  262. if (parts.Length >= 5) // 确保路径足够长
  263. {
  264. var middleParts = parts.Skip(3).Take(parts.Length - 4); // 跳过前3部分,去掉最后1部分
  265. string result = string.Join("/", middleParts); // 合并成路径
  266. remoteDir = result;
  267. }
  268. try
  269. {
  270. //获取FTP服务器指定目录下的文件列表,并将结果存储在files变量中。
  271. var files = ListFilesOnFtp(remoteDir);
  272. foreach (var file in files)
  273. {
  274. if (file.LastModified < cutoffDate)
  275. {
  276. DeleteFileOnFtp(remoteDir + file.Name);
  277. //Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - 已删除FTP旧文件: {remoteDir}{file.Name} (修改时间: {file.LastModified})");
  278. }
  279. }
  280. }
  281. catch (Exception ex)
  282. {
  283. LogHelper.WriteLogError($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - 清理FTP目录 {remoteDir} 出错", ex);
  284. }
  285. //}
  286. //Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - FTP文件清理任务完成");
  287. }
  288. public List<FtpFileInfo> ListFilesOnFtp(string remoteDir)
  289. {
  290. var files = new List<FtpFileInfo>();
  291. var uri = new Uri($"{_config.FtpServer}/{_config.RemotePath}/{remoteDir}");//Uri($"{_config.FtpServer}/{remoteDir}");
  292. var request = (FtpWebRequest)WebRequest.Create(uri);
  293. request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
  294. request.Credentials = new NetworkCredential(_config.Username, _config.Password);
  295. request.UsePassive = true;
  296. using (var response = (FtpWebResponse)request.GetResponse())
  297. using (var stream = response.GetResponseStream())
  298. using (var reader = new StreamReader(stream))
  299. {
  300. string line;
  301. while ((line = reader.ReadLine()) != null)
  302. {
  303. var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  304. if (parts.Length > 8 && !string.IsNullOrEmpty(parts[8]))
  305. {
  306. try
  307. {
  308. var dateStr = $"{parts[5]} {parts[6]} {parts[7]}";
  309. if (DateTime.TryParse(dateStr, out var lastModified))
  310. {
  311. files.Add(new FtpFileInfo
  312. {
  313. Name = parts[8],
  314. LastModified = lastModified
  315. });
  316. }
  317. }
  318. catch
  319. {
  320. // 忽略解析错误的行
  321. }
  322. }
  323. }
  324. }
  325. return files;
  326. }
  327. public void DeleteFileOnFtp(string remoteFilePath)
  328. {
  329. var uri = new Uri($"{_config.FtpServer}/{_config.RemotePath}/{remoteFilePath}");
  330. var request = (FtpWebRequest)WebRequest.Create(uri);
  331. request.Method = WebRequestMethods.Ftp.DeleteFile;
  332. request.Credentials = new NetworkCredential(_config.Username, _config.Password);
  333. request.UsePassive = true;
  334. using (var response = (FtpWebResponse)request.GetResponse())
  335. {
  336. if (response.StatusCode != FtpStatusCode.FileActionOK)
  337. {
  338. // throw new Exception($"删除文件失败: {response.StatusCode}");
  339. }
  340. }
  341. }
  342. #endregion
  343. #region 压缩图片文件夹
  344. public async Task<string> CompressionImage(string sn,string currentPro)
  345. {
  346. if (_config.Open)
  347. {
  348. try
  349. {
  350. string zipPath = "";
  351. await Task.Run(() =>
  352. {
  353. zipPath = $"{_config.ImagePath}\\{sn}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.zip";//生成的zip文件路径
  354. string sourcePath = $"{_config.ImagePath}\\{DateTime.Now.ToString("yyyy-MM")}\\{DateTime.Now.ToString("MM-dd")}\\{currentPro}\\{sn}";//"D:\image\Recored\2026-02\02-28\产品1\CN0D0NDYCKJ006250103X02"
  355. ZipFile.CreateFromDirectory(sourcePath, zipPath);
  356. });
  357. return zipPath;
  358. }
  359. catch (Exception ex)
  360. {
  361. LogHelper.WriteLogError($"压缩图片文件时出错", ex);
  362. return "";
  363. }
  364. }
  365. return "";
  366. }
  367. #endregion
  368. }
  369. }