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}"));
}
}
}
}