سؤال

أنا أستخدم 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 ملف في كل دليل.

-جيرون

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top