sincronizar - Esperando hasta que haya un archivo disponible para leer con Win32
se requieren permisos adicionales para acceder a los siguientes archivos mac (4)
No creo que haya una notificación para el tipo de evento que está buscando, pero como una mejora, sugeriría retrasos progresivos. De esta forma obtendrá tiempos de respuesta rápidos para cosas como arrastrar / soltar y no encerrará la CPU con un bucle cerrado si el usuario mantiene el archivo abierto durante una hora en Excel.
int delay= 10;
while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_SHARING_VIOLATION) {
Sleep (delay);
if (delay<5120) // max delay approx 5.Sec
delay*= 2;
}
else
break; // some other error occurred
}
Estoy viendo un directorio llamando a ReadDirectoryChangesW
sincrónica. Cuando hay un nuevo archivo disponible, intento acceder de inmediato con GENERIC_READ
con GENERIC_READ
y FILE_SHARE_READ
, pero esto me da ERROR_SHARING_VIOLATION
. El proceso que coloca el archivo en el directorio supervisado no termina de escribirse cuando intento leerlo.
¿Hay alguna manera de esperar de manera confiable hasta que el archivo esté disponible para su lectura? Puedo poner el método en un ciclo como el siguiente, pero espero que haya una mejor manera.
while ((hFile = CreateFile (path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_SHARING_VIOLATION)
Sleep (500);
else
break; // some other error occurred
}
if (hFile == INVALID_HANDLE_VALUE)
{
// deal with other error
return 0;
}
ReadFile (...);
No hay API de modo de usuario para las notificaciones en un archivo cerrado del que soy consciente. El ciclo que ha propuesto es probablemente la mejor manera. La única otra cosa que podría hacer sería mirar por CloseFile en un controlador de filtro ala Process Monitor, pero puaj ...
Si sabe algo sobre cómo se crea el archivo, quizás espere hasta que el archivo deje de crecer durante X segundos, o espere hasta que se elimine un archivo centinela. O siente el estado del programa que los crea.
Como dijo @Matt Davis, desafortunadamente no hay una API de modo de usuario, pero hay una solución que dependiendo de su caso de uso (he escrito la mía a continuación) puede hacer justo lo que quiera.
Lo que funcionó para mí en el pasado fue registrarme para FILE_NOTIFY_CHANGE_LAST_WRITE
lugar de FILE_NOTIFY_CHANGE_FILE_NAME
cuando ReadDirectoryChangesW
a ReadDirectoryChangesW
:
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
overlapped.hEvent = hChangeEvent;
// ...
ReadDirectoryChangesW(hSpoolPath,
eventBuffer,
EVENT_BUF_LENGTH,
FALSE,
FILE_NOTIFY_CHANGE_LAST_WRITE, // <----
NULL,
&overlapped,
NULL);
// ...
HANDLE events[2];
events[0] = hChangeEvent;
events[1] = hCancelEvent;
DWORD wRc = WaitForMultipleObjects(2, events, FALSE, DIRECTORY_WATCH_TIMEOUT);
El último tiempo de escritura se actualiza tan pronto como el proceso de propiedad cierre el controlador después de crear el archivo y escribir en él.
Mi caso de uso fue un proceso que recibió solicitudes de HTTP a través de TCP / IP y escribió el cuerpo de HTTP en un directorio, donde otro proceso lo recogió tan pronto como el proceso de recepción terminó de escribir (y, por consiguiente, cerró el manejador). El servidor http fue el único proceso que se escribió en ese directorio, por lo que pude confiar en el patrón crear-escribir-cerrar.