كيف تقرأ ملفات السجل عبر الشبكة بسرعة حقيقية؟
-
21-09-2019 - |
سؤال
أنا أستخدم Delphi 2007 ولدي تطبيق يقرأ ملفات السجل من عدة أماكن عبر شبكة داخلية وعرض استثناءات. تحتوي هذه الدلائل أحيانًا على آلاف ملفات السجل. يحتوي التطبيق على خيار لقراءة ملفات السجل فقط من آخر أيام N ، ويمكن أن يكون أيضًا في أي نطاق DateTime.
المشكلة هي أنه في المرة الأولى التي يتم فيها قراءة دليل السجل يمكن أن تكون بطيئة للغاية (عدة دقائق). المرة الثانية هي أسرع بكثير.
أتساءل كيف يمكنني تحسين التعليمات البرمجية الخاصة بي لقراءة ملفات السجل في أسرع وقت ممكن؟ أنا أستخدم vCurrentFile: TstringList لتخزين الملف في الذاكرة. يتم تحديث هذا من filestream كما أعتقد أن هذا أسرع.
هنا بعض التعليمات البرمجية:
تحديث: الحلقة الرئيسية لقراءة ملفات السجل
// In this function the logfiles are searched for exceptions. If a exception is found it is stored in a object.
// The exceptions are then shown in the grid
procedure TfrmMain.Refresh;
var
FileData : TSearchRec; // Used for the file searching. Contains data of the file
vPos, i, PathIndex : Integer;
vCurrentFile: TStringList;
vDate: TDateTime;
vFileStream: TFileStream;
begin
tvMain.DataController.RecordCount := 0;
vCurrentFile := TStringList.Create;
memCallStack.Clear;
try
for PathIndex := 0 to fPathList.Count - 1 do // Loop 0. This loops until all directories are searched through
begin
if (FindFirst (fPathList[PathIndex] + '\*.log', faAnyFile, FileData) = 0) then
repeat // Loop 1. This loops while there are .log files in Folder (CurrentPath)
vDate := FileDateToDateTime(FileData.Time);
if chkLogNames.Items[PathIndex].Checked and FileDateInInterval(vDate) then
begin
tvMain.BeginUpdate; // To speed up the grid - delays the guichange until EndUpdate
fPathPlusFile := fPathList[PathIndex] + '\' + FileData.Name;
vFileStream := TFileStream.Create(fPathPlusFile, fmShareDenyNone);
vCurrentFile.LoadFromStream(vFileStream);
fUser := FindDataInRow(vCurrentFile[0], 'User'); // FindData Returns the string after 'User' until ' '
fComputer := FindDataInRow(vCurrentFile[0], 'Computer'); // FindData Returns the string after 'Computer' until ' '
Application.ProcessMessages; // Give some priority to the User Interface
if not CancelForm.IsCanceled then
begin
if rdException.Checked then
for i := 0 to vCurrentFile.Count - 1 do
begin
vPos := AnsiPos(MainExceptionToFind, vCurrentFile[i]);
if vPos > 0 then
UpdateView(vCurrentFile[i], i, MainException);
vPos := AnsiPos(ExceptionHintToFind, vCurrentFile[i]);
if vPos > 0 then
UpdateView(vCurrentFile[i], i, HintException);
end
else if rdOtherText.Checked then
for i := 0 to vCurrentFile.Count - 1 do
begin
vPos := AnsiPos(txtTextToSearch.Text, vCurrentFile[i]);
if vPos > 0 then
UpdateView(vCurrentFile[i], i, TextSearch)
end
end;
vFileStream.Destroy;
tvMain.EndUpdate; // Now the Gui can be updated
end;
until(FindNext(FileData) <> 0) or (CancelForm.IsCanceled); // End Loop 1
end; // End Loop 0
finally
FreeAndNil(vCurrentFile);
end;
end;
تحديث طريقة: أضف صفًا واحدًا إلى DisplayGrid
{: Update the grid with one exception}
procedure TfrmMain.UpdateView(aLine: string; const aIndex, aType: Integer);
var
vExceptionText: String;
vDate: TDateTime;
begin
if ExceptionDateInInterval(aLine, vDate) then // Parse the date from the beginning of date
begin
if aType = MainException then
vExceptionText := 'Exception'
else if aType = HintException then
vExceptionText := 'Exception Hint'
else if aType = TextSearch then
vExceptionText := 'Text Search';
SetRow(aIndex, vDate, ExtractFilePath(fPathPlusFile), ExtractFileName(fPathPlusFile), fUser, fComputer, aLine, vExceptionText);
end;
end;
طريقة لتحديد ما إذا كان الصف في Daterange:
{: This compare exact exception time against the filters
@desc 2 cases: 1. Last n days
2. From - to range}
function TfrmMain.ExceptionDateInInterval(var aTestLine: String; out aDateTime: TDateTime): Boolean;
var
vtmpDate, vTmpTime: String;
vDate, vTime: TDateTime;
vIndex: Integer;
begin
aDateTime := 0;
vtmpDate := Copy(aTestLine, 0, 8);
vTmpTime := Copy(aTestLine, 10, 9);
Insert(DateSeparator, vtmpDate, 5);
Insert(DateSeparator, vtmpDate, 8);
if TryStrToDate(vtmpDate, vDate, fFormatSetting) and TryStrToTime(vTmpTime, vTime) then
aDateTime := vDate + vTime;
Result := (rdLatest.Checked and (aDateTime >= (Now - spnDateLast.Value))) or
(rdInterval.Checked and (aDateTime>= dtpDateFrom.Date) and (aDateTime <= dtpDateTo.Date));
if Result then
begin
vIndex := AnsiPos(']', aTestLine);
if vIndex > 0 then
Delete(aTestLine, 1, vIndex + 1);
end;
end;
اختبار ما إذا كان الملف داخل النطاق:
{: Returns true if the logtime is within filters range
@desc Purpose is to sort out logfiles that are no idea to parse (wrong day)}
function TfrmMain.FileDateInInterval(aFileTimeStamp: TDate): Boolean;
begin
Result := (rdLatest.Checked and (Int(aFileTimeStamp) >= Int(Now - spnDateLast.Value))) or
(rdInterval.Checked and (Int(aFileTimeStamp) >= Int(dtpDateFrom.Date)) and (Int(aFileTimeStamp) <= Int(dtpDateTo.Date)));
end;
المحلول
ما هي السرعة التي تريد أن تكون؟ إذا كنت تريد أن تكون سريعًا حقًا ، فأنت بحاجة إلى استخدام شيء إلى جانب شبكات Windows لقراءة الملفات. السبب هو إذا كنت تريد قراءة السطر الأخير من ملف السجل (أو جميع الخطوط منذ آخر مرة تقرأها) ، فأنت بحاجة إلى قراءة الملف بالكامل مرة أخرى.
في سؤالك ، قلت أن المشكلة هي أنه بطيء في تعداد قائمة الدليل الخاصة بك. هذا هو أول عنق الزجاجة. إذا كنت تريد أن تكون سريعًا حقيقيًا ، فأنت بحاجة إلى التبديل إلى HTTP أو إضافة نوع من خادم السجل إلى الجهاز حيث يتم تخزين ملفات السجل.
ميزة استخدام HTTP هي أنه يمكنك القيام بطلب النطاق والحصول على الخطوط الجديدة لملف السجل الذي تمت إضافته منذ آخر مرة طلبته. سيؤدي ذلك حقًا إلى تحسين الأداء نظرًا لأنك تقوم بنقل بيانات أقل (خاصة إذا قمت بتمكين ضغط HTTP) ولديك أيضًا بيانات أقل لمعالجة جانب العميل.
إذا قمت بإضافة خادم سجل من نوع ما ، فيمكن لهذا الخادم القيام بالمعالجة على جانب الخادم ، حيث يتمتع بوصول أصلي إلى البيانات ، وإرجاع الصفوف فقط في نطاق التاريخ. قد تكون هناك طريقة بسيطة للقيام بذلك هي وضع سجلاتك في قاعدة بيانات SQL من نوع ما ، ثم تشغيل الاستعلامات ضدها.
لذا ، ما مدى سرعة الذهاب؟
نصائح أخرى
المشكلة ليست منطقك ، ولكن نظام الملفات الأساسي.
تصبح معظم أنظمة الملفات بطيئة للغاية عند وضع العديد من الملفات في الدليل. هذا أمر سيء للغاية مع الدهون ، لكن NTFs يعاني منه أيضًا ، خاصة إذا كان لديك آلاف الملفات في الدليل.
أفضل ما يمكنك فعله هو إعادة تنظيم هياكل الدليل هذه ، على سبيل المثال حسب العمر.
ثم يكون لديك على الأكثر في 100 ملف في كل دليل.
-جيرون