2009-04-22 3 views
4

D6 Professional을 사용 중이며 이미 메모리에있는 많은 작은 문자열의 특정 형식으로 텍스트 파일을 만들어야합니다. 성능상의 이유로 TMemoryStream을 사용하여 파일 데이터를 대조 한 다음 TFileStream을 통해 한 번에 디스크에 기록하는 것이 고려 중입니다.파일에 쓰기 전에 효율적인 버퍼로 TMemoryStream을 사용해야합니까?

그러나 TMemoryStream이 비효율적 인 곳, 특히 용량 크기에 도달 한 후 어딘가에서 읽은 부분을 반쯤 잊어 버렸습니다 (아마도 D6 일 전부터). My Delphi (및 Windows API) 기술은 Classes.pas 코드를 직접 확인하기에 충분하지 않습니다. 이런

(논외) 특히 코드 (Classes.pas 라인 5152)
NewCapacity = (NewCapacity + (MemoryDelta - 1)) 및하지 (MemoryDelta - 1); 내 걱정에 추가
(/ 논외)

는 관련 질문 Using MemoryStream to write out to XML
의 결론은 TMemoryStream을 사용 아니었지만, 왜 말을하지 않았다입니다 - 여부로 인해 TMemoryStream이 자체, 또는 때문에이 TFileStream 또는 I/O 장치 드라이버에서 버퍼링이 충분하거나 문제가되는 코드의 세부 사항 만 있습니다.

모든 조언 주셔서 감사합니다.
감사합니다.
PhilW.

+1

안녕 필

라이언, 당신이 어떤 버퍼링을 사용하게 했습니까? 나는 버퍼링이 파일에 나의 쓰기를 가속화 할 것인지에 관해 궁금하게 생각하고있는이 페이지를 가로 질러 할 수있다. 저는 수백만 개의 큰 정수를 파일로 작성하고 TaaWriteBufferFilter를 시도해 보았습니다. 라이언은 Ryan과 연결하여 Win XP Pro에서 파일 저장 시간을 약 6 초로 줄였습니다. 따라서 작은 글을 많이 작성한다면 TFileStream을 버퍼링 된 스트림으로 래핑하는 것이 도움이되는지 확인하는 데 몇 분 정도 시간을 할애 할 가치가 있다고 말하고 싶습니다. 감사 : D – CodeAndCats

답변

8

일반 TFileStram도 버퍼링을 수행하며 I/O를 최적화하기에 충분합니다. MemoryStream을 앞에두면 오버 헤드가 추가됩니다.

+3

헨크, TFileStream이 버퍼링되었는지 확실히 알고 있습니까? 시간이 지남에 따라 나는 여러 장소에서 TFileStream을 ** 읽지 않은 채로 ** 읽었으며, 델파이의 텍스트 파일 구현은 그렇지 않습니다. 필자의 연습은 - readln이 매우 빠르다는 것을 확인하는 반면, TFileStream에서 읽는 것은 특히 빠릅니다. 루프에서 많은 작은 버퍼를 읽을 때. 버퍼링되지 않은 파일 스트림 (예 : Primoz Gabrijelcic의 TGpBufferedStream)을 구현 한 Delphi가 여러 개 있습니다. 또한 기본 파일 스트림이 버퍼링되지 않은 상태로 suggtests합니다. –

+0

아니요, Delphi Wrapper TFileStream은 버퍼링을하지 않지만 Win32 스트림은 (제한적 임에도 불구하고) 버퍼링을 수행합니다. –

+0

"간단하게 유지하십시오"라는 접근 방식은 언제나 좋습니다. 조언 해주셔서 감사합니다. – PhilW

2

TStringList를 사용하고 SaveToFile 메서드를 호출 할 수 있습니다. TStringList에는 문자열을 추가 할 때 메모리가 복사되지 않는다는 장점이 있습니다.

또 다른 옵션은 Jedi JCL 클래스 TJclBufferedStream입니다.

8

TFileStream 자체는 버퍼링을 수행하지 않으며, 이는 OS에 의해 처리되며 일반적으로 대부분의 목적으로 충분합니다.

내 제안은 데이터를 스트림에 쓰고이 메서드에 TSTream 매개 변수를 전달하는 메서드를 작성하는 것입니다. 이 방법을 사용하면 프로그램에 영향을 미치지 않고 다른 옵션을 쉽게 테스트 할 수 있습니다. 예를 들어

: 이전에 언급 된 JCL에서

Procedure TForm1.StreamMyObjects(aStream : tStream); 
begin 
    aStream.Write(MyString[1], Length(MyString) * SizeOf(Char)); 
    aStream.Write(CRLF, Length(CRLF) * SizeOf(Char)); 
    aStream.Write(MyOtherString[1], Length(MyOtherString) * SizeOf(Char)); 
    aStream.Write(CRLF, Length(CRLF) * SizeOf(Char)); 
end; 

은, 당신이 다음 어떤 성능 이점이 있는지에 대한 테스트, 무엇을 당신의 쓰기에 따라 달라질 수있는 TJclBufferedStream있다 그리고 얼마나 많이 쓰는지. 루틴 다음 내 테스트에서

var 
    fstm : tFileSTream; 
    fBufStm : tJCLBufferedStream; 
    iTicks : Cardinal; 
    fModes : word; // for SO formatting. 
begin 
    fModes := fmOpenReadWrite or fmCreate or fmShareExclusive; 

    iTicks := GetTickCount; 
    fstm := tFilestream.create('test1.txt',fModes); 
    StreamMyObjects(fStm); 
    fstm.free; 
    ShowMessage('TEST1='+IntToSTr(GetTickCount-iTicks)); 

    iTicks := GetTickCount; 
    fstm := tFilestream.create('test2.txt',fModes); 
    fBufStm := tJclBufferedStream.create(fStm); 
    StreamMyObjects(fBufStm); 
    fBufStm.free; 
    fstm.free; 
    ShowMessage('TEST2='+IntToSTr(GetTickCount-iTicks)); 
end; 

: 예를 들어 (그래 난 내가 TRY/마침내 누락 알고) 다음은 TFileStream을을 테스트하고, tJCLBufferedStream 차이점이 무엇인지 볼 수

procedure TForm1.StreamMyObjects(aSTream: tStream); 
var 
    St : string; 
    ix : integer; 
begin 
    for ix := 0 to 10000 do 
    begin 
     St := 'This is a string which is written to a stream. ' + IntToStr(ix); 
     aStream.Write(st[1], Length(st) * SizeOf(Char)); 
    end; 
end; 

은 tFilestream에 대해 47, tJCLBufferedStream에 대해 16을 반환합니다. 루프가 없으면 시간은 중요하지 않습니다. 따라서 데이터와 비교하여 테스트해야합니다.

0

나만의 제한된 크기의 버퍼를 만드는 것이 문제가되는지 조사 할 것입니다. TFileStream에 작은 비트를 쓰는 속도가 느립니다 (특히 스토리지 볼륨에서 지연된 쓰기가 비활성화 된 경우). 디스크 드라이버가 각 작은 비트에 쓸 섹터를 찾아야하기 때문에. 그래서 몇 섹터 크기의 버퍼를 사용한다면 (512KB 또는 1MB 정도의 안전한 추측이 될 것입니다) 버퍼가 가득 찼을 때 버퍼를 쓰면 엄청나게 부 풀리는 일과 관련하여 걱정할 필요없이 작업 속도를 높일 수 있습니다 TMemoryStream.

2

TFileStream 앞에서 TMemoryStream을 추가 한 다른 사람들이 언급했듯이, 어디서 가야할 지 알 수 없습니다.

Julian Bucknall은 "The Delphi Magazine"기사에서 TStream 객체에 기능을 추가하는 프리웨어 유닛과 클래스 세트를 제작했습니다. 나는 TStream 객체들 (특히 TFileStream)에 대한 나의 거래에서 그것들이 매우 유용하다는 것을 알았다.

아래 링크는 Google 코드 검색에서 가져온 것으로, aaStrms.pas 파일에 직접 액세스 할 수 있습니다. aaStrms.pas 파일을 사용하려면 다른 단위 (aaIntDeq.pas, aaIntList.pas, aaRegEx.pas 및 aaStrBld.pas)가 필요합니다. 이것들은 모두 비 시각적 클래스이므로 유닛을 포함시키고 클래스를 인스턴스화하기 만하면됩니다.

http://www.google.com/codesearch/p?hl=en#7-hAM65i1Xc/disks/dmag70.zip|alfresco/AAStrms.pas&q=lang:pascal%20aaStrms

은 내가 TaaWriteBufferFilter 클래스를 사용하려는 하나라고 제안했다.

HTH,

+0

+1 26MB 이진 파일의 30 초 쓰기/읽기를 약 5 초로 줄이는 데 도움을 주신 +1! 건배! :디 – CodeAndCats