1) I have created a program that has opened a twitter stream and writes everything to a file.
FileStream fs = new FileStream(#"\Database\twitterstream.txt", FileMode.Create);
TextWriter tmp = Console.Out;
StreamWriter sw = new StreamWriter(fs);
Console.SetOut(sw);
2) I have another program that I want to read said text file.
using (StreamReader sr = File.OpenText("C:\\Database\\twitterstream.txt"))
{
input = sr.ReadLine();
}
Because I want it to be in real time I am trying to have one program write, while at the same time the other program reads, however obviously it is throwing
"The process cannot access the file
'C:\Database\twitterstream.txt' because it is being used by another
process" back at me.
Is what I am trying to do possible? If so, how do I go about doing it?
Add a couple parameters to you FileStream constructor:
FileStream fs = new FileStream(
#"\Database\twitterstream.txt",
FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
See FileStream on MSDN
Related
Documentation says FileMode.OpenOrCreate "specifies that the operating system should open a file if it exists; otherwise, a new file should be created", which sounds like it will open the file and write to it. Instead, the file seems to be overwritten.
How do I add to the file, rather than overwrite it?
class Logger : IDisposable
{
private FileStream fs;
private StreamWriter sw;
public Logger()
{
// INTENT (but not reality): Will create file if one does not exist, otherwise opens existing file
fs = new FileStream("log.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
sw = new StreamWriter(fs, Encoding.UTF8);
}
public void Log(string message)
{
sw.WriteLine(message);
sw.Flush();
fs.Flush();
}
public void Dispose()
{
sw?.Dispose();
fs?.Dispose();
}
}
The documentation is correct – but note that open and append are not synonymous.
FileMode.OpenOrCreate is not causing the FileStream constructor to delete the preexisting file wholesale; rather, it causes the stream to start at the beginning of the file. What you are observing is the file contents being overwritten by the StreamWriter, not the FileStream constructor replacing the file immediately.
You have to move the stream position to the end of the file to add text at the end. To do this, you could move the position with FileStream.Seek() or change the FileMode to FileMode.Append.
FileMode.Append is likely more idiomatic but also requires making the FileAccess write-only, rather than read-write. Otherwise, an exception is thrown upon calling the contructor.
Option 1 (FileMode.OpenOrCreate, FileAccess.ReadWrite)
public Logger()
{
// Will create file if one does not exist, otherwise opens existing file
fs = new FileStream("log.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
// Set stream position to end-of-file
fs.Seek(0, SeekOrigin.End);
sw = new StreamWriter(fs, Encoding.UTF8);
}
Option 2 (FileMode.Append, FileAccess.Write)
public Logger()
{
// Will create file if one does not exist, otherwise appends to existing file
fs = new FileStream("log.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
sw = new StreamWriter(fs, Encoding.UTF8);
}
I'm writing to a log file with this stream :
using(FileStream fs = new FileStream(Path.Combine(Folder, LogFile),
FileMode.OpenOrCreate,
FileAccess.Write,
FileShare.ReadWrite))
{
using(System.IO.StreamWriter file = new System.IO.StreamWriter(fs))
{
while(!token.IsCancellationRequested)
{
file.WriteLine("bla bla bla");
}
}
}
The purpose of this code sample is to write into a log file. What I would like to be able to do is to read it with Excel or notepad while this code is running. I can open the file externally with Excel, but the file is empty until I stop the program.
Furthermore, when I try to open it with Excel, I am said that the file is locked for editing although I declared the stream with the FileShare.ReadWrite.
when writing files in a while loop and you want to see the data real time for example in NotePad you need to immediately Flush the data in your case a simple
file.Flush();
inside of the while loop after the file.Write will work
using(FileStream fs = new FileStream(Path.Combine(Folder, LogFile),
FileMode.OpenOrCreate,
FileAccess.Write,
FileShare.ReadWrite))
{
using(System.IO.StreamWriter file = new System.IO.StreamWriter(fs))
{
while(!token.IsCancellationRequested)
{
file.WriteLine("bla bla bla");
file.Flush();
}
}
}
I am getting this error: The process cannot access the file (...) because it is being used by another process.
I have tried to use
File.WriteAllText;
StreamWriter sw = new StreamWriter(myfilepath);
sw.Write(mystring);
sw.Close();
sw.Dispose();
;
using (FileStream fstr = File.Create(myfilepath))
{
StreamWriter sw = new StreamWriter(myfilepath);
sw.Write(mystring);
sw.Close();
sw.Dispose();
fstr.Close();
}
All I am trying to do is to access a file, write on it, then close it. I might be making a silly mistake but I would like to understand what I am doing wrong and why. How to make sure that the file is closed and not to cause this error again.
Helped by the answers so far I did this:
using (FileStream fstr = File.Open(myfilepath,FileMode.OpenOrCreate,FileAccess.ReadWrite))
{
StreamWriter sw = new StreamWriter(fstr);
sw.Write(mystring);
sw.Close();
}
It seems to be better because it seems to close/stop the process of my file if I try to access another file on the second time I access the page. But if I try to access the same file on a second time, it gives me the error again.
Why not just use:
System.IO.File.WriteAllText(myfilepath, mystring");
That should not lock your file.
Internally WriteAllText uses FileShare.Read and releases that lock as soon as it is done writing.
"because it is being used by another process" that's the clue. Do you by chance have the file open in Notepad or something?
You may need to set the sharing mode when you open the file to allow readers, and ask only for the permission you need (write access).
http://msdn.microsoft.com/en-us/library/5h0z48dh.aspx
I would like to thank everyone for the help.
In fact, apart from this code I found out that I had a stremReader still opened somewhere else after the code above. At the end I changed the code I had before for this:
using (FileStream fstr = File.Open(myfile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
StreamWriter sw = new StreamWriter(fstr);
sw.Write(mystring);
sw.Flush();
sw.Dispose();
}
and on my StreamReader I did this:
StreamReader sr = new StreamReader(myfile);
string sometext = sr.ReadToEnd();
sr.Dispose();
I could also use this:
File.ReadAllText(myfile);
If there is something that I could have done in a better way please tell me.
Thank you very much.
Try this
FileStream fs = new FileStream(myfilepath, FileMode.Create, FileAccess.Write);
byte[] bt = System.Text.Encoding.ASCII.GetBytes(mystring);
fs.Write(bt, 0, bt.Length);
fs.Close();
for an application that uses a File as some sort of global storage for device reservations in a firm I need a way to read and write to a file (or lock a file, read from it, write to it, and unlock it). A little code snippet will shot what I mean:
FileStream in = new FileStream("storage.bin", FileMode.Open);
//read the file
in.Close();
//!!!!!
//here is the critical section since between reading and writing, there shouldnt
//be a way for another process to access and lock the file, but there is the chance
//because the in stream is closed
//!!!!!
FileStream out = new FileStream("storage.bin", FileMode.Create);
//write data to file
out.Close();
this should get something like this
LockFile("storage.bin");
//read from it...
//OVERwrite it....
UnlockFile("storage.bin");
the method should be absolute safe, since the program should run on 2000 devices at the same time
Simply holding a FileStream open with exclusive (not shared) access will prevent other processes from accessing the file. This is the default when opening a file for read/write access.
You can 'overwrite' a file that you currently hold open by truncating it.
So:
using (var file = File.Open("storage.bin", FileMode.Open))
{
// read from the file
file.SetLength(0); // truncate the file
// write to the file
}
the method should be absolute safe, since the program should run on 2000 devices at the same time
Depending on how often you're writing to the file, this could become a chokepoint. You probably want to test this to see how scalable it is.
In addition, if one of the processes tries to operate on the file at the same time as another one, an IOException will be thrown. There isn't really a way to 'wait' on a file, so you probably want to coordinate file access in a more orderly fashion.
You need a single stream, opened for both reading and writing.
FileStream fileStream = new FileStream(
#"c:\words.txt", FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None);
Alternatively you can also try
static void Main(string[] args)
{
var text = File.ReadAllText(#"C:\words.txt");
File.WriteAllText(#"C:\words.txt", text + "DERP");
}
As per http://msdn.microsoft.com/en-us/library/system.io.fileshare(v=vs.71).aspx
FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.None);
You need to pass in a FileShare enumeration value of None to open on the FileStream constructor overloads:
fs = new FileStream(#"C:\Users\Juan Luis\Desktop\corte.txt", FileMode.Open,
FileAccess.ReadWrite, FileShare.None);
I ended up writing this helper class to do this:
public static class FileHelper
{
public static void ReplaceFileContents(string fileName, Func<String, string> replacementFunction)
{
using (FileStream fileStream = new FileStream(
fileName, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None))
{
StreamReader streamReader = new StreamReader(fileStream);
string currentContents = streamReader.ReadToEnd();
var newContents = replacementFunction(currentContents);
fileStream.SetLength(0);
StreamWriter writer = new StreamWriter(fileStream);
writer.Write(newContents);
writer.Close();
}
}
}
which allows you to pass a function that will take the existing contents and generate new contents and ensure the file is not read or modified by anything else whilst this change is happening
You are likely looking for FileStream.Lock and FileStream.Unlock
I think you just need to use the FileShare.None flag in the overloaded Open method.
file = File.Open("storage.bin", FileMode.Open, FileShare.None);
I need to read a Windows file that may be locked, but I don't want to create any kind lock that will prevent other processes from writing to the file.
In addition, even if the file is locked for exclusive use, I'd like to see what's inside.
Although this isn't my exact use case, consider how to read a SQL/Exchange log or database file while it's in use and mounted. I don't want to cause corruption but I still want to see the insides of the file and read it.
You can do it without copying the file, see this article:
The trick is to use FileShare.ReadWrite (from the article):
private void LoadFile()
{
try
{
using(FileStream fileStream = new FileStream(
"logs/myapp.log",
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
using(StreamReader streamReader = new StreamReader(fileStream))
{
this.textBoxLogs.Text = streamReader.ReadToEnd();
}
}
}
catch(Exception ex)
{
MessageBox.Show("Error loading log file: " + ex.Message);
}
}
The accepted answer is not correct. If the file is really locked, you cannot just change the file share. This would work if the lock has been set with this fileshare option too but it does not mean that it is the case. In fact, you can test #CaffGeek solution pretty easily by opening the file without the FileShare.ReadWrite and than trying to open it with this flag to ReadWrite. You will get that the file is using by another process.
Code:
string content;
var filePath = "e:\\test.txt";
//Lock Exclusively the file
var r = File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.Write);
//CaffGeek solution
using (FileStream fileStream = new FileStream(
filePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
using (StreamReader streamReader = new StreamReader(fileStream))
{
content = streamReader.ReadToEnd();
}
}
As you can see, it crashes. This result is the same with any FileStream method like the File.Open. It will crash what ever you put for FileShare during the open stage.
//OPEN FOR WRITE with exclusive
var r = File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.Write);
//OPEN FOR READ with file share that allow read and write
var x = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); //Crash
Copying the file is not also an option. You can try it your self by opening the file exclusively and try to copy the file on Windows Explorer or by code:
var filePath = "e:\\test.txt";
var filePathCopy = "e:\\test.txt.bck";
//Lock the file
var r = File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.Write);
File.Copy(filePath, filePathCopy);
var x = File.Open(filePathCopy, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (var reader = new StreamReader(x))
{
content = reader.ReadToEnd();
}
r.Close();
File.Delete(filePathCopy);
This code crash when you hit the File.Copy line. The exception is the same as before : file is being using by another process.
You need to kill the process that has the lock of the file if you want to read it OR if you have the source code of the file that is locking the file to change this one to use FileShare.ReadWrite instead of just FileShare.Write.
You can probably create a copy and read that, even if the file is locked.
Or maybe a StreamReader on a FileStream depending on how SQL opened the file?
new FileStream("c:\myfile.ext", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);