364 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.Collections.Generic;
 | |
| using System;
 | |
| using System.Drawing;
 | |
| using System.Diagnostics;
 | |
| using System.Data;
 | |
| using System.Collections;
 | |
| using System.Windows.Forms;
 | |
| using AR;
 | |
| using vmsnet;
 | |
| using System.Linq;
 | |
| using System.Threading;
 | |
| using System.Threading.Tasks;
 | |
| using Project;
 | |
| using System.IO;
 | |
| 
 | |
| 
 | |
| namespace vmsnet
 | |
| {
 | |
|     public class CFDBA
 | |
|     {
 | |
|         string _BaseDir;
 | |
| 
 | |
|         public class ReadProgessArgs : EventArgs
 | |
|         {
 | |
|             public double value { get; set; }
 | |
|             public ReadProgessArgs(double value)
 | |
|             {
 | |
|                 this.value = value;
 | |
|             }
 | |
|         }
 | |
|         public class MessageArgs : EventArgs
 | |
|         {
 | |
|             public string Message { get; set; }
 | |
|             public MessageArgs(string value)
 | |
|             {
 | |
|                 Message = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         //public event EventHandler<ReadProgessArgs> ReadingProgressValueChanged;
 | |
|         public event EventHandler<MessageArgs> Message;
 | |
| 
 | |
|         public CFDBA(params string[] dirarrays)
 | |
|         {
 | |
|             var dir = System.IO.Path.Combine(dirarrays);
 | |
|             _BaseDir = dir;
 | |
|             if (System.IO.Directory.Exists(_BaseDir) == false)
 | |
|             {
 | |
|                 System.IO.Directory.CreateDirectory(_BaseDir);
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 데이터를 기록합니다.
 | |
|         /// </summary>
 | |
|         /// <param name="time">기록시간(파일명이 결정됨)</param>
 | |
|         /// <param name="table">기록할테이블명(파일명)</param>
 | |
|         /// <param name="buffer">기록할데이터(열데이터가 틀려서 고정할 수 없다)</param>
 | |
|         /// <returns></returns>
 | |
|         /// <remarks></remarks>
 | |
|         public bool InsertData(DateTime time, int ch, COMM.EALAMRAISETYPE raiseType, float volt, COMM.EALAMTYPE almType, float maxvolt, float minvolt, string am, string am2)
 | |
|         {
 | |
|             string DayStr = time.ToString("yyyyMMdd");
 | |
|             System.IO.FileInfo fi = new System.IO.FileInfo(_BaseDir + "\\" + DayStr.Substring(0, 4) + "\\" + DayStr.Substring(4, 2) + "\\" + DayStr.Substring(6) + "\\" + (time.Hour + 1).ToString("00") + ".txt");
 | |
|             if (!fi.Directory.Exists)
 | |
|             {
 | |
|                 try
 | |
|                 {
 | |
|                     fi.Directory.Create();
 | |
|                 }
 | |
|                 catch
 | |
|                 {
 | |
|                     PUB.log.AddE($"fail:make directory value={fi.Directory.FullName}");
 | |
|                     return false;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             System.Text.StringBuilder StrBuf = new System.Text.StringBuilder();
 | |
| 
 | |
|             ////파일이 없다면 제목줄을 생성해준다.
 | |
|             if (!fi.Exists)
 | |
|             {
 | |
| 
 | |
|                 ////헤더를 추가해야한다.
 | |
|                 System.Text.StringBuilder Header = new System.Text.StringBuilder();
 | |
|                 Header.Append("\t" + "ATIME    CH  RTYPE   VOLT    ATYPE   MAXVOLT MINVOLT AM  AM2");
 | |
|                 Header.AppendLine(); ////제목줄을 한칸띄운다
 | |
|                 StrBuf.Append(Header.ToString());
 | |
|             }
 | |
| 
 | |
|             ////실제데이터를 추가
 | |
|             int timeNumber = (int)(PUB.get_TimeNumber(time)); // time.Hour * 3600 + time.Minute * 60 + time.Second
 | |
|             StrBuf.AppendLine($"\t{timeNumber}\t{ch}\t{(int)raiseType}\t{volt}\t{(int)almType}\t{maxvolt}\t{minvolt}\t{am}\t{am2}");
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 //fi.WriteText(StrBuf.ToString(), true);    // 이전은 단독모드
 | |
|                 /* 작성자: 이재웅, 작성일: 2024-09-23, 작성내용: 접근모드를 공유모드로 전환 */
 | |
|                 using (FileStream fs = new FileStream(fi.FullName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
 | |
|                 using (StreamWriter writer = new StreamWriter(fs))
 | |
|                 { writer.Write(StrBuf.ToString()); }
 | |
|                 
 | |
|                 StrBuf.Clear();
 | |
|             }
 | |
|             catch (Exception)
 | |
|             {
 | |
|                 PUB.log.AddE($"fail:write aldata file={fi.FullName}");
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         ////기간내 존재하는 파일을 반환합니다(테이블단위)
 | |
|         public List<string> GetfileS(DateTime sd, DateTime ed)
 | |
|         {
 | |
| 
 | |
|             List<string> retval = new List<string>();
 | |
|             int SttYear = sd.Year;
 | |
|             int EndYear = ed.Year;
 | |
|             if (EndYear < SttYear)
 | |
|             {
 | |
|                 return retval;
 | |
|             }
 | |
| 
 | |
|             int SttMonth = sd.Month;
 | |
|             int EndMonth = ed.Month;
 | |
| 
 | |
|             int SttDay = sd.Day;
 | |
|             int EndDay = ed.Day;
 | |
| 
 | |
|             int si = System.Convert.ToInt32(sd.ToString("yyyyMMdd"));
 | |
|             int ei = System.Convert.ToInt32(ed.ToString("yyyyMMdd"));
 | |
|             bool SameDay = si == ei ? true : false;
 | |
| 
 | |
|             ////20140101
 | |
|             for (int dayinfo = si; dayinfo <= ei; dayinfo++)
 | |
|             {
 | |
|                 string DayStr = dayinfo.ToString();
 | |
|                 System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(_BaseDir + "\\" + DayStr.Substring(0, 4) + "\\" + DayStr.Substring(4, 2) + "\\" + DayStr.Substring(6));
 | |
|                 if (!dir.Exists)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 ////폴더가 존재하므로 해당 테이블파일이 존재하는지 확인한다
 | |
| 
 | |
|                 if (SameDay)
 | |
|                 {
 | |
|                     ////동일날짜라면 해당 시간대만 조회하면됨
 | |
|                     for (int hourinfo = int.Parse(sd.ToString("HH")); hourinfo <= int.Parse(ed.ToString("HH")); hourinfo++)
 | |
|                     {
 | |
|                         string fn = dir.FullName + "\\" + (hourinfo + 1).ToString("00") + ".txt";
 | |
|                         if (System.IO.File.Exists(fn))
 | |
|                         {
 | |
|                             retval.Add(fn);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (dayinfo == si) ////시작일이라면 시작시간부터 24시까지 이다.
 | |
|                     {
 | |
|                         for (int hourinfo = int.Parse(sd.ToString("HH")); hourinfo <= 23; hourinfo++)
 | |
|                         {
 | |
|                             string fn = dir.FullName + "\\" + (hourinfo + 1).ToString("00") + ".txt";
 | |
|                             if (System.IO.File.Exists(fn))
 | |
|                             {
 | |
|                                 retval.Add(fn);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     else if (dayinfo == ei) ////종료일이라면 1~ 종료시까지이다.
 | |
|                     {
 | |
|                         for (int hourinfo = 0; hourinfo <= int.Parse(ed.ToString("HH")); hourinfo++)
 | |
|                         {
 | |
|                             string fn = dir.FullName + "\\" + (hourinfo + 1).ToString("00") + ".txt";
 | |
|                             if (System.IO.File.Exists(fn))
 | |
|                             {
 | |
|                                 retval.Add(fn);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         ////중간에 끼어있는 날짜라면 1~24모두가 속한다.
 | |
|                         for (int hourinfo = 0; hourinfo <= 23; hourinfo++)
 | |
|                         {
 | |
|                             string fn = dir.FullName + "\\" + (hourinfo + 1).ToString("00") + ".txt";
 | |
|                             if (System.IO.File.Exists(fn))
 | |
|                             {
 | |
|                                 retval.Add(fn);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             retval.Sort();
 | |
|             return retval;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 이번달이후의 데이터를 조회합니다.
 | |
|         /// </summary>
 | |
|         /// <param name="ch"></param>
 | |
|         /// <returns></returns>
 | |
|         /// <remarks></remarks>
 | |
|         public (TimeSpan, DocumentElement.ALARMDataTable) GetAlarmData(int ch)
 | |
|         {
 | |
|             ////이번달이후의 데이터를 가져온다.
 | |
|             DateTime sd = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01 00:00:00"));
 | |
|             DateTime ed = DateTime.Now;
 | |
|             return GetAlarmData(ch, sd, ed);
 | |
|         }
 | |
| 
 | |
|         public (TimeSpan, DocumentElement.ALARMDataTable) GetAlarmData(DateTime sd, DateTime ed)
 | |
|         {
 | |
|             return GetAlarmData(-1, sd, ed);
 | |
|         }
 | |
| 
 | |
|         public (TimeSpan, DocumentElement.ALARMDataTable) GetAlarmData(DateTime sd, DateTime ed, int rtypes, int rtypee)
 | |
|         {
 | |
|             return GetAlarmData(-1, sd, ed, rtypes, rtypee);
 | |
|         }
 | |
| 
 | |
|         public volatile bool cancel;
 | |
|         private readonly object lockObject = new object();
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 지정된시간사이의 데이터를 조회합니다.
 | |
|         /// </summary>
 | |
|         /// <param name="stime">시작시간(20120319161800)</param>
 | |
|         /// <param name="etime">종료시간(년월일시분초)</param>
 | |
|         /// <returns></returns>
 | |
|         /// <remarks></remarks>
 | |
|         public (TimeSpan, DocumentElement.ALARMDataTable) GetAlarmData(int ch, DateTime sd, DateTime ed, int rtypes = -1, int rtypee = -1)
 | |
|         {
 | |
|             DateTime dtStart = DateTime.Now;
 | |
|             List<string> files = GetfileS(sd, ed);
 | |
| 
 | |
|             //전체파일의 내용을 버퍼에 담는다
 | |
|             Dictionary<string, string[]> lines = new Dictionary<string, string[]>();
 | |
| 
 | |
|             foreach (var fn in files)
 | |
|             {
 | |
|                 lines.Add(fn, System.IO.File.ReadAllLines(fn));
 | |
|             }
 | |
|             var totallines = lines.Sum(t => t.Value.Length);
 | |
|             Message?.Invoke(this, new MessageArgs($"total : {totallines} lines"));
 | |
| 
 | |
|             var progressMax = (double)totallines;
 | |
|             var progressVal = 0.0;
 | |
|             var currentline = 0;
 | |
|             var alertprogress = 0.0;
 | |
| 
 | |
| 
 | |
|             //ReadingProgressValueChanged?.Invoke(this, new ReadProgessArgs(0));
 | |
| 
 | |
|             var alaramDT = new DocumentElement.ALARMDataTable();
 | |
|             cancel = false;
 | |
|             try
 | |
|             {
 | |
|                 foreach (var line in lines)
 | |
|                 {
 | |
|                     foreach (string linedata in line.Value)
 | |
|                     {
 | |
| 
 | |
|                         lock (lockObject)
 | |
|                         {
 | |
|                             if (cancel)
 | |
|                             {
 | |
|                                 //Console.WriteLine("작업이 취소되었습니다.");
 | |
|                                 //token.ThrowIfCancellationRequested();  // OperationCanceledException을 발생시켜 작업을 종료합니다.
 | |
|                                 //return (new TimeSpan(0), null);
 | |
|                                 //cancel = true;
 | |
|                                 Message?.Invoke(this, new MessageArgs($"job cancel"));
 | |
|                                 break;
 | |
| 
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
| 
 | |
| 
 | |
|                         currentline += 1;
 | |
|                         progressVal = currentline / progressMax;
 | |
| 
 | |
|                         if (progressVal - alertprogress >= 5)
 | |
|                         {
 | |
|                             alertprogress = progressVal;
 | |
|                             Message?.Invoke(this, new MessageArgs($"Progress : {progressVal} lines"));
 | |
|                             //ReadingProgressValueChanged?.Invoke(this, new ReadProgessArgs(progressVal));
 | |
|                         }
 | |
| 
 | |
| 
 | |
|                         if (linedata.Trim() == "") continue;
 | |
| 
 | |
|                         string[] buf = linedata.Split(System.Convert.ToChar("\t"));
 | |
|                         if (buf.GetUpperBound(0) < 8) continue; ////데이터수량이 안맞다.
 | |
| 
 | |
|                         string chStr = buf[2];
 | |
|                         if (chStr.IsNumeric() == false) continue; ////채널정보가 일치하지 않는경우
 | |
| 
 | |
|                         if (ch > -1 && chStr != ch.ToString()) continue;
 | |
| 
 | |
|                         if (rtypes != -1 && rtypee != -1) ////rtype도 검색한다.
 | |
|                         {
 | |
|                             if (buf[3] != rtypes.ToString() && buf[3] != rtypee.ToString()) continue;
 | |
|                         }
 | |
| 
 | |
|                         var v_atime = buf[1];
 | |
|                         var v_ch = short.Parse(buf[2]);
 | |
|                         var v_rtype = short.Parse(buf[3]);
 | |
| 
 | |
|                         //존재하는 데이터는 처리하지 않느낟.
 | |
|                         if (alaramDT.Where(t => t.ATIME == v_atime && t.CH == v_ch && t.RTYPE == v_rtype).Any() == false)
 | |
|                         {
 | |
|                             var newdr = alaramDT.NewALARMRow();
 | |
|                             newdr.ATIME = v_atime;// buf[1];
 | |
|                             newdr.TIME = PUB.get_TimeString(decimal.Parse(newdr.ATIME), line.Key);
 | |
|                             newdr.CH = v_ch;// short.Parse(buf[2]);
 | |
|                             newdr.RTYPE = v_rtype;// short.Parse(buf[3]);
 | |
|                             newdr.VOLT = float.Parse(buf[4]);
 | |
|                             newdr.ATYPE = short.Parse(buf[5]);
 | |
|                             newdr.MAXVOLT = float.Parse(buf[6]);
 | |
|                             newdr.MINVOLT = float.Parse(buf[7]);
 | |
|                             newdr.AM = buf[8];
 | |
|                             newdr.AM2 = buf[9];
 | |
|                             alaramDT.AddALARMRow(newdr);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             //중복데이터
 | |
|                             PUB.log.AddAT($"알람중복데이터 atime={v_atime},ch={v_ch},rtype={v_rtype}");
 | |
|                         }
 | |
| 
 | |
| 
 | |
|                     }
 | |
| 
 | |
|                     if (cancel)
 | |
|                     {
 | |
|                         //Console.WriteLine("작업이 취소되었습니다.");
 | |
|                         //token.ThrowIfCancellationRequested();  // OperationCanceledException을 발생시켜 작업을 종료합니다.
 | |
|                         //return (new TimeSpan(0), null);
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             catch (OperationCanceledException)
 | |
|             {
 | |
|                 Console.WriteLine("작업이 정상적으로 취소되었습니다.");
 | |
|                 throw;  // 예외를 다시 던져 작업이 중지되도록 합니다.
 | |
|             }
 | |
| 
 | |
|             alaramDT.AcceptChanges();
 | |
|             var ts = DateTime.Now - dtStart;
 | |
|             return (ts, alaramDT);
 | |
|         }
 | |
| 
 | |
| 
 | |
|     }
 | |
| 
 | |
| }
 | 
