2009-10-14 4 views
0

저는 Delphi 2007을 사용 중이며 내부 네트워크를 통해 여러 위치에서 로그 파일을 읽고 예외를 표시하는 응용 프로그램을 보유하고 있습니다. 이러한 디렉토리에는 때때로 수천 개의 로그 파일이 있습니다. 응용 프로그램은 최신 날짜의 로그 파일 만 읽을 수있는 옵션을 가지고 있으며 날짜 시간 범위에있을 수도 있습니다.네트워크를 통해 로그 파일을 실제로 읽는 방법은 무엇입니까?

처음으로 로그 디렉토리를 읽는 것은 매우 느릴 수 있습니다 (몇 분). 두 번째로 상당히 빠릅니다.

가능한 한 빨리 로그 파일을 읽도록 코드를 최적화 할 수 있을지 궁금합니다. vCurrentFile : TStringList를 사용하여 메모리에 파일을 저장합니다. 이 방법이 FileStream에서 업데이트 된 것 같습니다.

새로 고침 : 여기

는 일부 코드이다 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; 

에 하나 개의 행을 추가 : 메인 루프가 로그 파일

// 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; 

UpdateView 방법를 읽고 행이 daterange에 있는지를 결정하는 메소드 :

filedate가 범위 내에있는 경우
{: 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; 

답변

0

얼마나 빠르 길 원하십니까? 당신이 정말로 빠르길 원한다면, 파일을 읽기 위해 윈도우 네트워킹 외에 뭔가를 사용해야합니다. 그 이유는 로그 파일의 마지막 행 (또는 마지막으로 읽은 이후의 모든 행)을 읽으려면 전체 파일을 다시 읽어야하기 때문입니다.

귀하의 질문에 귀하의 디렉토리 목록을 열거하는 것이 느리다는 것이 문제라고 말했습니다. 그것이 당신의 첫번째 병목입니다. 정말 빠르려면 HTTP로 전환하거나 로그 파일이 저장된 시스템에 일종의 로그 서버를 추가해야합니다.

HTTP를 사용하는 이점은 범위 요청을 할 수 있으며 마지막으로 요청한 이후 추가 된 로그 파일의 새 줄을 가져 오는 것입니다. 데이터를 덜 전송하고 (특히 HTTP 압축을 사용하는 경우) 특히 클라이언트 측에서 처리 할 데이터가 적기 때문에 성능이 향상됩니다.

일종의 로그 서버를 추가하면 해당 서버는 데이터에 대한 기본 액세스 권한이있는 서버 측에서 처리를 수행하고 날짜 범위에있는 행만 반환합니다.이를 수행하는 간단한 방법은 로그를 일종의 SQL 데이터베이스에 저장 한 다음 쿼리를 실행하는 것입니다.

그럼 얼마나 빨리 가고 싶습니까?

+0

예, 프로그램 코드에서 할 일이 많지 않다는 것을 두려워했습니다. 몇 년 전에 데이터베이스에 로그를 저장하고 SQL로 액세스하는 프로젝트가 있었지만 완료되지 않았습니다. 하지만 우리가 서버의 로그를 준비하는 데 많은 시간을 할애한다면 꽤 빠를 수 있습니다. 하지만 이것은 우선 순위가 높은 프로젝트가 아닙니다 :) 어쨌든 당신이 대답 해 주셔서 감사합니다. –

+0

더 많은 코딩 작업을 할 때마다 매번 전체 파일을 읽지 않아도됩니다. 파일의 마지막 부분에만 관심이 있다면 마지막 몇 KB를 찾아 직접 읽어보십시오. –

2

문제는 논리지만, 기본 파일 시스템이 아닙니다.

디렉토리에 많은 파일을 넣으면 대부분의 파일 시스템이 매우 느려집니다. 이것은 FAT에서 매우 나쁘지 만, 특히 NTFS는 디렉토리에 수천 개의 파일이있는 경우에 문제가 발생합니다.

할 수있는 최선의 방법은 예를 들어 나이별로 해당 디렉토리 구조를 재구성하는 것입니다.

그런 다음 각 디렉토리에 최대 두 개의 100 개의 파일이 있습니다.

- 제로

+0

사실이긴하지만 현실입니다. 필자의 경우 거의 30 일 이상 검색된 파일이 아니기 때문에 오래된 파일을 예정된 박쥐 파일에 의해 보관 디렉토리로 이동해야 검색 속도가 빨라집니다. –

+0

두 번째로 빠를 이유는 서버가 메모리의 정보를 캐시했기 때문입니다. 따라서 Delphi 측에서 할 수있는 일은 속도를 높이는 것입니다 (속도를 조금 높일 수는 있지만 사용자는 그 효과를 눈치 채지 못할 것입니다). 따라서 더 이상 필요하지 않은 파일을 보관하는 것이 가장 좋습니다. –

관련 문제