Recently, I have been open to the album software (http://www.tonix.net/ultraalbum/index.php?lang=chs) to open a big file, and my previous practice is to open a file with TFileStream. Then find the data segment therein, copy the content to a TMEMORYSTREAM, and then copy it to a separate TMEMORYSTREAM because a subsequent file type database component must accept a whole TSTREAM as its storage medium The whole process is simply unbearable. The reason why the speed is slow, there are two reasons: 1. Open the file with TFileStream, the operating system generates memory mirroring for the file after opening the file, the file is large, then the opening of the space and the work of the memory will become extremely slow. 2. Copy some of TFileStream to TMemoryStream, this replication process will open new memory and then replicate, and it will be a large memory, and the replication time will also grow. I am determined to write a file reading class, and then call TFastFileStream. It must be inherited from TSTREAM, so that it can be easily combined with other components.
First, to solve the problem of opening a big file, for this, use mappviewoffile () to access the file directly as a memory image, about mappViewoffile (), and file memory mirror, you can refer to this article: the method of establishing the http://www.vccode.com/file_show.php?id=2409Delphi mirror file as: constructor TFastFileStream.Create (const aFileName: String); var FileSizeHigh: LongWord; begin FFileHandle: = CreateFile (PChar (aFileName ), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if FFileHandle = INVALID_HANDLE_VALUE then begin raise FastFileStreamException.Create ( 'Error when open file'); end; FSize: = GetFileSize (FFileHandle, @ FileSizeHigh); if FSize = INVALID_FILE_SIZE then begin raise FastFileStreamException.Create ( 'Error when get file size'); end; FMappingHandle: = CreateFileMapping (FFileHandle, nil, PAGE_READONLY, 0,0, nil); if FMappingHandle = 0 then begin raise FastFileStreamException.Create ( 'Error when mapping file '); end; FMemory: = MapViewOfFile (FMappingHandle, FILE_MAP_READ, 0,0,0); if FMemory = nil then begin raise FastFileStreamException.Create (' Error when map view of file '); end; end; final , was made The image of the mirror is stored in the FMemory, then cover the TSTREAM's READ () method. When the external needs to get data, let it go to FMEMORY: Function TFastFileStream.read (var buffer; count: longint): Longint Begin if (fposition> = 0) and (count> = 0) Then Begin Result: = fsize - fposition; if Result> 0 The beginness: = count; //move (Pointer (FMEMory ) Fposition) ^, buffer, result); copyMemory (Pointer), Pointer (long), result; incitation, incitation; End; end; result: = 0; END;
This function is mainly written by simulating the same name method in TCUSTomMemoryStream, but there is a little strange, when I use Delphi's own memory copy function Move (), the program always accesses illegal addresses, so I have to change to API Function CopyMemory (). Further, there is need to implement the function: function TFastFileStream.GetSize (): Int64; begin result: = FSize; end; function TFastFileStream.Seek (const Offset: Int64; Origin: TSeekOrigin): Int64; begin case Ord (Origin) of SOFROMBEGINNING: FPSIMBEGINNING: = Offset; SOFROMCURRENT: INC; SOFROMEND: fposition: = fsize off; end; result: = fposition; end; This is a complete set of file read mechanisms. Due to complexity relationship, I didn't realize file preservation mechanism, interested friends, please do it yourself. Next, it is necessary to solve how to optimize the current use of the two streams of the current STREAM. It is the way to start to create a new Stream class. It does not open memory when copying data from other streams. Instead, the internal memory pointer points to a certain paragraph in the source stream, but in this way, this Stream class can only be used in the source stream's survival, and the relationship seems to be a chaotic. Later, I suddenly thought of another way. In fact, for external classes (ie I used the file type database component), it just use read (), seek (), etc. to access data, then I just use some spoofings. The method allows the internal class to return to the outside. It is only a certain paragraph in its internal data. For my programs, after finding the position I want, set a virtual data range, and the data within the virtual data range is returned when external access. In this way, it is only necessary to make certain modifications on the basis of the original TFastFileStream. procedure TFastFileStream.SetUseableMemory (const StartPos: Int64; const Size: Int64); begin FUseableStartPos: = StartPos; FSize: = Size; end; function TFastFileStream.Read (var Buffer; Count: LongInt): LongInt; begin ... CopyMemory ( Pointer (@Buffer), Pointer (long (fMemory) fuseableableStartPOS fposition), result); ... End; ok, you will end this, and finally replace this newly written FileStream class, one trial, The speed is really amazing, it turns opens a nearly 30MB file, use two stream classes, it takes about 40 seconds, changed to new TFastFileStream, only one class is required, Time is within 5 seconds, haha, really Cool! If you need this complete code, you can write to me: tonyki [at] citiz.net