2010-06-29 13 views
7

Tengo un programa que abre un archivo binario grande, le agrega una pequeña cantidad de datos y cierra el archivo.¿Cómo evito las E/S excesivas de archivos de red al agregarlas a un archivo grande con .NET?

FileStream fs = File.Open("\\\\s1\\temp\\test.tmp", FileMode.Append, FileAccess.Write, FileShare.None); 
fs.Write(data, 0, data.Length); 
fs.Close(); 

Si test.tmp es de 5 MB antes de que este programa se ejecuta y la matriz de datos es de 100 bytes, este programa causará más de 5 MB de datos a transmitir a través de la red. Hubiera esperado que los datos que ya estaban en el archivo no se transmitieran a través de la red ya que no los leo ni los escribo. ¿Hay alguna forma de evitar este comportamiento? Esto hace que sea terriblemente lento para anexar archivos muy grandes.

+1

¿Ha probado el método FileStream.Seek en su lugar? – ChrisW

+2

¿Hay un escáner antivirus activo que realice una comprobación de acceso? –

+0

Puede agregar cierta información sobre su objetivo final (es decir, un sistema de registro o herramienta de informe de datos), ya que los usuarios pueden tener algunas sugerencias que quizás no hayan considerado. –

Respuesta

2

0xA3 proporcionó la respuesta en un comentario anterior. El bajo rendimiento se debió a un escaneo de virus en el acceso. Cada vez que mi programa abría el archivo, el escáner de virus leía todo el contenido del archivo para detectar virus, aunque mi programa no leyó ninguno de los contenidos existentes. Al deshabilitar el escaneo de virus en el acceso se eliminó la excesiva E/S de red y el bajo rendimiento.

Gracias a todos por sus sugerencias.

0

Puede almacenar en caché sus datos en un búfer local y periódicamente (con mucha menos frecuencia que ahora) anexar al archivo grande. Esto ahorraría un montón de transferencias de red, pero ... Esto también aumentaría el riesgo de perder ese caché (y sus datos) en caso de que su aplicación falle.

El registro (si eso es lo que es) de este tipo a menudo se almacena en un db. El uso de un RDBMS decente le permitiría publicar esos 100 bytes de datos con mucha frecuencia con una sobrecarga mínima. La advertencia es el mantenimiento de un RDBMS.

-3

he hecho un poco buscando en Google y estaba buscando más en la forma de leer archivos excesivamente grandes de forma rápida y encontramos este enlace http://www.4guysfromrolla.com/webtech/010401-1.shtml

La parte más interesante no habría la parte de lectura de bytes: Además de la ReadAll más comúnmente usado y Los métodos ReadLine, el objeto TextStream también admite un método Read (n), donde n es el número de bytes en el archivo/textstream en cuestión. Al crear una instancia de un objeto adicional (un objeto de archivo), podemos obtener el tamaño del archivo que se leerá y luego usar el método de Lectura (n) para recorrer nuestro archivo. Como resultado, el método de "leer bytes" es extremadamente rápido en comparación:

const ForReading = 1 
const TristateFalse = 0 
dim strSearchThis 
dim objFS 
dim objFile 
dim objTS 
set objFS = Server.CreateObject("Scripting.FileSystemObject") 
set objFile = objFS.GetFile(Server.MapPath("myfile.txt")) 
set objTS = objFile.OpenAsTextStream(ForReading, TristateFalse) 

strSearchThis = objTS.Read(objFile.Size) 

if instr(strSearchThis, "keyword") > 0 then 
Response.Write "Found it!" 
end if 

Este método podría ser utilizado por usted para ir al final del archivo y añadiendo manualmente en lugar de cargar todo el archivo en el modo de agregar con una secuencia de archivos.

+0

-1: ¿Notaste que este era un artículo de 2001, para VBScript, no para .NET? –

0

Si tiene acceso al sistema o quizás un administrador amigable para la máquina que realmente aloja el archivo, puede crear un pequeño programa de escucha que se encuentre en el otro extremo.

Usted hace una llamada al pasar solo los datos que se escriben y lo hace escribir localmente, evitando el tráfico de red adicional.

0

El objeto File en .NET tiene bastantes métodos estáticos para manejar este tipo de cosas. Sugeriría probar:

File file = File.AppendAllText("FilePath", "What to append", Encoding.UTF8); 

Cuando se refleja este método resulta que se trata de utilizar:

using (StreamWriter writer = new StreamWriter(path, true, encoding)) 
{ 
    writer.Write(contents); 
} 

Este método StreamWriter le debería permitir Simplemente añada algo al final (al menos esta es la método que he visto utilizado en cada instancia de registro que he encontrado hasta ahora).

+0

¿Has probado el rendimiento de esto? –

+1

AppendAllText devuelve void, not File :) http://msdn.microsoft.com/en-us/library/system.io.file.appendalltext.aspx –

1

He encontrado this on MSDN (CreateFile se llama internamente):

Cuando una aplicación crea un archivo a través de una red, es mejor utilizar GENERIC_READ | GENERIC_WRITE para dwDesiredAccess que usar GENERIC_WRITE solo. El código resultante es más rápido, porque el redireccionador puede usar el administrador de caché y enviar menos SMB con más datos.Esta combinación también evita un problema por el cual escribir en un archivo a través de una red puede ocasionalmente devolver ERROR_ACCESS_DENIED.

El uso del reflector, FileAccess mapas a dwDesiredAccess, por lo que parece sugerir el uso de FileAccess.ReadWrite en lugar de sólo FileAccess.Write.

tengo ni idea de si esto ayuda :)

0

Escribir los datos en archivos separados, y luego unirse a ellos (hacerlo en la máquina de alojamiento si es posible) sólo cuando sea necesario.

+0

Lo digo porque la "respuesta larga" es realmente larga , http://en.wikipedia.org/wiki/Server_Message_Block y no hay forma de evitarlo. Es una limitación del sistema de intercambio de archivos de Windows. – rwong

Cuestiones relacionadas