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 System.Linq; using System.Threading; using System.Threading.Tasks; using System.IO; namespace vmsnet { public class CFDBA { // ..\Database\Alarm /* 알람 */ 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 ReadingProgressValueChanged; public event EventHandler 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); } } /// /// 데이터를 기록합니다. /// /// 기록시간(파일명이 결정됨) /// 기록할테이블명(파일명) /// 기록할데이터(열데이터가 틀려서 고정할 수 없다) /// /// 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 GetfileS(DateTime sd, DateTime ed) { List retval = new List(); 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; } /// /// 이번달이후의 데이터를 조회합니다. /// /// /// /// 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(); /// /// 지정된시간사이의 데이터를 조회합니다. /// /// 시작시간(20120319161800) /// 종료시간(년월일시분초) /// /// public (TimeSpan, DocumentElement.ALARMDataTable) GetAlarmData(int ch, DateTime sd, DateTime ed, int rtypes = -1, int rtypee = -1) { DateTime dtStart = DateTime.Now; List files = GetfileS(sd, ed); //전체파일의 내용을 버퍼에 담는다 Dictionary lines = new Dictionary(); 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); } } }