Penggunaan pemetaan memori untuk file besar di Delphi
Saya jarang menggunakan pemetaan memori file besar. Kebetulan saya menemui persyaratan seperti itu, jadi saya mencatat prosesnya untuk memberi Anda pengenalan. Karena aplikasinya tidak rumit, mungkin ada hal yang tidak bisa dipertimbangkan.
Untuk beberapa file kecil, aliran file biasa dapat digunakan untuk menyelesaikan masalah. Namun, untuk file yang sangat besar, seperti 2G atau lebih, aliran file tidak akan berfungsi, jadi Anda perlu menggunakan metode API yang terkait dengan pemetaan memori, bahkan jika itu adalah pemetaan memori. Seluruh ukuran file juga tidak dapat dipetakan sekaligus, jadi pemetaan harus dilakukan dalam beberapa bagian, memproses sebagian kecil dalam satu waktu.
Mari kita lihat beberapa fungsinya terlebih dahulu
CreateFile: membuka file
GetFileSize: Dapatkan ukuran file
CreateFileMapping: Membuat pemetaan
MapViewOfFile: file pemetaan
Melihat bantuan MapViewOfFile, dua parameter terakhirnya harus berupa kelipatan bilangan bulat dari granularitas halaman. Umumnya, granularitas halaman mesin adalah 64k (65536 byte). .Posisi apa pun, panjang apa pun dimungkinkan, jadi beberapa pemrosesan perlu dilakukan.
Tugas dari contoh ini adalah membaca nilai panjang secara berurutan dari daftar panjang (FInfoList), dan kemudian membaca data dengan panjang yang ditentukan secara berurutan dari file besar lainnya (FSourceFileName). untuk menanganinya. Cukup baca aliran file satu kali dan kemudian membacanya secara berurutan. Untuk file besar, kita perlu terus-menerus mengubah posisi pemetaan untuk mendapatkan data yang kita inginkan.
Contoh ini menunjukkan bahwa granularitas halaman pertama kali diperoleh melalui GetSystemInfo, dan kemudian 10 kali granularitas halaman digunakan sebagai blok data yang dipetakan. Dalam loop for, akan dinilai apakah panjang baca (totallen) ditambah panjang yang akan dibaca berada dalam waktu ini Dalam rentang pemetaan (10 kali granularitas halaman), jika ya, lanjutkan membaca. Jika terlampaui, sisa data harus direkam, lalu blok memori berikutnya harus dipetakan ulang, dan sisa data yang direkam harus digabungkan. ke dalam bacaan baru. Data yang didapat agak berbelit-belit (mungkin ide saya terlalu berbelit-belit),
Kode tercantum di bawah ini.
prosedur TGetDataThread.DoGetData; var FFile_Handle:THandle; FFile_Map:THandle; daftar:TStringList; p:PCar;i,interval:Integer; TMemoryStream.Buat; daftar := TStringList.Buat; //Dapatkan informasi sistem GetSystemInfo(sysinfo); //Ukuran blok granularitas alokasi halaman := sysinfo.dwAllocationGranularity; //Buka file FFile_Handle := CreateFile(PChar(FSourceFileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); FFile_Handle = INVALID_HANDLE_VALUE lalu Keluar; //Dapatkan ukuran file filesize := GetFileSize(FFile_Handle,nil); //Buat pemetaan FFile_Map := CreateFileMapping(FFile_Handle,nil,PAGE_READONLY,0,0,nil); //Di sini kita telah memetakan 10 kali ukuran blok ke dalam satu blok data. Jika ukuran file kurang dari 10 kali ukuran blok, seluruh panjang file akan langsung dipetakan jika ukuran file div ukuran blok > 10 lalu readlen := 10*ukuran blok else readlen := filesize; untuk i := 0 hingga FInfoList.Count - 1 memulai list.Delimiter := ':'; list.DelimitedText := FInfoList.Strings[i]; //Cari panjangnya, saya analisa disini, karena informasi yang saya simpan bertipe a:b:c, jadi len dipisahkan dengan ::= StrToInt(list.Strings[1]); .Strings[2]); jika (i = 0) atau (totallen+len >=readlen) maka mulailah //Jika panjang baca ditambah panjang yang akan dibaca lebih besar dari 10 kali ukuran blok, maka kita perlu mempertahankan konten di akhir pemetaan sebelumnya untuk menggabungkannya dengan konten pemetaan baru jika i > 0 lalu mulai offset := offset + readlen ; //Tulis ke aliran sementara tstream.Write(p^,readlen-totallen); granularitas, lalu langsung memetakan sisa panjangnya jika ukuran file-offset < ukuran blok lalu readlen := filesize-offset; //Pemetaan, p adalah penunjuk ke area pemetaan //Perhatikan bahwa parameter ketiga di sini selalu disetel ke 0. Nilai ini harus disetel sesuai dengan situasi sebenarnya p:= PChar(MapViewOfFile( FFile_Map,FILE_MAP_READ, 0,offset,readlen)); end; //Jika ada data dalam aliran sementara, maka perlu digabungkan jika tstream.Size > 0 lalu mulai //Salin data aliran sementara melalui stream.CopyFrom(tstream,tstream.Size); //Kemudian tulis data baru di akhir dan gabungkan untuk menyelesaikan stream.Write(p^,len-tstream.Size); - tstream.Size; //Pindahkan posisi pointer untuk menunjuk ke awal data berikutnya Inc(p,len-tstream.Size); totallen := totallen + len; Inc(p,len); end; stream.Position := 0; //Simpan aliran ke dalam file stream.SaveToFile(IntToStr(i)+'.txt'); Gratis ; tstream.Gratis; CloseHandle(FFile_Handle);
Jika Anda memiliki pertanyaan, silakan tinggalkan pesan atau kunjungi komunitas situs ini untuk berkomunikasi dan berdiskusi. Terima kasih telah membaca. Saya harap ini dapat membantu semua orang.