2008-11-25 15 views
10

Necesito crear un nuevo identificador de archivo para que cualquier operación de escritura en ese manipulador se escriba en el disco inmediatamente.Win32: ¿Escribir en el archivo sin almacenamiento en búfer?

Información adicional: El identificador heredado es heredado de un proceso hijo, por lo que necesito que cualquier resultado de ese proceso se escriba inmediatamente en el disco.

El estudio de la documentación CreateFile, la bandera FILE_FLAG_WRITE_THROUGH parecía exactamente lo que necesito:

operaciones de escritura no van a ir a través de cualquier caché intermedio, van a ir directamente en el disco.

Escribí un programa de prueba muy básico y, bueno, no está funcionando. Utilicé la bandera en CreateFile y usé WriteFile(myHandle,...) en un ciclo largo, escribiendo aproximadamente 100 MB de datos en aproximadamente 15 segundos. (Agregué algunos Sleep()).

Luego configuré un entorno de supervisión profesional que consiste en presionar continuamente 'F5' en el explorador. Los resultados: el archivo permanece en 0kB y luego salta a 100MB aproximadamente al momento en que finaliza el programa de prueba.

Lo siguiente que probé fue enjuagar manualmente el archivo después de cada escritura, con FlushFileBuffers(myHandle). Esto hace que el tamaño del archivo observado crezca agradable y estable, como se esperaba.

Mi pregunta es, entonces, ¿no debería el FILE_FLAG_WRITE_THROUGH haber hecho esto sin enjuagando manualmente el archivo? ¿Me estoy perdiendo de algo? En el programa 'mundo real', no puedo vaciar el archivo, porque no tengo ningún control sobre el proceso secundario que lo está usando.

También existe el indicador FILE_FLAG_NO_BUFFERING, que no puedo usar por la misma razón: no tengo control sobre el proceso que está usando el identificador, por lo que no puedo alinear manualmente las escrituras como lo requiere esta bandera.

EDIT: He hecho un proyecto separado específicamente para ver cómo cambia el tamaño del archivo. Utiliza la clase .NET FileSystemWatcher. También escribo menos datos, alrededor de 100kB en total.

Aquí está la salida. Mira los segundos en las marcas de tiempo.

El 'orden interna no-buffers' versión:

25.11.2008 7:03:22 PM: 10230 bytes added. 
25.11.2008 7:03:31 PM: 10240 bytes added. 
25.11.2008 7:03:31 PM: 10240 bytes added. 
25.11.2008 7:03:31 PM: 10240 bytes added. 
25.11.2008 7:03:31 PM: 10200 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10190 bytes added. 

... y el 'forzada (manual) a ras' versión (FlushFileBuffers() se llama cada ~ 2,5 segundos):

25.11.2008 7:06:10 PM: 10230 bytes added. 
25.11.2008 7:06:12 PM: 10230 bytes added. 
25.11.2008 7:06:15 PM: 10230 bytes added. 
25.11.2008 7:06:17 PM: 10230 bytes added. 
25.11.2008 7:06:19 PM: 10230 bytes added. 
25.11.2008 7:06:21 PM: 10230 bytes added. 
25.11.2008 7:06:23 PM: 10230 bytes added. 
25.11.2008 7:06:25 PM: 10230 bytes added. 
25.11.2008 7:06:27 PM: 10230 bytes added. 
25.11.2008 7:06:29 PM: 10230 bytes added. 
+0

¿Por qué cree que necesita esto? – Tim

+1

+1 para el 'profesional Explorer + F5'. Pero tengo que recordarle que la visibilidad dentro del mismo sistema operativo no significa el 'lavado/durabilidad'. Debe actuar de manera más profesional: reinicie la PC o extraiga en caliente la unidad de disco duro del sistema. No estoy seguro de que el reinicio o apagado no inicie el enjuague de la memoria caché integrada. Solo si retira la unidad físicamente o utiliza algún almacenamiento falso, puede estar seguro de que la descarga ha llegado efectivamente al dispositivo. – Val

+0

@RecognizeEvilasWaste hmm ... veamos si wor –

Respuesta

11

Me ha mordido esto también en el contexto del registro de bloqueo.

FILE_FLAG_WRITE_THROUGH sólo garantiza que los datos que está enviando es enviado al sistema de archivos antes WriteFile retornos; no garantiza que se envíe realmente al dispositivo físico. Entonces, por ejemplo, si ejecuta un ReadFile después de un WriteFile en un mango con este indicador, se le garantiza que la lectura devolverá los bytes que escribió, ya sea que obtuviera los datos del caché del sistema de archivos o del dispositivo subyacente.

Si desea garantizar que los datos se han escrito en el dispositivo, entonces necesita FILE_FLAG_NO_BUFFERING, con todo el trabajo adicional. Esas escrituras tienen que estar alineadas, por ejemplo, porque el buffer está llegando al controlador del dispositivo antes de volver.

La base de conocimiento tiene un terse but informative article en la diferencia.

En su caso, si el proceso padre va a sobrevivir el niño, entonces se puede:

  1. utilizar la API CreatePipe para crear un tubo heredable, anónimo.
  2. Use CreateFile para crear un archivo con FILE_FLAG_NO_BUFFERING conjunto.
  3. Proporcione el asa grabable de la tubería al niño como su STDOUT.
  4. En el proceso principal, lea desde el asa legible del conducto en los búferes alineados y escríbalos en el archivo.
+0

¡Buena idea sobre cómo eludir las limitaciones de FILE_FLAG_NO_BUFFERING! Tendré que ver cómo funciona el almacenamiento en búfer con CreatePipe(). ¡Gracias! –

2

Tal vez usted podría estar satisfecho con suficiente FlushFileBuffers:

Vacía los buffers de un archivo especificado y hace que todos los datos almacenados que se escriben en un archivo.

Normalmente los WriteFile y WriteFileEx funciones escribir datos en un buffer interno que el sistema operativo escribe a una tubería de disco o comunicación sobre una base regular. La función FlushFileBuffers escribe toda la información almacenada para un archivo específico en el dispositivo o tubería.

Ellos advierten que llamar ras, para vaciar las memorias intermedias mucho, es ineficiente - y es mejor simplemente deshabilitar el caché (es decir answer de Tim):

Debido al disco interacciones de almacenamiento en caché dentro de el sistema, la función FlushFileBuffers puede ser ineficiente cuando se utiliza después de cada escritura en un dispositivo de unidad de disco cuando se realizan muchas escrituras por separado. Si una aplicación realiza varias escrituras en el disco y también necesita asegurarse de que los datos críticos se escriben en medios persistentes, la aplicación debe usar E/S sin búfer en lugar de llamar con frecuencia a FlushFileBuffers. Para abrir un archivo para E/S sin búfer, llame a la función CreateFile con los indicadores FILE_FLAG_NO_BUFFERING y FILE_FLAG_WRITE_THROUGH. Esto evita que el contenido del archivo se guarde en la memoria caché y vacía los metadatos en el disco con cada escritura. Para obtener más información, consulte CreateFile.

Si no es una situación de alto rendimiento, y no se va a enjuagar con demasiada frecuencia, entonces FlushFileBuffers podría ser suficiente (y más fácil).

+0

+1 para la referencia a la bandera 'FILE_FLAG_WRITE_THROUGH'. Ya mencioné el uso de FlushFileBuffers en la pregunta, como una solución alternativa para la solución directa (no funciona), y eso es lo que estaba tratando de evitar. –

+0

Disculpe, quise decir +1 para la referencia al indicador 'FILE_FLAG_NO_BUFFERING' (aunque eso ya se ha respondido antes) –

2

El tamaño que está viendo en Explorer puede no estar del todo sincronizado con lo que el sistema de archivos conoce sobre el archivo, por lo que esta no es la mejor manera de medirlo.Da la casualidad de que FlushFileBuffers hará que el sistema de archivos actualice la información que está mirando el Explorer; cerrarlo y volver a abrir puede terminar haciendo lo mismo también.

Además de los problemas de caché de disco mencionados por otros, escribir está haciendo lo que esperabas que hiciera. Es solo que hacer un 'directorio' en el directorio puede no mostrar información actualizada.

Las respuestas que sugieren que escribir solo lo escribe "en el sistema de archivos" no son del todo correctas. Lo escribe en el caché del sistema de archivos, pero también envía los datos al disco. La escritura puede significar que se realiza una lectura posterior desde la memoria caché, pero eso no significa que hayamos salteado un paso y no lo estemos escribiendo en el disco. Lea el article's summary con mucho cuidado. Esto es un poco confuso para casi todos.

4

Esta es una vieja pregunta, pero pensé que podría agregarle un poco. En realidad, todos los que estoy aquí creo que están equivocados. Cuando escribe en una secuencia con escritura directa y sin almacenamiento temporal, escribe en el disco pero NO actualiza los metadatos asociados con el sistema de archivos (por ejemplo, qué explorador le muestra).

se puede encontrar una buena referencia en este tipo de cosas aquí http://winntfs.com/2012/11/29/windows-write-caching-part-2-an-overview-for-application-developers/

Cheers,

Greg

+1

Sin embargo, MSDN dice explícitamente todo lo contrario. Dice que los metadatos están siendo enrojecidos. De todos modos, lo que es sorprendente es para lo que se supone que se usa 'FILE_FLAG_WRITE_THROUGH'. Básicamente se trata de una escritura normal con búfer con una sola diferencia, la recuperación de páginas sucias comienza inmediatamente (a diferencia de "un tiempo no especificado más adelante"). Lo cual está bien, excepto que la KB indica que siempre se ejecuta de forma síncrona y bloquea hasta que la escritura completa ha finalizado. Lo que hace que todo el asunto no tenga sentido (sin búfer puede ejecutarse de forma asíncrona sin problemas). – Damon

0

Tal vez usted quiera considerar la asignación de memoria ese archivo. Tan pronto como escriba en la región mapeada en la memoria, el archivo se actualizará.

Win API File Mapping

Cuestiones relacionadas