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 los flujos de transporte, como los reproductores de mp3 o aplicaciones P2P.

Este ejemplo demuestra dos cosas:
En primer lugar: ¿cómo controlar la unidad utilizando un ReadDirectoryChangesW. Esto permitirá que las ventanas de la aplicación de devolución de llamada cuando un cambio en un archivo o atributos de archivo es.
En segundo lugar, un pequeño ejemplo de un hilo que lleva a cabo el pre-cache.

Crear el stringlists antes de llamar a monitordrive o poner en marcha el hilo.
Monitor de una unidad con MonitorDrive (ruta)


type
TTrackInfo = record
H:Integer;
O:TOverLapped;
B: TFNIBuf;
D: String;
final;
TPreCache = class (TThread)
procedimiento de ejecución; override;
final;


función de pista (I: Integer) (TrackIndex): LongBool;


aplicación
var Extensiones: array [0 .. 0] = de la cadena ( '. mp3');
var Temas: Array de TTrackInfo;
FFilesOpened, FFilesHistory: TStringList;
FHasNewFileToCache: Boolean = False;
FPrecached: Integer;
FTotPrecached: Int64 = 0;
FPreCachedFile: String;
CS, css: TCriticalSection;
/ / Llamada de rutina:
procedimiento DESIERTO WINAPI () FileIOCompletionRoutine (
dwErrorCode: DWORD; / / código de finalización
dwNumberOfBytesTransfered: DWORD; / / número de bytes transferidos
lpOverlapped: Puntero / / puntero a la estructura de I / O de información
); Stdcall;
var S, M, V: String;
POverLapped: ^ TOverLapped;
i, l: Integer;
empezar
/ / Retorno
POverLapped: = lpOverLapped;

/ / If = @ superpuesto POverlapped entonces log ( 'es decir');
l: =- 1;
for i: = 0 a alto (Temas) hacer
si Tracks @ [i]. lpOverlapped O = entonces / / encontrado índice correspondiente
empezar
l: = i;
break;
final;
si l <0 then / / Ayuda, que no se encuentra!
empezar
/ / Log ( 'pista índice no encontrado');
exit;
final;

repetir
si es cierto (Temas [l]. B. Acción <> 0) then / / ignore, etc escribe repetidos
empezar
S: Temas = [l]. NombreFichero B. / / Esto funciona porque NomArch = array de WChar!
SetLength (S, Tracks [l]. FileNameLength B. div 2);
S: Temas = [l]. D + S; / / Que sea ruta de acceso completa
(case Tracks [l]. B. Acción de
FILE_ACTION_ADDED: M: = 'El archivo se añadió al directorio. »;
FILE_ACTION_REMOVED: M: = 'El archivo fue eliminado del directorio. ";
FILE_ACTION_MODIFIED: M: = 'El archivo fue modificado. Esto puede ser un cambio en el sello de tiempo o atributos ».
FILE_ACTION_RENAMED_OLD_NAME: M: = 'El archivo se ha cambiado el nombre y este es el nombre antiguo ».
FILE_ACTION_RENAMED_NEW_NAME: M: = 'El archivo se ha cambiado el nombre y este es el nuevo nombre. ";
fin;)

/ / Log ( 'Jeempie' + S + '' + M);
/ / Ver la actividad del sistema:
(/ / No! Amplia a la informática
si frmMain.lbxActiveFiles.Items.IndexOf (S + '' + M) <0 entonces
empezar
frmMain.lbxActiveFiles.Items.Add (S + '' + M);
si frmMain.lbxActiveFiles.Items.Count> 8 entonces
frmMain.lbxActiveFiles.Items.Delete (0);
final;
)
/ / V: = minúsculas (ExtractFileExt (S));
/ / For i: = baja (extensiones) a alto (extensiones) no
/ / If (extensiones [i] = V), entonces
empezar
/ / añadir a la cola
si FFilesHistory.IndexOf (S) <0 then
empezar
si FFilesHistory.Count> 2000 entonces
FFilesHistory.Clear;
FFilesHistory.Add (S);
CS.Enter; / / Tamaño del archivo getfileattr
FFilesOpened.Add (S);
FHasNewFileToCache: = True;
CS.Leave;
final;
/ / Pausa / / isfileopen
final;
final;

Temas si [l]. NextEntryOf B.> 0 then
Mover (Temas [l]. RawData B. [Temas [l]. NextEntryOf B.], Temas [l]. RawData B. [0], SizeOf (Temas [l]. B)-Tracks [l]. B. NextEntryOf);
Temas hasta [l]. NextEntryOf B. = 0;

/ / Acabamos de llamar a pista de nuevo:
Pista (l);
final;

función de pista (I: Integer) (TrackIndex): LongBool;
empezar
/ / Si
Result: = ReadDirectoryChangesW (Temas [I]. H,
@ Temas [i]. B,
DWord (SizeOf (Temas [i]. B)),
LongBool (1),
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,
@ Temas [i]. O,
@ FileIOCompletionRoutine);
final;

procedimiento MonitorDrive (Path: String);
/ / Vamos a crear un ReadDirectoryChangesW (), subtree habilitado,
/ / para supervisar todos los archivos I / O.
var i: LongBool;
j, l: Integer;
/ / Buffer contenido:

HB: DWORD;
LB: LongBool;
NrBytes: Integer;
empezar
LB: = True; / / Sí, recursivo:)))
/ / For j: = 32 DOWNTO 0 hacer
SetLength (pistas, alta (Temas) 2);
l: = alto (Temas);
Temas [l]. D: = Ruta;
empezar
HB: = SizeOf (Temas [l]. B);
Temas [l]. H
() hDir: CreateFile = (
PChar (PATH), / / puntero al nombre del archivo
$ 1, / / FILE_READ_DATA, FILE_LIST_DIRECTORY,
FILE_SHARE_READ o FILE_SHARE_DELETE, / / share modo
0, / / descriptor de seguridad
OPEN_EXISTING, / / de cómo crear
FILE_FLAG_BACKUP_SEMANTICS o FILE_FLAG_OVERLAPPED, / / atributos de archivo
0 / / archivo con los atributos para copiar
);
i: = ReadDirectoryChangesW (Temas [l]. hDir (H),
Temas @ [l]. B) (buf,
HB,
LongBool (1),
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,
Temas @ [l]. Verlapped O (),
@ FileIOCompletionRoutine);
/ / CloseHandle (hDir); Vamos a mantener el mango, ¿no?
i si a continuación,
empezar
/ / Log ( 'Track logrado' + IntToStr (Temas [l]. H))
final
otra cosa; / / log ( 'Track Error' + IntToStr (Temas [l]. hDir H ()));
final;

(MANIPULAR hDirectory, / / para manejar el directorio para ser visto
LPVOID lpBuffer, / / puntero a la amortiguación para recibir el leer los resultados
DWORD nBufferLength, / / longitud de lpBuffer
BOOL bWatchSubtree, / / bandera para el seguimiento de directorio o árbol de directorios
DWORD dwNotifyFilter, / / filtro para ver las condiciones de
LPDWORD lpBytesReturned, / / número de bytes mostrados
LPOVERLAPPED lpOverlapped, / / puntero a la estructura necesaria para superpuesto I / O
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine / / puntero a la realización de rutina
)
final;

TPreCache.Execute procedimiento;
var F: TFileStream;
s, fn: String;
empezar
SetLength (s, 262144); / / página tamaño de bloque = 256 K
F: = nil;
Terminado mientras que no hacer
empezar
dormir (2);
entonces si FHasNewFileToCache
empezar
CS.Enter;
si FFilesOpened.Count> 0 then
empezar
FN: FFilesOpened = [0];
FFilesOpened.Delete (0);
final
algo más
empezar
fn :='';
FHasNewFileToCache: = False;
final;
CS.Leave;
final;
if (fn y no <>'') (DirectoryExists (fn)) y Fileexists (fn) y luego
empezar
intentar
F: = TFileStream.Create (fn, fmOpenRead o fmShareDenyNone);
F. Tamaño de si <12 * 1024 * 1024 y luego / / tamaño máximo de 12MB
empezar
mientras que F. Posición <F. Tamaño de hacer
empezar
Leer F. (S [1], Longitud (S));
dormir (32); / / <2 MB / s
final;
inc (FTotPrecached, F. Tamaño);
FPrecached: Tamaño = F.;
FreeAndNil (F);
css.Enter;
FPrecachedFile: = fn;
css.Leave;
final;
excepto / / archivo probablemente no abierto, acaba de pasar por alto
final;
FN: ='';
intentar
si se ha asignado (F), entonces
FreeAndNil (F);
salvo fin;

final;
final;
final;


Hay una cosa importante que hacer. Con el fin de recibir el mensaje de devolución de llamada, el hilo debe estar en alertable estado.
Este ejemplo se corrió desde el hilo principal, por lo que utilizar un temporizador para que:

procedure TForm1.tmrAlertableStateTimer(Sender: TObject);
begin
SleepEx (2, True);
end;

Si no llamar a la sleepex () función, la de devolución de llamada de rutina no se llama.
Ajuste el temporizador de intervalo razonable baja (200 ms o menos).
Por supuesto, sería mejor para ejecutar esta dentro de un hilo, este hilo sólo tendrían que bucle sleepex todo el tiempo.


empezamos las cosas con esto:

procedimiento TForm1.FormCreate (Sender: TObject);
TDrives tipo = 'C' .. 'Z';
var d: TDrives;
DT: Integer;
p: TPreCache;
empezar
FFilesOpened: = TStringList.Create;
FFilesHistory: = TStringList.Create;
FFilesHistory.Sorted: = True;
CS: = TCriticalSection.Create;
CSS: = TCriticalSection.Create;
/ / unidad pistas:
D: = baja (TDrives) a alto (TDrives) hacer
empezar
dt: = GetDriveType (PChar (d + ': \'));
if (dt = DRIVE_FIXED) o
(DT = DRIVE_REMOTE) y luego
MonitorDrive (D + ': \');
final;
p: = TPreCache.Create (falso);
final;


Sólo en el comentario y las partes que lo desee.

Average rating: