Crear un pre-sistema de almacenamiento en caché
en Este artículo se describe cómo supervisar una unidad y pre-caché de archivos pequeños. Esto es especialmente útil con aplicaciones que poco a poco las secuencias de transporte, como los reproductores de mp3 o aplicaciones p2p.
Este ejemplo demuestra dos cosas:
Primero: cómo controlar una unidad con ReadDirectoryChangesW. Esto permitirá que el windows de devolución de llamada de la aplicación cada vez que un cambio en un archivo o atributos de archivo se hace.
en Segundo lugar, un pequeño ejemplo de un subproceso que realiza la pre-caché.
Crear el stringlists antes de llamar a monitordrive o el lanzamiento de la rosca.
Monitor de una unidad con MonitorDrive (Pathname)
tipo
TTrackInfo = record
H:Integer
O:TOverLapped
B:TFNIBuf
D:String
fin
TPreCache = class(clase TThread)
la Ejecución del procedimiento de invalidación
fin
la función de Seguimiento(I:Integer{TrackIndex}):LongBool
aplicación
var Extensiones : array[0..0] of String = ('.mp3')
var Pistas:Matriz de TTrackInfo
FFilesOpened, FFilesHistory:TStringList
FHasNewFileToCache:Boolean=False
FPrecached:Integer
FTotPrecached:Int64=0
FPreCachedFile:String
CS,css:TCriticalSection
//rutina de devolución de llamada:
procedimiento {VOID WINAPI} FileIOCompletionRoutine(
dwErrorCode:Dword // código de finalización
dwNumberOfBytesTransfered:DWord // número de bytes transferidos
lpOverlapped:Puntero // puntero a la estructura de e/S de información.
a ) stdcall
var S,M,V:String
POverLapped:^TOverLapped
i,l:Integer
begin
//Return
POverLapped := lpOverLapped
// si @Superpuesta = POverlapped entonces log ('ie')
l:=-1
for i:=0 a alta(Pistas)
si @Pistas[i].O = lpOverlapped entonces //encuentra el índice correspondiente
begin
l:=i
break
fin
si l<0 entonces //no encontrado!
begin
// Log ('pista de índice no se encuentra')
salir
fin
repetir
si es cierto, {Pistas de[l].B.La acción <> 0}, entonces //ignorar los repetidos escribe, etc
begin
S:=Pistas de[l].B.Nombre de archivo //Esto funciona porque FileName = matriz de WChar !
SetLength (S, Pistas de[l].B.FileNameLength div 2)
S:=Pistas de[l].D S //Hacer la ruta completa
{case Pistas de[l].B.La acción de
FILE_ACTION_ADDED : M:='El archivo se ha añadido al directorio.'
FILE_ACTION_REMOVED : M:='El archivo se elimina del directorio.'
FILE_ACTION_MODIFIED : M:='El archivo fue modificado. Esto puede ser un cambio en la marca de tiempo o atributos.'
FILE_ACTION_RENAMED_OLD_NAME : M:='El archivo se ha cambiado de nombre y este es el antiguo nombre.'
FILE_ACTION_RENAMED_NEW_NAME : M:='El archivo se ha cambiado de nombre y este es el nuevo nombre.'
}
// Log ('Jeempie ' S', M)
//Visualizar la actividad del sistema:
{ //No!! A la COMPUTACIÓN AMPLIA
si frmMain.lbxActiveFiles.Elementos.IndexOf (S, M) < 0, entonces
begin
frmMain.lbxActiveFiles.Elementos.Agregar (S, M)
si frmMain.lbxActiveFiles.Elementos.Count > 8
frmMain.lbxActiveFiles.Elementos.Eliminar(0)
fin
}
// v:=minúsculas (extractfileext(S))
// para i:=baja (Extensiones) a alta(Extensiones)
// si (Extensiones[i]=V) entonces
begin
//añadir a la cola
si FFilesHistory.IndexOf(S)<0, entonces
begin
si FFilesHistory.Count>2000, a continuación,
FFilesHistory.Claro
FFilesHistory.Agregar(S)
CS.Enter //Tamaño de archivo getfileattr
FFilesOpened.Agregar (S)
FHasNewFileToCache := True
CS.Dejar
fin
// Romper // isfileopen
fin
fin
si las Pistas de[l].B.NextEntryOf > 0, entonces
Mover (Pistas de[l].B.RawData[Pistas de[l].B.NextEntryOf], Pistas de[l].B.RawData[0], SizeOf(Pistas de[l].B)-Pistas de[l].B.NextEntryOf)
hasta las Pistas de[l].B.NextEntryOf = 0
//acabamos de llamar a la Pista de nuevo:
Pista(l)
fin
la función de Seguimiento(I:Integer{TrackIndex}):LongBool
begin
//Si nos
Resultado:= ReadDirectoryChangesW( Pistas[I].H,
@Pistas[i].B,
valor de DWord(SizeOf(Pistas[i].B)),
LongBool(1),
valor de DWord (
FILE_NOTIFY_CHANGE_FILE_NAME o
FILE_NOTIFY_CHANGE_DIR_NAME o
FILE_NOTIFY_CHANGE_ATTRIBUTES o
FILE_NOTIFY_CHANGE_SIZE o
FILE_NOTIFY_CHANGE_LAST_WRITE o
FILE_NOTIFY_CHANGE_LAST_ACCESS o
FILE_NOTIFY_CHANGE_CREATION o
FILE_NOTIFY_CHANGE_CREATION o
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistas[i].O,
@FileIOCompletionRoutine)
fin
procedimiento MonitorDrive (Ruta:String)
//vamos a establecer una ReadDirectoryChangesW (), subárbol habilitado,
//para supervisar todos los archivos I/O.
var i:LongBool
j,l:Integer
//contenido del Buffer:
HB:DWord
LB:LongBool
NrBytes:Integer
begin
LB:=True //Sí, recursiva :)))
// para j:=32 downto 0
SetLength (Pistas, alta(Pistas) 2)
l := alto(Pistas)
Tracks[l].D := Ruta de acceso
begin
HB:=SizeOf(Pistas de[l].B)
Tracks[l].H
{hDir}:= CreateFile (
PChar(Ruta de acceso), // puntero al nombre de archivo
$1, //FILE_READ_DATA, FILE_LIST_DIRECTORY,
FILE_SHARE_READ o FILE_SHARE_DELETE, // share mode
0, // descriptor de seguridad
OPEN_EXISTING, // cómo crear
FILE_FLAG_BACKUP_SEMANTICS o FILE_FLAG_OVERLAPPED, // atributos de archivo
0 // archivo con atributos para copiar
)
i:= ReadDirectoryChangesW( Pistas de[l].H{hDir},
@Pistas de[l].B{Buf},
HB,
LongBool(1),
valor de DWord (
FILE_NOTIFY_CHANGE_FILE_NAME o
FILE_NOTIFY_CHANGE_DIR_NAME o
FILE_NOTIFY_CHANGE_ATTRIBUTES o
FILE_NOTIFY_CHANGE_SIZE o
FILE_NOTIFY_CHANGE_LAST_WRITE o
FILE_NOTIFY_CHANGE_LAST_ACCESS o
FILE_NOTIFY_CHANGE_CREATION o
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistas de[l].O{verlapped},
@FileIOCompletionRoutine)
// CloseHandle (hDir) Vamos a mantener el mango, ¿verdad ?
si
begin
// Log ('Pista correcta' IntToStr(Pistas de[l].H))
fin
else //Log ('Pista Fracasado' IntToStr(Pistas de[l].H{hDir}))
fin
{ MANEJAR hDirectory,// identificador del directorio para ser visto
LPVOID lpBuffer,// puntero al buffer para recibir la lectura de los resultados
DWORD nBufferLength,// longitud de lpBuffer
BOOL bWatchSubtree,// bandera para el seguimiento de directorio o árbol de directorios
DWORD dwNotifyFilter,// condiciones de filtro para ver por
LPDWORD lpBytesReturned,// número de bytes devueltos
LPOVERLAPPED lpOverlapped,// puntero a la estructura necesaria para la e/S superpuesta
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine// puntero a la rutina de finalización
}
fin
procedimiento TPreCache.Ejecutar
var F:TFileStream
s,fn:String
begin
SetLength (s, 262144) //página tamaño del bloque=256K
F:=nil
mientras no se terminen de hacer
begin
el sueño(2)
si FHasNewFileToCache, a continuación,
begin
CS.Entrar
si FFilesOpened.Count>0 then
begin
fn:=FFilesOpened[0]
FFilesOpened.Eliminar(0)
fin
else
begin
fn:='
FHasNewFileToCache := False
fin
CS.Dejar
fin
si (fn<>') y no (DirectoryExists(fn)) y FileExists(fn), a continuación,
begin
prueba
F:=TFileStream.Create (fn, fmOpenRead o fmShareDenyNone)
si F. Tamaño < 12 * 1024 * 1024 entonces //12 mb de tamaño máximo
begin
mientras que F. Posición < F. Tamaño
begin
F. Lectura (S[1], la Longitud de la(S))
el sueño (32) //<2 MB/s
fin
inc (FTotPrecached, F. Tamaño)
FPrecached := F. Tamaño
FreeAndNil (F)
css.Entrar
FPrecachedFile := fn
css.Dejar
fin
excepto //probablemente archivo no se pudo abrir, simplemente ignore
fin
fn := '
prueba
si se ha Asignado(F), a continuación,
FreeAndNil(F)
excepto el final
final
fin
fin
Hay una cosa importante que hacer. Con el fin de recibir el mensaje de devolución de llamada, el hilo debe estar en wait_alertable estado.
Este ejemplo se corrió desde el hilo principal, por lo que se utiliza un temporizador para que:
procedure TForm1.tmrAlertableStateTimer(Sender: TObject)
begin
SleepEx (2, True)
fin
Si usted no llama la sleepex() función, la rutina de devolución de llamada no se llama.
Establecer el temporizador de intervalo razonable de baja (200ms).
por supuesto, sería mejor para ejecutar esta dentro de un hilo, este hilo sólo tendría bucle sleepex todo el tiempo.
empezamos el conjunto de cosas con esto:
procedure TForm1.FormCreate(Sender: TObject)
tipo de TDrives='C'..'Z'
var d:TDrives
dt:Integer
p:TPreCache
begin
FFilesOpened := TStringList.Crear
FFilesHistory := TStringList.Crear
FFilesHistory.Ordenada := True
CS := TCriticalSection.Crear
css := TCriticalSection.Crear
//unidad de pistas:
d:=baja(TDrives) a alta(TDrives)
begin
dt := GetDriveType(PChar(d ':/'))
si (dt=DRIVE_FIXED) o
(dt=DRIVE_REMOTE), a continuación,
MonitorDrive(D ':/')
fin
p:=TPreCache.Create (Falso)
fin
Sólo un comentario dentro y fuera de las partes como quieras.
Crear un pre-sistema de almacenamiento en cache
Crear un pre-sistema de almacenamiento en cache : Multi-millones de consejos para hacer su vida mas facil.
en Este articulo se describe como supervisar una unidad y pre-cache de archivos pequeños. Esto es especialmente util con aplicaciones que poco a poco las secuencias de transporte, como los reproductores de mp3 o aplicaciones p2p.
Este ejemplo demuestra dos cosas:
Primero: como controlar una unidad con ReadDirectoryChangesW. Esto permitira que el windows de devolucion de llamada de la aplicacion cada vez que un cambio en un archivo o atributos de archivo se hace.
en Segundo lugar, un pequeño ejemplo de un subproceso que realiza la pre-cache.
Crear el stringlists antes de llamar a monitordrive o el lanzamiento de la rosca.
Monitor de una unidad con MonitorDrive (Pathname)
tipo
TTrackInfo = record
H:Integer
O:TOverLapped
B:TFNIBuf
D:String
fin
TPreCache = class(clase TThread)
la Ejecucion del procedimiento de invalidacion
fin
la funcion de Seguimiento(I:Integer{TrackIndex}):LongBool
aplicacion
var Extensiones : array[0..0] of String = ('.mp3')
var Pistas:Matriz de TTrackInfo
FFilesOpened, FFilesHistory:TStringList
FHasNewFileToCache:Boolean=False
FPrecached:Integer
FTotPrecached:Int64=0
FPreCachedFile:String
CS,css:TCriticalSection
//rutina de devolucion de llamada:
procedimiento {VOID WINAPI} FileIOCompletionRoutine(
dwErrorCode:Dword // codigo de finalizacion
dwNumberOfBytesTransfered:DWord // numero de bytes transferidos
lpOverlapped:Puntero // puntero a la estructura de e/S de informacion.
a ) stdcall
var S,M,V:String
POverLapped:^TOverLapped
i,l:Integer
begin
//Return
POverLapped := lpOverLapped
// si @Superpuesta = POverlapped entonces log ('ie')
l:=-1
for i:=0 a alta(Pistas)
si @Pistas[i].O = lpOverlapped entonces //encuentra el indice correspondiente
begin
l:=i
break
fin
si l<0 entonces //no encontrado!
begin
// Log ('pista de indice no se encuentra')
salir
fin
repetir
si es cierto, {Pistas de[l].B.La accion <> 0}, entonces //ignorar los repetidos escribe, etc
begin
S:=Pistas de[l].B.Nombre de archivo //Esto funciona porque FileName = matriz de WChar !
SetLength (S, Pistas de[l].B.FileNameLength div 2)
S:=Pistas de[l].D S //Hacer la ruta completa
{case Pistas de[l].B.La accion de
FILE_ACTION_ADDED : M:='El archivo se ha añadido al directorio.'
FILE_ACTION_REMOVED : M:='El archivo se elimina del directorio.'
FILE_ACTION_MODIFIED : M:='El archivo fue modificado. Esto puede ser un cambio en la marca de tiempo o atributos.'
FILE_ACTION_RENAMED_OLD_NAME : M:='El archivo se ha cambiado de nombre y este es el antiguo nombre.'
FILE_ACTION_RENAMED_NEW_NAME : M:='El archivo se ha cambiado de nombre y este es el nuevo nombre.'
}
// Log ('Jeempie ' S', M)
//Visualizar la actividad del sistema:
{ //No!! A la COMPUTACION AMPLIA
si frmMain.lbxActiveFiles.Elementos.IndexOf (S, M) < 0, entonces
begin
frmMain.lbxActiveFiles.Elementos.Agregar (S, M)
si frmMain.lbxActiveFiles.Elementos.Count > 8
frmMain.lbxActiveFiles.Elementos.Eliminar(0)
fin
}
// v:=minusculas (extractfileext(S))
// para i:=baja (Extensiones) a alta(Extensiones)
// si (Extensiones[i]=V) entonces
begin
//añadir a la cola
si FFilesHistory.IndexOf(S)<0, entonces
begin
si FFilesHistory.Count>2000, a continuacion,
FFilesHistory.Claro
FFilesHistory.Agregar(S)
CS.Enter //Tamaño de archivo getfileattr
FFilesOpened.Agregar (S)
FHasNewFileToCache := True
CS.Dejar
fin
// Romper // isfileopen
fin
fin
si las Pistas de[l].B.NextEntryOf > 0, entonces
Mover (Pistas de[l].B.RawData[Pistas de[l].B.NextEntryOf], Pistas de[l].B.RawData[0], SizeOf(Pistas de[l].B)-Pistas de[l].B.NextEntryOf)
hasta las Pistas de[l].B.NextEntryOf = 0
//acabamos de llamar a la Pista de nuevo:
Pista(l)
fin
la funcion de Seguimiento(I:Integer{TrackIndex}):LongBool
begin
//Si nos
Resultado:= ReadDirectoryChangesW( Pistas[I].H,
@Pistas[i].B,
valor de DWord(SizeOf(Pistas[i].B)),
LongBool(1),
valor de DWord (
FILE_NOTIFY_CHANGE_FILE_NAME o
FILE_NOTIFY_CHANGE_DIR_NAME o
FILE_NOTIFY_CHANGE_ATTRIBUTES o
FILE_NOTIFY_CHANGE_SIZE o
FILE_NOTIFY_CHANGE_LAST_WRITE o
FILE_NOTIFY_CHANGE_LAST_ACCESS o
FILE_NOTIFY_CHANGE_CREATION o
FILE_NOTIFY_CHANGE_CREATION o
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistas[i].O,
@FileIOCompletionRoutine)
fin
procedimiento MonitorDrive (Ruta:String)
//vamos a establecer una ReadDirectoryChangesW (), subarbol habilitado,
//para supervisar todos los archivos I/O.
var i:LongBool
j,l:Integer
//contenido del Buffer:
HB:DWord
LB:LongBool
NrBytes:Integer
begin
LB:=True //Si, recursiva :)))
// para j:=32 downto 0
SetLength (Pistas, alta(Pistas) 2)
l := alto(Pistas)
Tracks[l].D := Ruta de acceso
begin
HB:=SizeOf(Pistas de[l].B)
Tracks[l].H
{hDir}:= CreateFile (
PChar(Ruta de acceso), // puntero al nombre de archivo
$1, //FILE_READ_DATA, FILE_LIST_DIRECTORY,
FILE_SHARE_READ o FILE_SHARE_DELETE, // share mode
0, // descriptor de seguridad
OPEN_EXISTING, // como crear
FILE_FLAG_BACKUP_SEMANTICS o FILE_FLAG_OVERLAPPED, // atributos de archivo
0 // archivo con atributos para copiar
)
i:= ReadDirectoryChangesW( Pistas de[l].H{hDir},
@Pistas de[l].B{Buf},
HB,
LongBool(1),
valor de DWord (
FILE_NOTIFY_CHANGE_FILE_NAME o
FILE_NOTIFY_CHANGE_DIR_NAME o
FILE_NOTIFY_CHANGE_ATTRIBUTES o
FILE_NOTIFY_CHANGE_SIZE o
FILE_NOTIFY_CHANGE_LAST_WRITE o
FILE_NOTIFY_CHANGE_LAST_ACCESS o
FILE_NOTIFY_CHANGE_CREATION o
FILE_NOTIFY_CHANGE_SECURITY
),
nil,//@NrBytes,
@Pistas de[l].O{verlapped},
@FileIOCompletionRoutine)
// CloseHandle (hDir) Vamos a mantener el mango, ¿verdad ?
si
begin
// Log ('Pista correcta' IntToStr(Pistas de[l].H))
fin
else //Log ('Pista Fracasado' IntToStr(Pistas de[l].H{hDir}))
fin
{ MANEJAR hDirectory,// identificador del directorio para ser visto
LPVOID lpBuffer,// puntero al buffer para recibir la lectura de los resultados
DWORD nBufferLength,// longitud de lpBuffer
BOOL bWatchSubtree,// bandera para el seguimiento de directorio o arbol de directorios
DWORD dwNotifyFilter,// condiciones de filtro para ver por
LPDWORD lpBytesReturned,// numero de bytes devueltos
LPOVERLAPPED lpOverlapped,// puntero a la estructura necesaria para la e/S superpuesta
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine// puntero a la rutina de finalizacion
}
fin
procedimiento TPreCache.Ejecutar
var F:TFileStream
s,fn:String
begin
SetLength (s, 262144) //pagina tamaño del bloque=256K
F:=nil
mientras no se terminen de hacer
begin
el sueño(2)
si FHasNewFileToCache, a continuacion,
begin
CS.Entrar
si FFilesOpened.Count>0 then
begin
fn:=FFilesOpened[0]
FFilesOpened.Eliminar(0)
fin
else
begin
fn:='
FHasNewFileToCache := False
fin
CS.Dejar
fin
si (fn<>') y no (DirectoryExists(fn)) y FileExists(fn), a continuacion,
begin
prueba
F:=TFileStream.Create (fn, fmOpenRead o fmShareDenyNone)
si F. Tamaño < 12 * 1024 * 1024 entonces //12 mb de tamaño maximo
begin
mientras que F. Posicion < F. Tamaño
begin
F. Lectura (S[1], la Longitud de la(S))
el sueño (32) //<2 MB/s
fin
inc (FTotPrecached, F. Tamaño)
FPrecached := F. Tamaño
FreeAndNil (F)
css.Entrar
FPrecachedFile := fn
css.Dejar
fin
excepto //probablemente archivo no se pudo abrir, simplemente ignore
fin
fn := '
prueba
si se ha Asignado(F), a continuacion,
FreeAndNil(F)
excepto el final
final
fin
fin
Hay una cosa importante que hacer. Con el fin de recibir el mensaje de devolucion de llamada, el hilo debe estar en wait_alertable estado.
Este ejemplo se corrio desde el hilo principal, por lo que se utiliza un temporizador para que:
procedure TForm1.tmrAlertableStateTimer(Sender: TObject)
begin
SleepEx (2, True)
fin
Si usted no llama la sleepex() funcion, la rutina de devolucion de llamada no se llama.
Establecer el temporizador de intervalo razonable de baja (200ms).
por supuesto, seria mejor para ejecutar esta dentro de un hilo, este hilo solo tendria bucle sleepex todo el tiempo.
empezamos el conjunto de cosas con esto:
procedure TForm1.FormCreate(Sender: TObject)
tipo de TDrives='C'..'Z'
var d:TDrives
dt:Integer
p:TPreCache
begin
FFilesOpened := TStringList.Crear
FFilesHistory := TStringList.Crear
FFilesHistory.Ordenada := True
CS := TCriticalSection.Crear
css := TCriticalSection.Crear
//unidad de pistas:
d:=baja(TDrives) a alta(TDrives)
begin
dt := GetDriveType(PChar(d ':/'))
si (dt=DRIVE_FIXED) o
(dt=DRIVE_REMOTE), a continuacion,
MonitorDrive(D ':/')
fin
p:=TPreCache.Create (Falso)
fin
Solo un comentario dentro y fuera de las partes como quieras.
Crear un pre-sistema de almacenamiento en caché
By Consejos Y Trucos
Crear un pre-sistema de almacenamiento en caché : Multi-millones de consejos para hacer su vida más fácil.