I made an application to copy a file using thread and the method of TFileStream, but I was a little disappointed with the speed, especially when copying large files. Then I heard about the file mapping, which apparently could certainly yield a method of copying a lot faster since access to the files would be much faster.
I'm a beginner so I'm trying to, but I have not managed to copy a file via file mapping. (The file is created test2.iso but instead of doing 0ko 3GB ^ ^.)
Here is my code.
procedure TForm1.Button1Click(Sender: TObject);
var
FFilehandle: THANDLE;
FFileMap: THANDLE;
FmappingPtr: pchar;
hFile2: THANDLE ;
SizeFile1,BytesWritten: DWORD ;
begin
FFilehandle := CreateFile('titan.iso',
GENERIC_WRITE OR GENERIC_READ,
FILE_SHARE_READ OR FILE_SHARE_WRITE,
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (FFilehandle <> INVALID_HANDLE_VALUE) then
begin
FFileMap := CreateFileMapping(FFileHandle, // handle to file to map
nil, // optional security attributes
PAGE_READWRITE, // protection for mapping object
0, // high-order 32 bits of object size
2*1024, // low-order 32 bits of object size
0); //
if (FFileMap <> NULL) then
begin
FMappingPtr := MapViewOfFile(FFileMap,
FILE_MAP_WRITE,
0,
0,
0);
if Assigned(FMappingPtr) then
begin
// Manipulation de FMappingPtr
hFile2 := CreateFile('test.iso', GENERIC_WRITE, 0, nil,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile2 <> INVALID_HANDLE_VALUE) then
begin
SizeFile1 := GetFileSize(FFilehandle, NIL); // recupere taille du fichier 1
WriteFile(hFile2, Fmappingptr, SizeFile1, &BytesWritten, NIL); // Transfert la mémoire mappé dans file 2
// libere les ressources
end
else
MessageBox(0, 'Impossible de lire le fichier mappé', 'Error', 0);
UnmapViewOfFile(Fmappingptr);
CloseHandle(FFileMap);
CloseHandle(FFilehandle);
CloseHandle(hFile2);
end
else
begin
CloseHandle (FFileMap);
CloseHandle (FFileHandle);
MessageBox(0, 'Impossible de lire le fichier mappé', 'Error', 0);
end;
end
else
begin
CloseHandle (FFilemap);
MessageBox(0, 'Impossible de mappe le fichier en mémoire', 'Error', 0);
end;
end
else
MessageBox(NULL, 'Impossible d''ouvrir le fichier', 'Error', NULL);
end;
Where is my problem?
Not that I disagree with the comments to your question, but there are two reasons that fail your code.
First is, you're specifying 2Kb for dwFileOffsetLow
with CreateFileMapping
but then passing the entire file size to WriteFile
. With this mapping view, 'WriteFile' should be called at most with 2Kb for nNumberOfBytesToWrite
.
Second is, you're not passing the starting address of your file data correct, try this:
[...]
FFileMap := CreateFileMapping(FFileHandle, // handle to file to map
nil, // optional security attributes
PAGE_READWRITE, // protection for mapping object
0, // high-order 32 bits of object size
0, // low-order 32 bits of object size
0); //
if (FFileMap <> NULL) then
begin
FMappingPtr := MapViewOfFile(FFileMap,
FILE_MAP_WRITE,
0,
0,
0);
if Assigned(FMappingPtr) then
begin
// Manipulation de FMappingPtr
hFile2 := CreateFile('test.iso', GENERIC_WRITE, 0, nil,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile2 <> INVALID_HANDLE_VALUE) then
begin
SizeFile1 := GetFileSize(FFilehandle, NIL); // recupere taille du fichier 1
WriteFile(hFile2, Fmappingptr[0], SizeFile1, &BytesWritten, NIL); // Transfert la mémoire mappé dans file 2
// libere les ressources
end
[...]
BTW, the reason the code is not returning any errors is that you're not checking the return of 'WriteFile'.