2008-09-24 14 views
15

Ma question est basée sur l'héritage de beaucoup de code hérité que je ne peux pas faire beaucoup. Fondamentalement, j'ai un appareil qui va produire un bloc de données. Une bibliothèque qui appelle l'appareil pour créer ce bloc de données, pour une raison que je ne comprends pas complètement et ne peut pas changer même si je le voulais, écrit ce bloc de données sur le disque.Le fichier C# en lecture/écriture Le partage de fichiers ne semble pas fonctionner

Cette écriture n'est pas instantanée mais peut durer jusqu'à 90 secondes. Pendant ce temps, l'utilisateur veut obtenir une vue partielle des données qui sont produites, donc je veux avoir un thread consommateur qui lit les données que l'autre bibliothèque écrit sur le disque. Avant que je ne touche même ce code hérité, je veux imiter le problème en utilisant le code que je contrôle entièrement. J'utilise C#, ostensiblement parce qu'il fournit beaucoup de fonctionnalités que je veux.

Dans la classe de producteur, j'ai ce code créer un bloc aléatoire de données:

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(); 

Jusqu'à présent, si bon. Ce code fonctionne. La version actuelle (en utilisant FileStream et BinaryWriter) semble être équivalente (bien que plus lente, à cause de la copie) à l'utilisation de File.Open avec les mêmes options et un BinaryFormatter sur l'ushort [] étant écrit sur le disque.

Mais j'ajouter un fil à la consommation:

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); 

Maintenant, il est possible que la déclaration de theNewArray est rompue, et provoquera une sorte de débordement de lecture. Cependant, ce code ne va jamais aussi loin, car il interrompt toujours toujours l'ouverture du nouveau FileStream avec une exception System.IO.IOException qui indique qu'un autre processus a ouvert le fichier. Je définis les énumérations FileAccess et FileShare comme indiqué dans la documentation FileStream sur MSDN, mais il semble que je ne peux pas faire ce que je veux faire (écrire dans un thread, lire dans un autre thread). Je me rends compte que cette application est un peu peu orthodoxe, mais quand je reçois le périphérique réel impliqué, je vais devoir faire la même chose, mais en utilisant MFC.

Dans tous les cas, qu'est-ce que j'oublie? Est ce que je veux faire possible, puisque c'est spécifié comme possible dans la documentation?

Merci! MMR

Répondre

3

Je n'ai pas eu le temps de tester cela, mais je pense que vous devrez peut-être appeler la méthode de rinçage 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(); 

Désolé, je ne l'ai pas eu le temps de tester. J'ai rencontré un problème avec un fichier que je créais qui était similaire à cela (mais pas exact) et un "Flush" manquant était le coupable.

34

Votre client doit spécifier FileShare.ReadWrite. En essayant d'ouvrir le fichier en tant que FileShare.Read dans le consommateur, vous dites "Je veux ouvrir le fichier et laisser les autres le lire en même temps" ... puisqu'il y a déjà un écrivain qui appelle échoue, vous devez autoriser les écritures simultanées avec le lecteur.

2

Je crois que Chuck a raison, mais gardez à l'esprit La seule raison pour laquelle cela fonctionne est parce que le système de fichiers est assez intelligent pour sérialiser vos lectures/écritures; C'est pas une bonne chose :)

+0

Assez bien - mais rappelez-vous, je dois le faire avec du code hérité qui n'a presque certainement aucun verrou de fichier (et les personnes qui ont écrit ce code vous regarderait comme si vous étiez folle de suggérer qu'il y a de telles choses). Donc, si ça casse à cause de ça, je ferais mieux d'imiter ces pauses. – mmr

Questions connexes