.
Type TPartialTextfile =
Class
Private
_FileName:
String;
_FileHandle: THandle;
_FileSize, _Start: Int64;
_OrgLen: Integer;
_Part: TStringList;
Function _FindNextLineBreak(
Const i: Int64): Integer;
Public
Constructor Create;
Destructor Destroy;
Override;
Property FileName:
String Read _FileName;
Property FileSize: Int64
Read _FileSize;
Property Start: Int64
Read _Start;
Property OrgLen: Integer
Read _OrgLen;
Property Part: TStringList
Read _Part;
Function Open (
Const FileName:
String): Boolean;
Function LoadPart (
Const Pos: Int64; MinLen: Integer): Boolean;
Overload;
Function LoadPart (
{next part} MinLen: Integer): Boolean;
Overload;
Function LoadPartLi(
Const Pos: Int64; Lines: Integer): Boolean;
Overload;
Function LoadPartLi(
{next part} Lines: Integer): Boolean;
Overload;
Function SavePart: Boolean;
Procedure Close;
End;
Function TPartialTextfile._FindNextLineBreak(
Const i: Int64): Integer;
Var B:
Array[0..65535]
of Char;
i2: LARGE_INTEGER;
W, W2: Cardinal;
Begin
Result := 0;
Repeat
i2.QuadPart := i + Result;
i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
If i2.QuadPart <> i + Result
Then Exit;
ReadFile(_FileHandle, B, SizeOf(B), W,
nil);
If (W <> SizeOf(B))
and (W <> _FileSize - i - Result)
Then Exit;
W2 := 0;
While W2 < W
do Begin
Inc(W2);
Case B[W2 - 1]
of
#0, #10: Break;
#13:
Begin
If W2 > W
Then Begin
i2.QuadPart := i + Result + W2;
i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
If i2.QuadPart = i + Result + W2
Then Begin
ReadFile(_FileHandle, B, 1, W,
nil);
If (W = 1)
and (B[0] = #10)
Then Inc(W2);
End;
End Else If B[W2] = #10
Then Inc(W2);
Break;
End;
End;
End;
Inc(Result, W2);
Until W < SizeOf(B);
End;
Constructor TPartialTextfile.Create;
Begin
_FileHandle := INVALID_HANDLE_VALUE;
_Part := TStringList.Create;
End;
Destructor TPartialTextfile.Destroy;
Begin
_Part.Free;
End;
Function TPartialTextfile.Open(
Const FileName:
String): Boolean;
Var i64: LARGE_INTEGER;
Begin
If _FileHandle <> INVALID_HANDLE_VALUE
Then Close;
_FileHandle := CreateFile(PChar(FileName), GENERIC_READ
or GENERIC_WRITE,
FILE_SHARE_READ,
nil, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
If _FileHandle <> INVALID_HANDLE_VALUE
Then Begin
i64.LowPart := GetFileSize(_FileHandle, @i64.HighPart);
_FileName := FileName;
_FileSize := i64.QuadPart;
Result := True;
End Else Result := False;
End;
Function TPartialTextfile.LoadPart(
Const Pos: Int64; MinLen: Integer): Boolean;
Var S:
String;
W: Cardinal;
i: LARGE_INTEGER;
Begin
Result := False;
If (_FileHandle = INVALID_HANDLE_VALUE)
or (Pos > _FileSize)
or (MinLen <= 0)
Then Exit;
Try
SetLength(S, _FindNextLineBreak(Pos + MinLen));
Except
Exit;
End;
i.QuadPart := Pos;
i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
If i.QuadPart <> Pos
Then Exit;
ReadFile(_FileHandle, S[1], Length(S), W,
nil);
If Length(S) <> Integer(W)
Then Exit;
Try
_Start := Pos;
_OrgLen := Length(S);
_Part.Text := S;
Except
_OrgLen := 0;
_Part.Clear;
Exit;
End;
Result := True;
End;
Function TPartialTextfile.LoadPart(MinLen: Integer): Boolean;
Begin
Result := LoadPartLi(_Start + _OrgLen, MinLen);
End;
Function TPartialTextfile.LoadPartLi(
Const Pos: Int64; Lines: Integer): Boolean;
Var S:
String;
W: Cardinal;
i: LARGE_INTEGER;
Begin
Result := False;
If (_FileHandle = INVALID_HANDLE_VALUE)
or (Pos > _FileSize)
or (Lines <= 0)
Then Exit;
W := 0;
While Lines > 0
do Begin
Inc(W, _FindNextLineBreak(Pos + W));
If Integer(W) < 0
Then Exit;
Dec(Lines);
End;
Try
SetLength(S, W);
Except
Exit;
End;
i.QuadPart := Pos;
i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
If i.QuadPart <> Pos
Then Exit;
ReadFile(_FileHandle, S[1], Length(S), W,
nil);
If Length(S) <> Integer(W)
Then Exit;
Try
_Start := Pos;
_OrgLen := Length(S);
_Part.Text := S;
Except
_OrgLen := 0;
_Part.Clear;
Exit;
End;
Result := True;
End;
Function TPartialTextfile.LoadPartLi(Lines: Integer): Boolean;
Begin
Result := LoadPartLi(_Start + _OrgLen, Lines);
End;
Function TPartialTextfile.SavePart: Boolean;
Var S:
String;
W, W2: Cardinal;
B:
Array[0..65535]
of Char;
i, i2: LARGE_INTEGER;
i3: Integer;
Begin
Result := False;
If _FileHandle = INVALID_HANDLE_VALUE
Then Exit;
Try
S := _Part.Text;
Except
Exit;
End;
i3 := _OrgLen - Length(S);
If i3 > 0
Then Begin
i.QuadPart := _Start + _OrgLen;
While i.QuadPart < _FileSize
do Begin
i2.QuadPart := i.QuadPart;
i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
If i2.QuadPart <> i.QuadPart
Then Exit;
ReadFile(_FileHandle, B, SizeOf(B), W,
nil);
If (W <> SizeOf(B))
and (W <> _FileSize - i.QuadPart)
Then Exit;
W2 := W;
i2.QuadPart := i.QuadPart - i3;
i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
If i2.QuadPart <> i.QuadPart - i3
Then Exit;
WriteFile(_FileHandle, B, W2, W,
nil);
If W <> W2
Then Exit;
Inc(i.QuadPart, SizeOf(B));
End;
End Else If i3 < 0
Then Begin
i3 := -i3;
i.QuadPart := _Start + _OrgLen;
Inc(i.QuadPart, (_FileSize - i.QuadPart)
and -SizeOf(B));
While i.QuadPart >= _Start + _OrgLen
do Begin
i2.QuadPart := i.QuadPart;
i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
If i2.QuadPart <> i.QuadPart
Then Exit;
ReadFile(_FileHandle, B, SizeOf(B), W,
nil);
If (W <> SizeOf(B))
and (W <> _FileSize - i.QuadPart)
Then Exit;
W2 := W;
i2.QuadPart := i.QuadPart + i3;
i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
If i2.QuadPart <> i.QuadPart + i3
Then Exit;
WriteFile(_FileHandle, B, W2, W,
nil);
If W <> W2
Then Exit;
dec(i.QuadPart, SizeOf(B));
End;
End;
Dec(_FileSize, i3);
i.QuadPart := _FileSize;
i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
If i.QuadPart = _FileSize
Then SetEndOfFile(_FileHandle);
i.QuadPart := _Start;
i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
If i.QuadPart <> _Start
Then Exit;
WriteFile(_FileHandle, S[1], Length(S), W,
nil);
_OrgLen := Length(S);
Result := Length(S) <> Integer(W);
End;
Procedure TPartialTextfile.Close;
Begin
CloseHandle(_FileHandle);
_FileName := '
';
_FileHandle := INVALID_HANDLE_VALUE;
_FileSize := 0;
_Start := 0;
_OrgLen := 0;
_Part.Clear;
End;