c# - papel - libro fisico vs libro digital
El uso compartido de archivos de lectura/escritura de C#no parece funcionar (3)
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 :)
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.
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 usando el código que controlo completamente. Estoy usando C #, aparentemente porque proporciona una gran cantidad de la funcionalidad que quiero.
En la clase de productor, tengo este código creando un bloque de datos al azar:
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 aquí 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 el ushort [] escrito en el disco.
Pero luego agrego un hilo de consumo:
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 Newark esté rota y cause 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 de FileAccess y FileShare como se indica en la documentación de FileStream en MSDN, pero parece que no puedo hacer lo que quiero hacer (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
No he tenido tiempo de probar esto, pero creo que es posible que deba llamar al método Flush del 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 de probar esto. Me encontré con un problema con un archivo que estaba creando que era similar a esto (aunque no exacto) y el "Flush" que faltaba era el culpable.
Su consumidor debe especificar FileShare.ReadWrite.
Al intentar abrir el archivo como FileShare.Read en el consumidor, usted está diciendo "Quiero abrir el archivo y dejar que otros lo lean al mismo tiempo" ... dado que ya hay un escritor que falla la llamada, debe permitir escrituras concurrentes con el lector.