using System; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Vinno.FIS.TRTCClient.Common.Log; namespace Vinno.FIS.TRTCClient.Common.FileTransfer { public class FileTransferReader : IDisposable { private readonly CancellationTokenSource _cts; private readonly Task _task; private bool _disposed; private byte[] _currentByteArray; private bool _hasReserveFolder => !string.IsNullOrEmpty(ReserveStorageFolderPath); /// /// Name Of File Reader and Folder Name /// public string Name { get; private set; } /// /// Parent Folder Name /// public string ParentFolderName { get; private set; } /// /// Parent Folder Path /// public string ParentFolderPath { get; private set; } /// /// Folder Storage Path /// public string StorageFolderPath { get; private set; } /// /// Basic Folder under FIS Folder /// public string ImageTransferBaseFolderPath { get; private set; } /// /// 预留文件夹路径 /// public string ReserveStorageFolderPath { get; private set; } /// /// Raised when log msg throw /// public event EventHandler LogMsgThrow; public event EventHandler DataReceived; public FileTransferReader(string name, string parentFolderName, string fisFolderPath, string reserveName) { Name = name; ParentFolderName = parentFolderName; ImageTransferBaseFolderPath = Path.Combine(fisFolderPath, FISTRTCConsts.DataTransferFolder); ParentFolderPath = Path.Combine(ImageTransferBaseFolderPath, ParentFolderName); StorageFolderPath = Path.Combine(ParentFolderPath, Name); if (!string.IsNullOrEmpty(reserveName)) { ReserveStorageFolderPath = Path.Combine(ParentFolderPath, reserveName); } CreateDirectory(ImageTransferBaseFolderPath); CreateDirectory(ParentFolderPath); CreateDirectory(StorageFolderPath); if (_hasReserveFolder) { CreateDirectory(ReserveStorageFolderPath); var existFiles = Directory.GetFiles(ReserveStorageFolderPath); if (existFiles.Length > 0) { foreach (var existFile in existFiles.OrderBy(x => x)) { var fileName = Path.GetFileName(existFile); var copyFilePath = Path.Combine(StorageFolderPath, fileName); File.Copy(existFile, copyFilePath, true); } } } _cts = new CancellationTokenSource(); _currentByteArray = new byte[0]; } private void CreateDirectory(string directory) { if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } } public void StartContinuousRead() { Task.Run(() => { while (!_cts.IsCancellationRequested && !_disposed) { try { if (!Directory.Exists(StorageFolderPath)) { break; } var files = Directory.GetFiles(StorageFolderPath, "*.fis"); var oldestFile = files.OrderBy(x => x).FirstOrDefault(); if (oldestFile == null) { Thread.Sleep(100); continue; } try { using (FileStream fileStream = new FileStream(oldestFile, FileMode.Open, FileAccess.Read)) { using (BinaryReader reader = new BinaryReader(fileStream)) { var dataLength = reader.ReadInt32(); if (_currentByteArray == null) { _currentByteArray = new byte[dataLength]; } if (_currentByteArray.Length != dataLength) { Array.Resize(ref _currentByteArray, dataLength); } _currentByteArray = reader.ReadBytes(dataLength); } } } catch (Exception ex) { LogMsgThrow?.Invoke(this, new LogEventArgs(DeviceLogCategory.Error, $"FileTransferReader: {Name} ReadContinuous Error:{ex}")); } finally { DeleteFile(oldestFile); } DataReceived?.Invoke(this, _currentByteArray); } catch (Exception ex) { if (!((ex is FileNotFoundException) || (ex is DirectoryNotFoundException))) { LogMsgThrow?.Invoke(this, new LogEventArgs(DeviceLogCategory.Error, $"FileTransferReader: {Name} ReadContinuous Error:{ex}")); } } } }, _cts.Token); } /// /// Delete file /// /// The file to be deleted. private void DeleteFile(string filePath) { if (string.IsNullOrEmpty(filePath)) { return; } try { if (File.Exists(filePath)) { File.SetAttributes(filePath, FileAttributes.Normal); File.Delete(filePath); } } catch (Exception ex) { LogMsgThrow?.Invoke(this, new LogEventArgs(DeviceLogCategory.Error, $"Exception when delete file {filePath},detail:{ex}")); } } /// /// 用于写一个,读一个 /// /// /// public byte[] ReadFromFile(int dataLength) { try { if (_disposed || !Directory.Exists(StorageFolderPath)) { return null; } var files = Directory.GetFiles(StorageFolderPath, "*.fis"); var oldestFile = files.OrderBy(x => x).FirstOrDefault(); if (oldestFile == null) { return null; } try { using (FileStream fileStream = new FileStream(oldestFile, FileMode.Open, FileAccess.Read)) { using (BinaryReader reader = new BinaryReader(fileStream)) { if (_currentByteArray.Length != dataLength) { Array.Resize(ref _currentByteArray, dataLength); } _currentByteArray = reader.ReadBytes(dataLength); } } } catch (Exception ex) { LogMsgThrow?.Invoke(this, new LogEventArgs(DeviceLogCategory.Error, $"FileTransferReader: {Name} ReadFromFile Error:{ex}")); } finally { DeleteFile(oldestFile); } return _currentByteArray; } catch (Exception ex) { if (!((ex is FileNotFoundException) || (ex is DirectoryNotFoundException))) { LogMsgThrow?.Invoke(this, new LogEventArgs(DeviceLogCategory.Error, $"FileTransferReader: {Name} ReadFromFile Error:{ex}")); } return null; } } public void Dispose() { try { if (_disposed) { return; } _cts.Cancel(); try { _task?.Wait(200);//因Task在Wait过程中Cancel有几率会出错 } catch { } _disposed = true; LogMsgThrow?.Invoke(this, new LogEventArgs(DeviceLogCategory.Info, $"FileTransferReader:{Name} Dispose Success")); } catch (Exception ex) { LogMsgThrow?.Invoke(this, new LogEventArgs(DeviceLogCategory.Error, $"FileTransferReader:{Name} Dispose Error:{ex}")); } } } }