FileStream question
-
I'm trying to open a file for writing in a server process. I do not want any other process to be able to write to the file while I have it open, but I do want to allow other programs to read from it. Seems simple enough. I think I've done this with CFile in MFC. I'm getting a problem trying to use the .NET FileStream class. Can any of you shed light on why I'm getting a 'File is in use' IO exception with this: try { String Nm = "c:\\testfile.txt"; //simulate the server opening the file for writing: FileStream str = File.Open(Nm, FileMode.Append, FileAccess.Write, FileShare.Read); //simulate some other process opening the file for reading: (exception thrown here) FileStream sss = File.OpenRead(Nm); } catch (IOException e) { System.Console.WriteLine(e.Message); }
-
I'm trying to open a file for writing in a server process. I do not want any other process to be able to write to the file while I have it open, but I do want to allow other programs to read from it. Seems simple enough. I think I've done this with CFile in MFC. I'm getting a problem trying to use the .NET FileStream class. Can any of you shed light on why I'm getting a 'File is in use' IO exception with this: try { String Nm = "c:\\testfile.txt"; //simulate the server opening the file for writing: FileStream str = File.Open(Nm, FileMode.Append, FileAccess.Write, FileShare.Read); //simulate some other process opening the file for reading: (exception thrown here) FileStream sss = File.OpenRead(Nm); } catch (IOException e) { System.Console.WriteLine(e.Message); }
Actually, you're aren't opening it in a different process so it's not a good test. According to the documentation for the
FileShare
enum, the file has to be opened in a different process or in a different thread. I tried your code and, of course, got the same error. I open the file in a separate thread and it works fine. Also, pay attention to myfinally
block in the code below. You should use thefinally
block in a try-catch (or forget thecatch
if you want the exception to be thrown to the caller) to make sure things are cleaned up, whether or not an exception is thrown, or evenreturn
is called (it is not executed only when the CLR is unloaded, like callingEnvironment.Exit
):// FileTest.cs
using System;
using System.IO;
using System.Threading;public class FileTest
{
public static void Main()
{
FileStream s = null;
try
{
s = File.Open("FileTest.cs", FileMode.Open,
FileAccess.ReadWrite, FileShare.Read);
new Thread(new ThreadStart(ReadFile)).Start();
}
catch (Exception e)
{
Console.Error.WriteLine(e.Message);
}
finally
{
if (s != null) s.Close();
}
}private static void ReadFile()
{
FileStream s = null;
try
{
s = File.OpenRead("FileTest.cs");
Stream os = Console.OpenStandardOutput(4096);
int read = 0;
byte[] buffer = new byte[4096];
do
{
read = s.Read(buffer, 0, buffer.Length);
os.Write(buffer, 0, read);
} while (read == buffer.Length);
}
catch (Exception e)
{
Console.Error.WriteLine(e.Me -
Actually, you're aren't opening it in a different process so it's not a good test. According to the documentation for the
FileShare
enum, the file has to be opened in a different process or in a different thread. I tried your code and, of course, got the same error. I open the file in a separate thread and it works fine. Also, pay attention to myfinally
block in the code below. You should use thefinally
block in a try-catch (or forget thecatch
if you want the exception to be thrown to the caller) to make sure things are cleaned up, whether or not an exception is thrown, or evenreturn
is called (it is not executed only when the CLR is unloaded, like callingEnvironment.Exit
):// FileTest.cs
using System;
using System.IO;
using System.Threading;public class FileTest
{
public static void Main()
{
FileStream s = null;
try
{
s = File.Open("FileTest.cs", FileMode.Open,
FileAccess.ReadWrite, FileShare.Read);
new Thread(new ThreadStart(ReadFile)).Start();
}
catch (Exception e)
{
Console.Error.WriteLine(e.Message);
}
finally
{
if (s != null) s.Close();
}
}private static void ReadFile()
{
FileStream s = null;
try
{
s = File.OpenRead("FileTest.cs");
Stream os = Console.OpenStandardOutput(4096);
int read = 0;
byte[] buffer = new byte[4096];
do
{
read = s.Read(buffer, 0, buffer.Length);
os.Write(buffer, 0, read);
} while (read == buffer.Length);
}
catch (Exception e)
{
Console.Error.WriteLine(e.MeThanks for the quick response Heath. Try adding a Thread.Sleep after you start that other thread so that the original thread still has the file open for writing. Before moving my stuff to the over simple example I submitted, I had it in different programs altogther. Any other suggestions? I tried the exact same thing with CFile and it works: try { //open for exclusive write CStdioFile file; BOOL bOpen1 = file.Open("C:\\timtest2.txt", CFile::modeWrite | CFile::modeCreate | CFile::shareDenyWrite); file.WriteString("hi"); file.Flush(); //open a reader CStdioFile f2; BOOL bOpen2 = f2.Open("c:\\timtest2.txt", CFile::modeRead | CFile::shareDenyNone); CString str; f2.ReadString(str); //try to open another writer --- this open fails CStdioFile file3; BOOL bOpen3 = file3.Open("C:\\timtest2.txt", CFile::modeWrite | CFile::modeCreate | CFile::shareDenyWrite); file3.WriteString("hi"); file3.Flush(); } catch (CFileException* pe) { pe->ReportError(); pe->Delete(); } Argh!!
-
Thanks for the quick response Heath. Try adding a Thread.Sleep after you start that other thread so that the original thread still has the file open for writing. Before moving my stuff to the over simple example I submitted, I had it in different programs altogther. Any other suggestions? I tried the exact same thing with CFile and it works: try { //open for exclusive write CStdioFile file; BOOL bOpen1 = file.Open("C:\\timtest2.txt", CFile::modeWrite | CFile::modeCreate | CFile::shareDenyWrite); file.WriteString("hi"); file.Flush(); //open a reader CStdioFile f2; BOOL bOpen2 = f2.Open("c:\\timtest2.txt", CFile::modeRead | CFile::shareDenyNone); CString str; f2.ReadString(str); //try to open another writer --- this open fails CStdioFile file3; BOOL bOpen3 = file3.Open("C:\\timtest2.txt", CFile::modeWrite | CFile::modeCreate | CFile::shareDenyWrite); file3.WriteString("hi"); file3.Flush(); } catch (CFileException* pe) { pe->ReportError(); pe->Delete(); } Argh!!
Good point - hadn't thought of that. :-O Have you tried accessing the file from two different processes? I mean, I would think the same process could access it, but maybe there is a problem related to that.
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
Good point - hadn't thought of that. :-O Have you tried accessing the file from two different processes? I mean, I would think the same process could access it, but maybe there is a problem related to that.
-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
Well I originally coded it in two processes and that's when I noticed the problem to begin with. The weird thing is that other applications (notepad) can open the files (and they come up in readonly like I would expect). I'm totally stumped on what's wrong. I really don't want to do interop for something so silly.
-
Well I originally coded it in two processes and that's when I noticed the problem to begin with. The weird thing is that other applications (notepad) can open the files (and they come up in readonly like I would expect). I'm totally stumped on what's wrong. I really don't want to do interop for something so silly.
Heath, I was able to get around this by resorting to interop. I just wrapped a call to the CreateFile function and then instantiated a FileStream object using the file handle (IntPtr) returned from CreateFile. Once I took this route everything works fine. It looks like there's a bug in the FCL when the FileStream class goes to open the files. Anyway, just an FYI. thanks again Tim