using Mirle.Component.MPLC.DataBlocks; using Mirle.Component.MPLC.Interfaces; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Mirle.Component.MPLC.FileData { /// /// 檔案讀取器 /// public class FileReader : IMPLCProvider, IDisposable { /// /// 建構式 /// public FileReader() { } /// /// 檔案集 /// private readonly List files = new List(); /// /// 建立快取任務 /// private Task _createCacheTask; /// /// /// private CancellationTokenSource _cancellationTokenSource; /// /// 資料區塊 /// private readonly List _dataBlocks = new List(); /// /// 原始資料 /// protected ConcurrentDictionary _rawData = new ConcurrentDictionary(); /// /// /// public double CachingPercentage => (double)_rawData.Values.Count(r => r.IsCached) / _rawData.Count * 100; /// /// /// public DateTime CurrentRowTime { get; private set; } /// /// /// public bool IsConnected => true; /// /// /// /// public void AddDataBlock(FileDataBlock newDataBlock) { _dataBlocks.Add(newDataBlock); } /// /// /// /// public IEnumerable GetDataBlocks() { return _dataBlocks; } /// /// /// /// public void AddFile(string FileName) { WaitForCreateCacheTask(); files.Add(FileName); } /// /// /// public void ClearFile() { WaitForCreateCacheTask(); _rawData.Clear(); files.Clear(); } /// /// /// public void OpenFile() { WaitForCreateCacheTask(); foreach (string f in files) { try { string[] rows = System.IO.File.ReadAllLines(f); foreach (string row in rows) { var time = DateTime.ParseExact(row.Substring(row.IndexOf('[') + 1, 14), "HH:mm:ss.fffff", null); var rawRecord = CreateRawRecord(row.Substring(row.IndexOf(']') + 2)); _rawData.TryAdd(time, rawRecord); } } catch (Exception ex) { Debug.WriteLine($"{ex.Message}-{ex.StackTrace}"); } } _cancellationTokenSource = new CancellationTokenSource(); _createCacheTask = new Task(() => CreateCache(_cancellationTokenSource.Token)); _createCacheTask.Start(); } /// /// /// private void WaitForCreateCacheTask() { if (_createCacheTask != null && _createCacheTask.Status == TaskStatus.Running) { _cancellationTokenSource.Cancel(); _createCacheTask.Wait(1000); } } /// /// /// /// private void CreateCache(CancellationToken token) { try { ParallelOptions po = new ParallelOptions { CancellationToken = token, MaxDegreeOfParallelism = Environment.ProcessorCount }; Parallel.ForEach(_rawData.Values, po, (r) => { r.CreateCache(); }); } catch (Exception ex) { Debug.WriteLine($"{ex.Message}-{ex.StackTrace}"); } } /// /// /// /// /// protected virtual RawRecord CreateRawRecord(string rawString) { return new RawRecord(rawString); } /// /// /// /// public IEnumerable GetDateTimeIndexes() { return _rawData.Keys.OrderBy(k => k); } /// /// /// /// public void Refresh(int index) { try { foreach (FileDataBlock block in _dataBlocks) { try { var rawRecords = _rawData.OrderBy(r => r.Key).ToList(); var rawRecord = rawRecords[index]; CurrentRowTime = rawRecord.Key; byte[] newByteArray = rawRecord.Value.GetBlockByIndex(block.ColumnIndex); block.SetRawData(newByteArray); } catch (Exception ex) { Debug.WriteLine($"{ex.Message}-{ex.StackTrace}"); } } } catch (Exception ex) { Debug.WriteLine($"{ex.Message}-{ex.StackTrace}"); } } /// /// /// /// public void Refresh(DateTime index) { if (_rawData.TryGetValue(index, out var value)) { try { foreach (var block in _dataBlocks) { try { byte[] newByteArray = value.GetBlockByIndex(block.ColumnIndex); block.SetRawData(newByteArray); } catch (Exception ex) { Debug.WriteLine($"{ex.Message}-{ex.StackTrace}"); } } CurrentRowTime = index; } catch (Exception ex) { Debug.WriteLine($"{ex.Message}-{ex.StackTrace}"); } } } /// /// /// /// /// public bool GetBit(string address) { foreach (var block in _dataBlocks) { if (block.TryGetBit(address, out bool value)) return value; } return false; } /// /// /// /// public void SetBitOn(string address) { return; } /// /// /// /// public void SetBitOff(string address) { return; } /// /// /// /// /// public int ReadWord(string address) { foreach (var block in _dataBlocks) { if (block.TryGetWord(address, out int value)) return value; } return 0; } /// /// /// /// /// public void WriteWord(string address, int data) { return; } /// /// /// /// /// /// public int[] ReadWords(string startAddress, int length) { foreach (var block in _dataBlocks) { if (block.TryGetWords(startAddress, out int[] data, length)) return data; } return new int[length]; } /// /// /// /// /// public void WriteWords(string startAddress, int[] data) { return; } /// /// /// /// public FileDataViewer GetDataView() { return new FileDataViewer(this); } /// /// /// /// /// /// public byte[] GetRawDataByDateTimeIndex(DateTime dateTimeIndex, int blockColumnIndex) { if (_rawData.TryGetValue(dateTimeIndex, out var value)) return value.GetBlockByIndex(blockColumnIndex); return null; } #region IDisposable Support private bool disposedValue = false; // 偵測多餘的呼叫 /// /// 釋放資源 /// /// protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { _createCacheTask?.Dispose(); _cancellationTokenSource?.Dispose(); } disposedValue = true; } } /// /// 建構式 /// ~FileReader() { Dispose(false); } /// /// 釋放資源 /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }