I have a windows service that writes out log file entries to an XML log file. I maintain a handle to the log file while the service is operational, and close, flush and dispose of it when the service is stopped. The file write operations are by the service only, and I have the filestream open in FileAccess.ReadWrite while sharing is set to FileShare.Read. I would like to be able to open and view this file with an XmlRead() call by another application, but I get an error stating the file is being used by another process. I had read another post on this and was under the impression this was possible: Other Thread.
The writer in use is flushed, closed, and disposed of, and each write the filestream is flushed. Is this just not possible in .Net, or have I perhaps done something wrong? A cutdown version of the code follows:
if (_logFS == null)
_logFS = new FileStream(_fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
if (!initFile)
{
_logFS.Seek(-13, SeekOrigin.End);
}
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
using (XmlWriter writer = XmlWriter.Create(_logFS, settings))
{
if (initFile)
{
writer.WriteRaw("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n");
writer.WriteStartElement("Entries", "http://www.abcdefg.com);
}
writer.WriteStartElement("Exception");
// write out some stuff here.
writer.WriteEndElement();
writer.Flush();
writer.Close();
}
_logFS.Flush();
The file opening code is now as follows:
_LogDS = new XmlLogFile();
using (FileStream logFS = new FileStream(_fileName, FileMode.Open, FileAccess.Read)
{
_LogDS.ReadXml(logFS);
}
You also need to close the FileStream. At a minimum, you need to close it when your service exits, or when the FileStream would go out of the application's scope.
You should be able to open it as ReadOnly from another application either way, but you have to specify that, it's not a default.
In your service you need to enable the file sharing:
FileStream fs = new FileStream("path", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
And in your reader application:
FileStream fs = new FileStream("path", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
Without the FileShare.Read, all requests to open the file for reading fail. Any other application requesting to open the file for writing will still fail, for write-enabled sharing you'd use FileShare.ReadWrite. The default option for FileShare is None.
Related
why in fs2 object throw error ?? i already have written a FileShare.ReadWrite in fs object
FileStream fs = new FileStream("hello.txt",FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.ReadWrite);
mama();
Console.ReadKey();
}
static void mama()
{
FileStream fs2 = new FileStream("hello.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
fs2.Read(new byte[3], 0, 3);
}
can any one tell me why this error ?
error = The process cannot access the file 'C:\Users\iP\documents\visual studio 2015\Projects\ConsoleApplication32\ConsoleApplication32\bin\Debug\hello.txt' because it is being used by another process.
You're getting that error because you're passing FileShare.None to the second call. If you change that to FileShare.ReadWrite to match the first call, you won't have that problem.
The reason for this is because the FileStream constructor calls CreateFileW underneath, and if you take a look at the documentation for that function, it states:
You cannot request a sharing mode that conflicts with the access mode
that is specified in an existing request that has an open handle.
CreateFile would fail and the GetLastError function would return
ERROR_SHARING_VIOLATION.
You already have an open handle from the first request using FileAccess.ReadWrite as the access mode, which conflicts with FileShare.None in the second call.
Because your code never closes the file and has an open handle to it
If you can, always use the using statement, it will flush and close the file
using(var fs = new FileStream(...))
{
// do stuff here
} // this is where the file gets flushed and closed
If 2 methods are working on the same file, pass the FileStream in
static void mama(FileStream fs )
{
fs .Read(new byte[3], 0, 3);
}
I need advice whether or not using a lock (ReaderWriterLockSlim).
A user interacts on screen, and data can be saved into a file :
XmlSerializer xmlserializer = new XmlSerializer(typeof(MyFile));
FileStream fs = new FileStream(fileName, FileMode.Create,FileAccess.ReadWrite);
xmlserializer.Serialize(fs, this);
fs.Close();
In parallel, I have a timer (thus same thread, System.Windows.Forms.Timer), which checks this same file size and sends it to a server if modified.
I'll use File.ReadAllBytes as this is a rather small file.
Should I use a lock since writing filestream takes some time ?
I wonder if the timer can cause problem (I don't have a clear understanding if it preempts).
Thanks for any advice.
In WinForms an event never interrupts a running method running in the same thread (i.e. in the UI thread). Any timer_Tick (from System.Windows.Forms.Timer) will be delayed until the serializing code is finished.
(I assume that you are not using async calls.)
You can read the file size directly from the FileStream before closing it.
var xmlserializer = new XmlSerializer(typeof(MyFile));
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite)) {
xmlserializer.Serialize(fs, this);
Console.WriteLine(fs.Length); // <=========
} // The using-statement automatically closes fs
If you need to know whether the file changed in another routine, why don't you just use a flag?
public static bool FileHasChanged { get; set; }
...
var xmlserializer = new XmlSerializer(typeof(MyFile));
using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite)) {
xmlserializer.Serialize(fs, this);
}
FileHasChanged = true;
In the other routine (timer_Tick I think):
if (MyFile.FileHasChanged) {
//TODO: Send file to server.
MyFile.FileHasChanged = false;
}
Since everything is running in the same thread, no locking is required.
Another question is whether you really need a file or whether you could just write to a MemoryStream and then use this memory stream to send the data to the server. If you still need the file, you could write to it using the same memory stream and serialize only once. The memory stream would replace the Boolean flag for the communication between the two routines. After sent to the server, the memory stream would be set to null after calling Dispose() (instead of MyFile.FileHasChanged = false;).
That would be more in the sense of Eric Lippert's comments.
I used the following code to write on *.txt file, but nothing happens. Even, there is no exception.
FileStream fs = new FileStream(#"D:\file.txt",FileMode.OpenOrCreate,FileAccess.Write,FileShare.None); //Creating a stream with certain features to a file
StreamWriter writer = new StreamWriter(fs); //Use the fs to write
// writer.WriteLine(Text.Text); none of the following methods works
writer.Write("aaaaaaaaaaaa");
fs.Close();
Thanks
Try to enclose it in a using block like this:
using ( FileStream fs = new FileStream(#"D:\file.txt",FileMode.OpenOrCreate,FileAccess.Write,FileShare.None))
using (StreamWriter fw = new StreamWriter(fs))
{
fw.Write("aaaaaaaaaaaa");
}
A StreamWriter buffers data before writing it to the underlying stream. You need to flushes the buffer by disposing the StreamWriter
public void WriteListToFile(Lists lists, string filePath)
{
FileStream outFile;
BinaryFormatter bFormatter = new BinaryFormatter();
// Ppen file for output
outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write);
// Output object to file via serialization
bFormatter.Serialize(outFile, lists);
// Close file
outFile.Close();
}
Whenever I try to output data to a .dat file I get an error saying that the file is already in use. How do I fix this?
EDT: Turns out it wouldn't let me save to an empty file so I create a new void to input data and then it allowed me to save over the file.
The immediate answer is "release the lock that some process has on the file".
Something already has the file open. You need to look at code and other processes that may access that file to find the root cause.
I note that you're not making use of using statements. If an exception were thrown in the block of code you show, outputFile.Close() would never execute, leaving the file open.
Try rewriting your code (and any similar code) like
public void WriteListToFile(Lists lists, string filePath)
{
BinaryFormatter bFormatter = new BinaryFormatter();
// Ppen file for output
using (FileStream outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
// Output object to file via serialization
bFormatter.Serialize(outFile, lists);
// Close file
outFile.Close();
}
}
The using keyword is a syntactic shortcut for
var outFile = new FileStream(filePath, FileMode.Create, FileAccess.Write);
try
{
// Do stuff with outFile
}
finally
{
outFile.Dispose();
}
and ensures that outFile is disposed (which also closes it) whether or not an exception is thrown.
you can try this:
outFile.Dispose();
I am still newbie to C# and I'm making a test program that writes the DateTime.Now every second. I tried using this and it worked:
StreamWriter sw = new StreamWriter("D:\Hello.txt", true);
sw.WriteLine(DateTime.Now);
sw.Close();
However, when I tried including a FileStream, it didn't work. What seems to be the problem? Here's my code:
FileStream fs = new FileStream(#"D:\Hello.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(DateTime.Now);
sw.Close();
fs.Close();
Note: I am using a timer, it executes the code every second..
Update:
I tried placing the code(the one that has the filestream) inside a button (w/out timer). Whenever I clicked the button, it just replaces the line in the textfile.. This is a code that appends a text to the textfile:
StreamWriter sw = new StreamWriter("D:\Hello.txt", true);
How will I do it in a filestream? I cannot use FileMode.Append in FileStream because it required=s the FileAccess to be write-only.
Since you are executing the code every second then its not a good idea to create FileStream and StreamWriter object everytime, because sometimes the file will remain under lock condition and the filestream will miss to acquire the handle.
As you are writing to single file its good to initialize a FileStream and subsequent StreamWriter in the constructor while leaving the refrence to them in class scope;then calling it every second on a thread for sw.WriteLine(DateTime.Now); should help.
And further never miss try catch in a filestream. They help a lot to locate the discrepancies.
May be try to use File?
File.AppendAllText(#"D:\Hello.txt", DateTime.Now.ToString());
or
File.WriteAllText(#"D:\Hello.txt", DateTime.Now.ToString());
to overwrite
You should use something like this because it works fine for me. If it does not work for you, you have to add more details
using (var fs = new FileStream("path", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
fs.Seek(0, SeekOrigin.End);
using (StreamWriter sw = new StreamWriter(fs) { AutoFlush = true })
{
sw.WriteLine("my text");
}
}
But remember I would not create it every second. Why don t you store a Streamwriter object as field when you call Timer.Start?
So you would not have to create it every second. (rememer to dispose it when you stop the timer)
Should work:
FileStream fs = new FileStream(#"D:\Hello.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(DateTime.Now);
sw.Flush();
sw.Close();
fs.Close();
I already solved it.. :) I just have to use FileMode.Append, FileAccess.Write as an argument in the filestream. Reason for not doing FileMode.Append earlier is because it needs FileAccess to be Write only. I thought switching the FileAcess to Write only will prevent the user from reading the file. So stupid of me.. This is my code:
private void timer1_Tick(object sender, EventArgs e)
{
FileStream fs = new FileStream(#"D:\Hello.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(DateTime.Now);
lbTimer.Items.Add(DateTime.Now);
sw.Close();
fs.Close();
}
Last question, what is setting the FileAccess to Write only for when you can still read it?
Try calling StreamWriter.Flush() before StreamWriter.Close().
You might wanna look here
How to: Write to a Text File (C# Programming Guide)
http://msdn.microsoft.com/en-us/library/8bh11f1k.aspx