2008-09-24 5 views
15

Mi pregunta se basa en heredar una gran cantidad de código heredado que no puedo hacer mucho al respecto. Básicamente, tengo un dispositivo que producirá un bloque de datos. Una biblioteca que llamará al dispositivo para crear ese bloque de datos, por alguna razón que no entiendo completamente y no puede cambiar incluso si quisiera, escribe ese bloque de datos en el disco.El uso compartido de archivos de lectura/escritura de C# no parece funcionar

Esta escritura no es instantánea, pero puede tomar hasta 90 segundos. En ese momento, el usuario desea obtener una vista parcial de los datos que se están produciendo, por lo que quiero tener un hilo de consumidor que lea los datos que la otra biblioteca está escribiendo en el disco.

Antes de siquiera tocar este código heredado, quiero imitar el problema utilizando el código que controlo completamente. Estoy usando C#, aparentemente porque proporciona una gran cantidad de la funcionalidad que quiero.

En la clase productora, tengo este código la creación de un bloque al azar de los datos:

FileStream theFS = new FileStream(this.ScannerRawFileName, 
    FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read); 
//note that I need to be able to read this elsewhere... 
BinaryWriter theBinaryWriter = new BinaryWriter(theFS); 
int y, x; 
for (y = 0; y < imheight; y++){ 
    ushort[] theData= new ushort[imwidth]; 
    for(x = 0; x < imwidth;x++){ 
     theData[x] = (ushort)(2*y+4*x); 
    } 
    byte[] theNewArray = new byte[imwidth * 2]; 
    Buffer.BlockCopy(theImage, 0, theNewArray, 0, imwidth * 2); 
    theBinaryWriter.Write(theNewArray); 
    Thread.Sleep(mScanThreadWait); //sleep for 50 milliseconds 
    Progress = (float)(y-1 >= 0 ? y-1 : 0)/(float)imheight; 
} 
theFS.Close(); 

Hasta ahora, todo bien. Este código funciona La versión actual (usando FileStream y BinaryWriter) parece ser equivalente (aunque más lenta, debido a la copia) a usar File.Open con las mismas opciones y un BinaryFormatter en ushort [] escrito en el disco.

Pero luego añadir un hilo consumidor:

FileStream theFS; 
if (!File.Exists(theFileName)) { 
    //do error handling 
    return; 
} 
else { 
    theFS = new FileStream(theFileName, FileMode.Open, 
     FileAccess.Read, FileShare.Read); 
      //very relaxed file opening 
} 
BinaryReader theReader = new BinaryReader(theFS); 

//gotta do this copying in order to handle byte array swaps 
//frustrating, but true. 
byte[] theNewArray = theReader.ReadBytes(
    (int)(imheight * imwidth * inBase.Progress) * 2); 
ushort[] theData = new ushort[((int)(theNewArray.Length/2))]; 
Buffer.BlockCopy(theNewArray, 0, theData, 0, theNewArray.Length); 

Ahora, es posible que la declaración de theNewArray se rompe, y causará algún tipo de desbordamiento de lectura. Sin embargo, este código nunca llega tan lejos, porque siempre siempre se rompe al tratar de abrir el nuevo FileStream con una excepción System.IO.IOException que indica que otro proceso ha abierto el archivo.

Estoy configurando las enumeraciones FileAccess y FileShare como se indica en la documentación de FileStream en MSDN, pero parece que simplemente no puedo hacer lo que quiero (es decir, escribir en un hilo, leer en otro). Me doy cuenta de que esta aplicación es poco ortodoxa, pero cuando involucro el dispositivo real, tendré que hacer lo mismo, pero usando MFC.

En cualquier caso, ¿qué estoy olvidando? ¿Es lo que quiero hacer posible, ya que está especificado como posible en la documentación?

Gracias! MMR

Respuesta

3

no he tenido tiempo para probar esto, pero creo que puede que tenga que llamar al método Flush de la BinaryWriter

FileStream theFS = new FileStream(this.ScannerRawFileName, 
    FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read); 
//note that I need to be able to read this elsewhere... 
BinaryWriter theBinaryWriter = new BinaryWriter(theFS); 
int y, x; 
for (y = 0; y < imheight; y++){ 
    ushort[] theData= new ushort[imwidth]; 
    for(x = 0; x < imwidth;x++){ 
     theData[x] = (ushort)(2*y+4*x); 
    } 
    byte[] theNewArray = new byte[imwidth * 2]; 
    Buffer.BlockCopy(theImage, 0, theNewArray, 0, imwidth * 2); 
    theBinaryWriter.Write(theNewArray); 
    Thread.Sleep(mScanThreadWait); //sleep for 50 milliseconds 
    Progress = (float)(y-1 >= 0 ? y-1 : 0)/(float)imheight; 
    theBinaryWriter.Flush(); 
} 
theFS.Close(); 

Lo siento, no he tenido tiempo para probar esto. Me encontré con un problema con un archivo que estaba creando que era similar a este (aunque no exacto) y el "Flush" que faltaba era el culpable.

34

Su consumidor debe especificar FileShare.ReadWrite.

Al tratar de abrir el archivo como FileShare.Lea en el consumidor que está diciendo "Quiero abrir el archivo y dejar que otros lo lean al mismo tiempo" ... ya que hay ya un escritor que llama falla, debe permitir escrituras concurrentes con el lector.

2

Creo que Chuck tiene razón, pero tenga en cuenta La única razón por la que esto funciona es porque el sistema de archivos es lo suficientemente inteligente como para serializar sus lecturas/escrituras; no tiene ningún bloqueo en el recurso de archivo, eso no es bueno :)

+0

Lo suficientemente justo, pero recuerde, tengo que hacer esto con un código heredado que casi con seguridad no tiene bloqueos de archivos (y las personas que escribieron ese código te miraría como si estuvieras loco por sugerir que hay tales cosas). Entonces, si se rompe debido a eso, será mejor que imite esos descansos. – mmr

Cuestiones relacionadas