source: CoolStreaming/UBufferedFileStream.pas

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