source: trunk/Packages/CoolStreaming/BufferedFileStream.pas

Last change on this file was 323, checked in by chronos, 6 months ago
File size: 5.0 KB
Line 
1unit BufferedFileStream;
2
3interface
4
5uses
6 Classes, SysUtils;
7
8type
9 TBufferedFileStream = class(TStream)
10 private
11 FFile: TFileStream;
12 FBuffer: TMemoryStream;
13 FBufferPosition: Integer;
14 FBufferMaxSize: Integer;
15 FPosition: Integer;
16 FSize: Integer;
17 FDoFlush: Boolean;
18 procedure SetSize(NewSize: Longint); override;
19 procedure SetSize(const NewSize: Int64); override;
20 function GetBufferUsed: Integer;
21 function GetSize: Int64; override;
22 public
23 constructor Create(const AFileName: string; Mode: Word); overload;
24 constructor Create(const AFileName: string; Mode: Word; Rights: Cardinal); overload;
25 destructor Destroy; override;
26 function Read(var Buffer; Count: Longint): Longint; override;
27 function Write(const Buffer; Count: Longint): Longint; override;
28 function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
29 procedure Flush;
30 property BufferMaxSize: Integer read FBufferMaxSize write FBufferMaxSize;
31 property BufferUsed: Integer read GetBufferUsed;
32 end;
33
34
35implementation
36
37{ TBufferedFileStream }
38
39constructor TBufferedFileStream.Create(const AFileName: string; Mode: Word;
40 Rights: Cardinal);
41begin
42 FFile := TFileStream.Create(AFileName, Mode, Rights);
43 FSize := FFile.Size;
44 FBuffer := TMemoryStream.Create;
45 FBufferMaxSize := 60000;
46 FPosition := 0;
47end;
48
49constructor TBufferedFileStream.Create(const AFileName: string;
50 Mode: Word);
51begin
52 {$IFDEF MSWINDOWS}
53 Create(AFilename, Mode, 0);
54 {$ELSE}
55 Create(AFilename, Mode, 0);
56 {$ENDIF}
57end;
58
59destructor TBufferedFileStream.Destroy;
60begin
61 Flush;
62 FFile.Free;
63 FBuffer.Free;
64 inherited;
65end;
66
67procedure TBufferedFileStream.Flush;
68var
69 BufferMemory: Pointer;
70 WritedCount: Integer;
71begin
72 if FDoFlush then begin
73 // Write buffer to disk
74 FFile.Position := FBufferPosition;
75 BufferMemory := FBuffer.Memory;
76 FBuffer.Position := 0;
77 WritedCount := FFile.Write(BufferMemory^, FBuffer.Size);
78 FBuffer.Size := 0;
79 FDoFlush := False;
80 FBufferPosition := FBufferPosition + WritedCount;
81 end;
82end;
83
84function TBufferedFileStream.GetBufferUsed: Integer;
85begin
86 Result := FBuffer.Size;
87end;
88
89function TBufferedFileStream.GetSize: Int64;
90begin
91 Result := FSize;
92end;
93
94function TBufferedFileStream.Read(var Buffer; Count: Integer): Longint;
95var
96 ReadedCount: Integer;
97 TotalReadedCount: Integer;
98 BufferMemory: Pointer;
99 BufferPointer: Pointer;
100 RequestRead: Integer;
101begin
102 TotalReadedCount := 0;
103 repeat
104 BufferPointer := Pointer(Integer(Addr(Buffer)) + TotalReadedCount);
105 RequestRead := Count - TotalReadedCount;
106 ReadedCount := FBuffer.Read(BufferPointer^, RequestRead);
107 Inc(FPosition, ReadedCount);
108 Inc(TotalReadedCount, ReadedCount);
109 if ReadedCount < RequestRead then begin
110 if FDoFlush then Flush;
111 // Not enough data in memory buffer, read next
112 FBufferPosition := FFile.Position;
113 FBuffer.Size := FBufferMaxSize; // Allocate max. buffer size
114 BufferMemory := FBuffer.Memory;
115 FBuffer.Position := 0;
116 ReadedCount := FFile.Read(BufferMemory^, FBufferMaxSize); // Try to load max amount of data
117 FBuffer.Size := ReadedCount; // Lower buffer size
118 end;
119 until (TotalReadedCount >= Count) or (Position = Size);
120 Result := TotalReadedCount;
121end;
122
123function TBufferedFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
124begin
125 case Origin of
126 soBeginning: FPosition := Offset;
127 soCurrent: Inc(FPosition, Offset);
128 soEnd: FPosition := FFile.Size + Offset;
129 end;
130 if (FPosition > (FBufferPosition + FBuffer.Size)) or (FPosition < FBufferPosition) then begin
131 FFile.Seek(FPosition, soFromBeginning);
132 Flush;
133 FBuffer.Clear;
134 end else FBuffer.Position := FPosition - FBufferPosition;
135
136 Result := FPosition;
137end;
138
139procedure TBufferedFileStream.SetSize(NewSize: Integer);
140begin
141 FBuffer.Size := 0;
142 inherited;
143end;
144
145procedure TBufferedFileStream.SetSize(const NewSize: Int64);
146begin
147 inherited;
148 FBuffer.Size := 0;
149end;
150
151function TBufferedFileStream.Write(const Buffer; Count: Integer): Longint;
152var
153 WritedCount: Integer;
154 TotalWritedCount: Integer;
155 BufferMemory: Pointer;
156 BufferPointer: Pointer;
157 RequestWrite: Integer;
158begin
159 TotalWritedCount := 0;
160 repeat
161 BufferPointer := Pointer(Integer(Addr(Buffer)) + TotalWritedCount);
162 RequestWrite := Count - TotalWritedCount;
163 if RequestWrite > (FBufferMaxSize - FBuffer.Position) then // Limit max buffer size
164 WritedCount := FBufferMaxSize - FBuffer.Position
165 else WritedCount := RequestWrite;
166
167 WritedCount := FBuffer.Write(BufferPointer^, WritedCount);
168 Inc(FPosition, WritedCount);
169 if FPosition > FSize then FSize := FPosition;
170 Inc(TotalWritedCount, WritedCount);
171 FDoFlush := True;
172
173 if (WritedCount < RequestWrite) and FDoFlush then Flush;
174 until (TotalWritedCount >= Count);
175 Result := TotalWritedCount;
176end;
177
178end.
Note: See TracBrowser for help on using the repository browser.