2016-08-27 2 views
1

필자는 Windows 10에서 Berlin을 사용합니다. tList<string>을 파일에 저장하려고합니다.tList를 쓰는 중 tListStream

나는 tStringlist, tStreamWriter 및 tStreamReader를 처리하는 방법을 알고 있지만 다른 유형의 데이터를 추가해야하기 때문에 tFileStream을 사용해야합니다.

다음 코드에서 데이터를 읽는 Button2Click 루프는 eOutOfMemory 예외를 발생시킵니다. 간단한 문자열 값을 _String 할당 할 때 잘 작동하지만 동일한 _String tList 값을 넣을 경우 파일에 잘못된 데이터가 기록 된 것 같습니다. _String := _List.List[i]_String := 'qwert'의 차이를 이해할 수 없습니다.

어떻게 tFileSteam에 tList<string>을 쓸 수 있습니까?

당신이, 당신을 알려줍니다 무엇을 TFileStream.Write 워드 프로세서에서 조회하면 ( THandleStream.Write에서 상속)
procedure TForm1.Button1Click(Sender: TObject); 
var 
    _List: TList<string>; 
    _FileStream: TFileStream; 
    _String: string; 
    i: Integer; 
begin 
    _List := TList<string>.Create; 

    _List.Add('abcde'); 
    _List.Add('abcde12345'); 

    _FileStream := TFileStream.Create('test', fmCreate); 

    for i := 0 to 1 do 
    begin 
    _String := _List.List[i]; // _String := 'qwert' works well 

    _FileStream.Write(_string, 4); 
    end; 

    _FileStream.Free; 
    _List.Free; 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    _FileStream: TFileStream; 
    _String: string; 
    i: Integer; 
begin 
    _FileStream := TFileStream.Create('test', fmOpenRead); 

    for i := 0 to 1 do 
    begin 
    _FileStream.Read(_String, 4); 

    Memo1.Lines.Add(_String); 
    end; 

    _FileStream.Free; 
end; 
+0

직렬화를 시도 했습니까? –

+0

@ IgnacioVazquez-Abrams 아니요. 나는 그 말을 듣지 못해서 미안합니다. –

+0

왜 [TStringList] (http://docwiki.embarcadero.com/Libraries/en/System.Classes.TStringList)를 사용하지 않고 SaveToFile 및 LoadFromFile 메서드가 있습니까? – whosrdaddy

답변

2

:

function Write(const Buffer; Count: Longint): Longint; override; 
function Write(const Buffer: TBytes; Offset, Count: Longint): Longint; override; 

는 자원의 현재 위치에 버퍼 바이트 카운트 씁니다.

이제 Buffer은 타이핑되지 않았으므로 쓰여지는 데이터의 메모리 주소가 될 것으로 예상됩니다. 실제 문자열 데이터에 대한 참조 인 문자열 변수를 전달하면 변수의 주소에 문자열 데이터에 대한 포인터가 저장됩니다. 따라서 파일 포인터를 쓰고 있습니다. ....write(PChar(_String)^, ...

: 당신은 컴파일러 지시문 {$ ZEROBASEDSTRINGS ON}에있는 경우

이 버퍼의 문자열을 첫 번째 문자를 통과 해결하려면, ....write(_string[1], ... 이 0 또는 색인을 사용, PChar와 역 참조 문자열을 캐스트

그런 다음 두 번째 매개 변수 Count을 확인하십시오. 워드 프로세서가 말한 것처럼, 바이트의 수를 나타냅니다. 구체적으로는 문자가 아닙니다. Delphi 2009 및 이후 문자열은 UnicodeString이므로 각 문자는 2 바이트입니다. 바이트 단위로 문자열 크기를 전달해야합니다.

파일 스트림에 4 자 (8 바이트) 기록합니다 : 당신이 변화에 대응해야 읽기

_FileStream.Write(_String[1], 4 * SizeOf(Char)); 

이상

_FileStream.Write(PChar(_String)^, 4 * SizeOf(Char)); 

, 그러나 가장 주목할만한, 다음을 수행해야 읽기 전에 문자열 길이를 설정하십시오 (길이는 문자로 계산됩니다).

SetLength(_String, 4); 
    for i := 0 to 1 do 
    begin 
    _FileStream.Read(_String[1], 4 * SizeOf(Char)); 

    Memo1.Lines.Add(_String); 
    end; 

당신이 문자열 쓰기를 일반화 할 수이 낮은 수준의 접근 방식을 계속 다음과 같이 읽기하려면 문자열의 길이를 유지하는 변수를 추가

var 
    _String: string; 
    _Length: integer; 

다음

를 작성
begin 
    ... 
    for .... 
    begin 
    _String := _List.List[i]; 
    _Length := Length(_String); 
    _FileStream.Write(_Length, SizeOf(Integer)); 
    _FileStream.Write(PChar(_List.List[i])^, _Length * SizeOf(Char)); 
    end; 

및 읽기

begin 
    ... 
    for .... 
    begin 
    _FileStream.Read(_Length, SizeOf(Integer)); 
    SetLength(_String, _Length); 
    _FileStream.Read(_String[1], _Length * SizeOf(Char)); 
    Memo1.Lines.Add(_String); 
    end; 

IOW, 먼저 길이를 쓰고 그 다음에 문자열을 씁니다. 독서에서 너는 길이 및 그 후에 끈을 읽는다.

+0

쓰기 _List.Add ('abcde'); _String : = _List.List [0]; _FileStream.Write (_string [1], 5); SetLength (_String, 5)를 읽는 것; _FileStream.Read (_String [1], 5); 잘 작동합니다. 귀하의 의견은 제가이 문제를 해결할 수 있도록 도움이되었습니다. 쓰기 및 읽기에는 각 tList 항목의 크기가 있어야하며 이는 성가시다. ShortString의 정적 문자열을 사용하는 것이 좋습니다. 고마워. –

+0

@JOSeongGng 내 업데이트를 참조하십시오. –

+0

문자열 [1]의 경우 길이는 길이 * 2 여야합니다. 유니 코드에 대한 귀하의 의견은 매우 유용했습니다. 고마워. –

관련 문제