Créer un pré-système de mise en cache
Cet article décrit comment contrôler un lecteur et pré-cache de petits fichiers. Ceci est particulièrement utile pour les applications qui lentement les flux de transport, tels que les lecteurs mp3 ou des applications p2p.
Cet exemple montre deux choses:
d'Abord: comment surveiller un disque à l'aide de ReadDirectoryChangesW. Cela permettra à windows de rappel de l'application à chaque fois qu'un changement dans un fichier ou attributs de fichier est fait.
d'autre part, un petit exemple d'un thread qui exécute le pré-cache.
Créer le stringlists avant d'appeler monitordrive ou de lancer le thread.
Moniteur d'un lecteur avec MonitorDrive (Chemin)
type
TTrackInfo = enregistrement
H:Integer
O:TOverLapped
B:TFNIBuf
D:String
fin
TPreCache = (de la classe TThread)
procédure d'Exécution remplacer
fin
la fonction Trace(I:Integer{TrackIndex}):LongBool
application
var Extensions : array[0..0] of String = ('.mp3')
var Pistes:Tableau de TTrackInfo
FFilesOpened, FFilesHistory:TStringList
FHasNewFileToCache:Boolean=False
FPrecached:Integer
FTotPrecached:Int64=0
FPreCachedFile:String
CS,css:TCriticalSection
//routine de Rappel:
procédure {VOID WINAPI} FileIOCompletionRoutine(
dwErrorCode:Dword // fin du code
dwNumberOfBytesTransfered:DWord // nombre d'octets transférés
lpOverlapped:Pointeur // pointeur vers la structure avec des données d'e/S
) stdcall
var S,M,V:String
POverLapped:^TOverLapped
i,l:Integer
begin
//Retour
POverLapped := lpOverLapped
// si @Superposé = POverlapped alors log ('ie')
l:=-1
for i:=0 to high(Pistes) ne
si @Pistes[i].O = lpOverlapped alors //trouvé l'index correspondant
begin
l:=i
break
fin
si l<0 alors //Aide, pas trouvé!!!
begin
// Log ('index de piste non trouvé')
sortie
fin
repeat
si vrai (true) {Pistes[l].B.Action <> 0} //ignorer répété écrit etc
begin
S:=Pistes[l].B.Nom de fichier //Cela fonctionne parce que le nom de fichier = array de WChar !
SetLength (S, par les Pistes[l].B.FileNameLength div 2)
S:=Pistes[l].D S //Faire chemin d'accès complet
{cas Pistes[l].B.L'Action de
FILE_ACTION_ADDED : M:='Le fichier a été ajouté à l'annuaire.'
FILE_ACTION_REMOVED : M:='Le fichier a été supprimé de l'annuaire.'
FILE_ACTION_MODIFIED : M:='Le fichier a été modifié. Cela peut être un changement dans le temps de timbre ou d'attributs.'
FILE_ACTION_RENAMED_OLD_NAME : M:='Le fichier a été renommé et c'est l'ancien nom.'
FILE_ACTION_RENAMED_NEW_NAME : M:='Le fichier a été renommé et c'est le nouveau nom.'
}
// Log ('Jeempie' S '' M)
//Visualiser l'activité du système:
{ //Non!! POUR le CALCUL de VASTES
si frmMain.lbxActiveFiles.Éléments.IndexOf (S 'M') < 0, alors
begin
frmMain.lbxActiveFiles.Éléments.Ajouter le (S 'M')
si frmMain.lbxActiveFiles.Éléments.Count > 8
frmMain.lbxActiveFiles.Éléments.Supprimer(0)
fin
}
// v:=minuscule (extractfileext(S))
// pour i:=faible (Extensions) à élevé(Extensions) ne
// si (Extensions[i]=V), alors
begin
//ajouter à la file d'attente
si FFilesHistory.IndexOf(S)<0, alors
begin
si FFilesHistory.Count>2000
FFilesHistory.Clair
FFilesHistory.Ajouter le(S)
CS.Entrez //Taille du fichier getfileattr
FFilesOpened.Ajouter le (S)
FHasNewFileToCache := True
CS.Quitter
fin
// Pause // isfileopen
fin
fin
si les Pistes[l].B.NextEntryOf > 0, alors
Move (Pistes[l].B.RawData[Pistes[l].B.NextEntryOf], par les Pistes[l].B.RawData[0], SizeOf(Pistes[l].B)-les Pistes[l].B.NextEntryOf)
jusqu'à ce que les Pistes[l].B.NextEntryOf = 0
//il suffit d'appeler de nouveau:
Piste(l)
fin
la fonction Trace(I:Integer{TrackIndex}):LongBool
begin
//Si nous
Result:= ReadDirectoryChangesW( Pistes[I].H,
@Pistes[i].B,
valeur DWord(SizeOf(Pistes[i].B)),
LongBool(1),
valeur DWord (
FILE_NOTIFY_CHANGE_FILE_NAME ou
FILE_NOTIFY_CHANGE_DIR_NAME ou
FILE_NOTIFY_CHANGE_ATTRIBUTES ou
FILE_NOTIFY_CHANGE_SIZE ou
FILE_NOTIFY_CHANGE_LAST_WRITE ou
FILE_NOTIFY_CHANGE_LAST_ACCESS ou
FILE_NOTIFY_CHANGE_CREATION ou
FILE_NOTIFY_CHANGE_CREATION ou
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistes[i].O,
@FileIOCompletionRoutine)
fin
procédure MonitorDrive (Chemin d'accès:String)
//Nous allons créer un ReadDirectoryChangesW (de), sous-arborescence activé,
//pour surveiller tous les fichier d'e/s.
var i:LongBool
j,l:Entier
//contenu de la mémoire Tampon:
HB:DWord
LB:LongBool
NrBytes:Integer
begin
LB:=True //Oui, récursive :)))
// pour j:=32 downto 0 do
SetLength (Pistes, haute(Pistes) 2)
l := haut(Pistes)
Pistes[l].D := Chemin d'accès
begin
HB:=SizeOf(Pistes[l].B)
Pistes[l].H
{hDir}:= CreateFile (
PChar(Chemin d'accès), // pointeur vers le nom de fichier
$1, //FILE_READ_DATA, FILE_LIST_DIRECTORY,
FILE_SHARE_READ ou FILE_SHARE_DELETE, // le mode de partage
0, // descripteur de sécurité
OPEN_EXISTING, // comment créer
FILE_FLAG_BACKUP_SEMANTICS ou FILE_FLAG_OVERLAPPED, // les attributs de fichier
0 // fichier avec des attributs pour copier
)
i:= ReadDirectoryChangesW( Pistes[l].H{hDir},
@Pistes[l].B{Buf},
HB,
LongBool(1),
valeur DWord (
FILE_NOTIFY_CHANGE_FILE_NAME ou
FILE_NOTIFY_CHANGE_DIR_NAME ou
FILE_NOTIFY_CHANGE_ATTRIBUTES ou
FILE_NOTIFY_CHANGE_SIZE ou
FILE_NOTIFY_CHANGE_LAST_WRITE ou
FILE_NOTIFY_CHANGE_LAST_ACCESS ou
FILE_NOTIFY_CHANGE_CREATION ou
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistes[l].O{verlapped},
@FileIOCompletionRoutine)
// CloseHandle (hDir), nous allons continuer à le manipuler, à droite ?
si je puis
begin
// Log ('Track réussi' IntToStr(Pistes[l].H))
fin
else //Log ('Suivi a Échoué' IntToStr(Pistes[l].H{hDir}))
fin
{ POIGNÉE hDirectory,// handle à l'annuaire pour être regardé
LPVOID lpBuffer,// pointeur vers le tampon de recevoir les résultats de lecture
DWORD nBufferLength,// longueur de la lpBuffer
BOOL bWatchSubtree,// drapeau pour la surveillance de répertoire ou du répertoire
DWORD dwNotifyFilter,// conditions de filtre à regarder pour
LPDWORD lpBytesReturned,// nombre d'octets renvoyés
LPOVERLAPPED lpOverlapped,// pointeur vers la structure nécessaires pour overlapped I/O
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine// pointeur vers l'achèvement de la routine
}
fin
procédure TPreCache.Exécuter
var F:TFileStream
s,fn:String
begin
SetLength (s, 262144) //en de la page taille de bloc=256
F:=nil
alors qu'il n'est pas Résilié ne
begin
sleep(2)
si FHasNewFileToCache puis
begin
CS.Entrez
si FFilesOpened.Count>0 then
begin
fn:=FFilesOpened[0]
FFilesOpened.Supprimer(0)
fin
else
begin
fn:='
FHasNewFileToCache := False
fin
CS.Quitter
fin
si (fn<>') et non pas (DirectoryExists(fn)) et FileExists(fn)
begin
F:=TFileStream.Create (fn, fmOpenRead ou fmShareDenyNone)
si F. Taille < 12 * 1024 * 1024 puis //12 mo max taille
begin
tandis que F. Poste < F. Taille
begin
F. Read (S[1], Longueur(S))
sommeil (32) //<2 MO/s
fin
inc (FTotPrecached, F. Taille)
FPrecached := F. la Taille
FreeAndNil (F)
feuille de style css.Entrez
FPrecachedFile := fn
feuille de style css.Quitter
fin
à l'exception de //probablement d'un fichier pour l'ouvrir, il suffit de les ignorer
fin
fn := '
s'il est Affecté(F)
FreeAndNil(F)
à l'exception de la fin
fin
fin
fin
Il y a une chose importante à faire. Afin de recevoir le message de rappel, le fil doit être en alertable état.
Cet exemple est couru depuis le thread principal, donc on utilise un timer pour que:
procedure TForm1.tmrAlertableStateTimer(Sender: TObject)
begin
SleepEx (2, True)
fin
Si vous n'appelez pas la sleepex fonction de (), la routine de rappel ne sera pas appelée.
Régler la minuterie d'intervalle raisonnable faible (200ms).
bien sûr, il serait préférable d'utiliser cette l'intérieur d'un fil, ce fil n'aurait qu'à boucle sleepex tout le temps.
nous commençons l'ensemble des choses avec ceci:
procedure TForm1.FormCreate(Sender: TObject)
type de TDrives='C'..'Z'
var d:TDrives
dt:Integer
p:TPreCache
begin
FFilesOpened := TStringList.Créer
FFilesHistory := TStringList.Créer
FFilesHistory.Triés := True
CS := TCriticalSection.Créer
css := TCriticalSection.Créer
//en voiture des pistes:
d:=faible(TDrives) à élevé(TDrives) ne
begin
dt := GetDriveType(PChar(d ':\'))
if (dt=DRIVE_FIXED) ou
(dt=DRIVE_REMOTE)
MonitorDrive(D ':\')
fin
p:=TPreCache.Create (Faux)
fin
Juste un commentaire et les parties que vous le souhaitez.
Creer un pre-systeme de mise en cache
Creer un pre-systeme de mise en cache : Plusieurs milliers de conseils pour vous faciliter la vie.
Cet article decrit comment controler un lecteur et pre-cache de petits fichiers. Ceci est particulierement utile pour les applications qui lentement les flux de transport, tels que les lecteurs mp3 ou des applications p2p.
Cet exemple montre deux choses:
d'Abord: comment surveiller un disque a l'aide de ReadDirectoryChangesW. Cela permettra a windows de rappel de l'application a chaque fois qu'un changement dans un fichier ou attributs de fichier est fait.
d'autre part, un petit exemple d'un thread qui execute le pre-cache.
Creer le stringlists avant d'appeler monitordrive ou de lancer le thread.
Moniteur d'un lecteur avec MonitorDrive (Chemin)
type
TTrackInfo = enregistrement
H:Integer
O:TOverLapped
B:TFNIBuf
D:String
fin
TPreCache = (de la classe TThread)
procedure d'Execution remplacer
fin
la fonction Trace(I:Integer{TrackIndex}):LongBool
application
var Extensions : array[0..0] of String = ('.mp3')
var Pistes:Tableau de TTrackInfo
FFilesOpened, FFilesHistory:TStringList
FHasNewFileToCache:Boolean=False
FPrecached:Integer
FTotPrecached:Int64=0
FPreCachedFile:String
CS,css:TCriticalSection
//routine de Rappel:
procedure {VOID WINAPI} FileIOCompletionRoutine(
dwErrorCode:Dword // fin du code
dwNumberOfBytesTransfered:DWord // nombre d'octets transferes
lpOverlapped:Pointeur // pointeur vers la structure avec des donnees d'e/S
) stdcall
var S,M,V:String
POverLapped:^TOverLapped
i,l:Integer
begin
//Retour
POverLapped := lpOverLapped
// si @Superpose = POverlapped alors log ('ie')
l:=-1
for i:=0 to high(Pistes) ne
si @Pistes[i].O = lpOverlapped alors //trouve l'index correspondant
begin
l:=i
break
fin
si l<0 alors //Aide, pas trouve!!!
begin
// Log ('index de piste non trouve')
sortie
fin
repeat
si vrai (true) {Pistes[l].B.Action <> 0} //ignorer repete ecrit etc
begin
S:=Pistes[l].B.Nom de fichier //Cela fonctionne parce que le nom de fichier = array de WChar !
SetLength (S, par les Pistes[l].B.FileNameLength div 2)
S:=Pistes[l].D S //Faire chemin d'acces complet
{cas Pistes[l].B.L'Action de
FILE_ACTION_ADDED : M:='Le fichier a ete ajoute a l'annuaire.'
FILE_ACTION_REMOVED : M:='Le fichier a ete supprime de l'annuaire.'
FILE_ACTION_MODIFIED : M:='Le fichier a ete modifie. Cela peut etre un changement dans le temps de timbre ou d'attributs.'
FILE_ACTION_RENAMED_OLD_NAME : M:='Le fichier a ete renomme et c'est l'ancien nom.'
FILE_ACTION_RENAMED_NEW_NAME : M:='Le fichier a ete renomme et c'est le nouveau nom.'
}
// Log ('Jeempie' S '' M)
//Visualiser l'activite du systeme:
{ //Non!! POUR le CALCUL de VASTES
si frmMain.lbxActiveFiles.Elements.IndexOf (S 'M') < 0, alors
begin
frmMain.lbxActiveFiles.Elements.Ajouter le (S 'M')
si frmMain.lbxActiveFiles.Elements.Count > 8
frmMain.lbxActiveFiles.Elements.Supprimer(0)
fin
}
// v:=minuscule (extractfileext(S))
// pour i:=faible (Extensions) a eleve(Extensions) ne
// si (Extensions[i]=V), alors
begin
//ajouter a la file d'attente
si FFilesHistory.IndexOf(S)<0, alors
begin
si FFilesHistory.Count>2000
FFilesHistory.Clair
FFilesHistory.Ajouter le(S)
CS.Entrez //Taille du fichier getfileattr
FFilesOpened.Ajouter le (S)
FHasNewFileToCache := True
CS.Quitter
fin
// Pause // isfileopen
fin
fin
si les Pistes[l].B.NextEntryOf > 0, alors
Move (Pistes[l].B.RawData[Pistes[l].B.NextEntryOf], par les Pistes[l].B.RawData[0], SizeOf(Pistes[l].B)-les Pistes[l].B.NextEntryOf)
jusqu'a ce que les Pistes[l].B.NextEntryOf = 0
//il suffit d'appeler de nouveau:
Piste(l)
fin
la fonction Trace(I:Integer{TrackIndex}):LongBool
begin
//Si nous
Result:= ReadDirectoryChangesW( Pistes[I].H,
@Pistes[i].B,
valeur DWord(SizeOf(Pistes[i].B)),
LongBool(1),
valeur DWord (
FILE_NOTIFY_CHANGE_FILE_NAME ou
FILE_NOTIFY_CHANGE_DIR_NAME ou
FILE_NOTIFY_CHANGE_ATTRIBUTES ou
FILE_NOTIFY_CHANGE_SIZE ou
FILE_NOTIFY_CHANGE_LAST_WRITE ou
FILE_NOTIFY_CHANGE_LAST_ACCESS ou
FILE_NOTIFY_CHANGE_CREATION ou
FILE_NOTIFY_CHANGE_CREATION ou
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistes[i].O,
@FileIOCompletionRoutine)
fin
procedure MonitorDrive (Chemin d'acces:String)
//Nous allons creer un ReadDirectoryChangesW (de), sous-arborescence active,
//pour surveiller tous les fichier d'e/s.
var i:LongBool
j,l:Entier
//contenu de la memoire Tampon:
HB:DWord
LB:LongBool
NrBytes:Integer
begin
LB:=True //Oui, recursive :)))
// pour j:=32 downto 0 do
SetLength (Pistes, haute(Pistes) 2)
l := haut(Pistes)
Pistes[l].D := Chemin d'acces
begin
HB:=SizeOf(Pistes[l].B)
Pistes[l].H
{hDir}:= CreateFile (
PChar(Chemin d'acces), // pointeur vers le nom de fichier
$1, //FILE_READ_DATA, FILE_LIST_DIRECTORY,
FILE_SHARE_READ ou FILE_SHARE_DELETE, // le mode de partage
0, // descripteur de securite
OPEN_EXISTING, // comment creer
FILE_FLAG_BACKUP_SEMANTICS ou FILE_FLAG_OVERLAPPED, // les attributs de fichier
0 // fichier avec des attributs pour copier
)
i:= ReadDirectoryChangesW( Pistes[l].H{hDir},
@Pistes[l].B{Buf},
HB,
LongBool(1),
valeur DWord (
FILE_NOTIFY_CHANGE_FILE_NAME ou
FILE_NOTIFY_CHANGE_DIR_NAME ou
FILE_NOTIFY_CHANGE_ATTRIBUTES ou
FILE_NOTIFY_CHANGE_SIZE ou
FILE_NOTIFY_CHANGE_LAST_WRITE ou
FILE_NOTIFY_CHANGE_LAST_ACCESS ou
FILE_NOTIFY_CHANGE_CREATION ou
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistes[l].O{verlapped},
@FileIOCompletionRoutine)
// CloseHandle (hDir), nous allons continuer a le manipuler, a droite ?
si je puis
begin
// Log ('Track reussi' IntToStr(Pistes[l].H))
fin
else //Log ('Suivi a Echoue' IntToStr(Pistes[l].H{hDir}))
fin
{ POIGNEE hDirectory,// handle a l'annuaire pour etre regarde
LPVOID lpBuffer,// pointeur vers le tampon de recevoir les resultats de lecture
DWORD nBufferLength,// longueur de la lpBuffer
BOOL bWatchSubtree,// drapeau pour la surveillance de repertoire ou du repertoire
DWORD dwNotifyFilter,// conditions de filtre a regarder pour
LPDWORD lpBytesReturned,// nombre d'octets renvoyes
LPOVERLAPPED lpOverlapped,// pointeur vers la structure necessaires pour overlapped I/O
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine// pointeur vers l'achevement de la routine
}
fin
procedure TPreCache.Executer
var F:TFileStream
s,fn:String
begin
SetLength (s, 262144) //en de la page taille de bloc=256
F:=nil
alors qu'il n'est pas Resilie ne
begin
sleep(2)
si FHasNewFileToCache puis
begin
CS.Entrez
si FFilesOpened.Count>0 then
begin
fn:=FFilesOpened[0]
FFilesOpened.Supprimer(0)
fin
else
begin
fn:='
FHasNewFileToCache := False
fin
CS.Quitter
fin
si (fn<>') et non pas (DirectoryExists(fn)) et FileExists(fn)
begin
F:=TFileStream.Create (fn, fmOpenRead ou fmShareDenyNone)
si F. Taille < 12 * 1024 * 1024 puis //12 mo max taille
begin
tandis que F. Poste < F. Taille
begin
F. Read (S[1], Longueur(S))
sommeil (32) //<2 MO/s
fin
inc (FTotPrecached, F. Taille)
FPrecached := F. la Taille
FreeAndNil (F)
feuille de style css.Entrez
FPrecachedFile := fn
feuille de style css.Quitter
fin
a l'exception de //probablement d'un fichier pour l'ouvrir, il suffit de les ignorer
fin
fn := '
s'il est Affecte(F)
FreeAndNil(F)
a l'exception de la fin
fin
fin
fin
Il y a une chose importante a faire. Afin de recevoir le message de rappel, le fil doit etre en alertable etat.
Cet exemple est couru depuis le thread principal, donc on utilise un timer pour que:
procedure TForm1.tmrAlertableStateTimer(Sender: TObject)
begin
SleepEx (2, True)
fin
Si vous n'appelez pas la sleepex fonction de (), la routine de rappel ne sera pas appelee.
Regler la minuterie d'intervalle raisonnable faible (200ms).
bien sûr, il serait preferable d'utiliser cette l'interieur d'un fil, ce fil n'aurait qu'a boucle sleepex tout le temps.
nous commençons l'ensemble des choses avec ceci:
procedure TForm1.FormCreate(Sender: TObject)
type de TDrives='C'..'Z'
var d:TDrives
dt:Integer
p:TPreCache
begin
FFilesOpened := TStringList.Creer
FFilesHistory := TStringList.Creer
FFilesHistory.Tries := True
CS := TCriticalSection.Creer
css := TCriticalSection.Creer
//en voiture des pistes:
d:=faible(TDrives) a eleve(TDrives) ne
begin
dt := GetDriveType(PChar(d ':\'))
if (dt=DRIVE_FIXED) ou
(dt=DRIVE_REMOTE)
MonitorDrive(D ':\')
fin
p:=TPreCache.Create (Faux)
fin
Juste un commentaire et les parties que vous le souhaitez.
Créer un pré-système de mise en cache
By commentfaire
Créer un pré-système de mise en cache : Plusieurs milliers de conseils pour vous faciliter la vie.