C # file read / write filehare не работает - PullRequest
15 голосов
/ 24 сентября 2008

Мой вопрос основан на наследовании большого количества унаследованного кода, с которым я мало что могу сделать. По сути, у меня есть устройство, которое будет производить блок данных. Библиотека, которая вызовет устройство для создания этого блока данных, по какой-то причине я не совсем понимаю и не могу изменить, даже если бы захотела, записывает этот блок данных на диск.

Эта запись не мгновенная, но может занять до 90 секунд. В это время пользователь хочет получить частичное представление создаваемых данных, поэтому я хочу иметь потребительский поток, который считывает данные, которые другая библиотека записывает на диск.

Прежде чем я коснусь этого унаследованного кода, я хочу имитировать проблему, используя код, который я полностью контролирую. Я использую C #, якобы потому, что он предоставляет много функций, которые я хочу.

В классе производителя у меня есть этот код, создающий случайный блок данных:

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

Пока все хорошо. Этот код работает. Текущая версия (с использованием FileStream и BinaryWriter), по-видимому, эквивалентна (хотя и медленнее, из-за копирования) использованию File.Open с теми же параметрами и BinaryFormatter для ushort [], записываемого на диск.

Но тогда я добавлю потребительскую ветку:

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

Теперь, возможно, что объявление NewArray нарушено и приведет к некоторому переполнению чтения. Однако этот код никогда не заходит так далеко, потому что он всегда всегда прерывается при попытке открыть новый FileStream с исключением System.IO.IOException, в котором говорится, что файл открыл другой процесс.

Я устанавливаю перечисления FileAccess и FileShare, как указано в документации FileStream на MSDN, но, похоже, я просто не могу делать то, что хочу (т.е. писать в одном потоке, читать в другом). Я понимаю, что это приложение немного неортодоксально, но когда я включу реальное устройство, мне придется делать то же самое, но с использованием MFC.

В любом случае, что я забыл? Возможно ли то, что я хочу сделать, так как это указано в документации?

Спасибо! MMR

Ответы [ 3 ]

37 голосов
/ 24 сентября 2008

Ваш потребитель должен указать FileShare.ReadWrite.

Пытаясь открыть файл как FileShare.Read в потребителе, вы говорите: «Я хочу открыть файл и позволить другим читать его одновременно» ... так как уже a Писатель, вызывающий ошибку, вы должны разрешить одновременную запись с читателем.

3 голосов
/ 24 сентября 2008

Я считаю, что Чак прав, но имейте в виду, единственная причина, по которой это работает вообще, заключается в том, что файловая система достаточно умна для сериализации ваших операций чтения / записи; у вас нет блокировки файлового ресурса - это нехорошо:)

3 голосов
/ 24 сентября 2008

У меня не было времени проверить это, но я думаю, что вам может понадобиться вызвать метод Flush для 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();

Извините, у меня не было времени проверить это. Я столкнулся с проблемой с файлом, который я создавал, который был похож на это (хотя и не точный), и пропавший "Flush" был виновником.

...