I am in a situation where i need to write to same file stream from different threads. The problem is that i cannot find any clear explanation whether i need to handle current stream position between writes ?
I open stream with FileOptions.Asynchronous option thus have an overlapped IO.
All write requests are coming in sequentially with buffers for next offset and from my test everything working fine and data is written correctly at file offsets.
But really can someone answer if there is no implications with this approach.
You can pass a FileStream to another method through the parameter. For example:
public void FirstMethod(){
FileStream filestream = new FileStream();
//fill filestream
SecondMethod(filestream);
}
public void SecondMethod(FileStream filestream)
filestream.//do whatever you want with it
}
Or you can make a method return the filestream:
public FileStream FirstMethod() {
FileStream filestream = new FileStream();
//fill filestream
}
public void SecondMethod() {
FileStream filestream = FirstMethod();
//do what you want with it
}
If you could show us what you did, we can give you an answer that suits your situation.
Related
I readed a lot of topics about C# streams, but did not find my situation.
For learing purpose i did list-file json-bd like:
public sealed class JSONBD<T> : IDisposable {
private FileStream fileStream;
private TextWriter textWriter; // textWriter = new StreamWriter(fileStream)
private TextReader textReader; // textReader = new StreamReader(fileStream)
public List<T> Bd { get; set; } // null is not awailable here
public string FilePath { get; }
public void Open();
public void Commit();
public void Close();
}
I tryed to use System.IO streams because they are garantee the only user of it file will be a current instance.
Much time in living time object i need to commit, so i cant using using construction because StreamWriter instance closes my FileStream when commiting like StreamReader after deserealization the file. Well, i need to close both of them?
So i decided to use one FileStream, StreamWriter and StreamReader objects at the same time.
The problem is: is it correct to do that way, having 2 streams from FileStream?
The second problem is: how should i close these streams? Will be FileStream.Close() enough or not? At the topics i didnt find any exact solution about that instead closing lower stream. But i have 2 lower streams actually! Well, should i close both of them? But one of them already closes FileStream.
I am really sorry for english mistakes i did. Im still in progress.
I'm using the following lines of code in order to write credentials of users to a text file. It's supposed to create the directory inside AppData (which it does) but it doesn't write the credentials to the text file, it leaves it blank!
public void RegisterUserCreds()
{
string[] creds = { Username.Text, Password.Text };
string roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
if (!Directory.Exists(roaming + "/Launcher"))
Directory.CreateDirectory(roaming + "/Launcher");
string specificFolder = roaming + "/Launcher/user_info.txt";
var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite);
var sw = new StreamWriter(fs);
sw.WriteLine(Username.Text);
fs.Close();
}
What's the problem? Thanks!
Just use the using statement when operating on streams:
public static void RegisterUserCreds()
{
string[] creds = { Username.Text, Password.Text };
string roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
if (!Directory.Exists(roaming + "/Launcher")) Directory.CreateDirectory(roaming + "/Launcher");
string specificFolder = roaming + "/Launcher/user_info.txt";
using (var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(Username.Text);
}
}
}
In your code you were closing the file stream before the stream writer was able to flush the changes you want to write so the file was created empty.
You're closing the wrong stream. When you create new stream objects and pass an existing stream to the constructor, that new stream now "owns" the old stream. When you dispose of the newer stream it will automatically dispose of the older one.
In your situation, you're closing the "fs" stream, but the "sw" stream might not have actually written to it yet (it has it's own internal buffer). If you were to close the "sw" stream instead, it would flush it's buffer (into the "fs" stream), and then it would call fs.Dispose() for you to make sure it did the same thing.
There's a much better way, that would help you avoid doing things out-of-order like this, as well as make sure you're calling Dispose() even if exceptions get thrown (streams implement IDisposable, so you're supposed to always call their Dispose() method when you're done with them so they can internally "clean up"). The using statement is perfect for this, since it will call Dispose() even if an exception is thrown (it's a shortcut for wrapping the code with try/finally blocks):
using (var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(Username.Text);
}
}
This is the same as this:
try
{
var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite);
try
{
var sw = new StreamWriter(fs);
sw.WriteLine(Username.Text);
}
finally
{
sw.Dispose();
}
}
finally
{
fs.Dispose();
}
Even though sw.Dispose() will call fs.Dispose() for you, there is no harm in calling fs.Dispose() again. Why is it important to call Dispose()? Let's say an exception was thrown during sw.WriteLine() (e.g. out of disk space, I/O error, etc.)... the file would stay open until your app terminated. The using (or the try/catch version) would make sure the file was closed no matter what.
(side note: with streams, Dispose() and Close() do the same thing, you don't need to call both. Close() just calls Dispose() -- MS included a method called Close() because that was what people were used to with a file API, but the .NET IDisposable interface uses a method called Dispose())
(another side note: starting with .NET 4.5, many of the stream classes have an additional constructor that has a new "leaveOpen" parameter... passing true would tell that stream to NOT dispose of the original stream automatically)
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 am using this code to write asynchronously to a file
public static void AsyncWrite(string file, string text)
{
try
{
byte[] data = Encoding.Unicode.GetBytes(text);
using ( FileStream fs = new FileStream(file, FileMode.Create,
FileAccess.Write, FileShare.Read, 1, true))
fs.BeginWrite(data, 0, data.Length, null, null);
}
catch
{
}
}
For some reason, from time to time, rather than writing text into the file as expected, Notepad++ shows the following ouput :
BeginWrite is asynchronous, so it might well happen that the stream is closed through the using statement while other things are happening.
I'd not use using when doing asynchronous writing. Instead I'd create a proper callback method and close the stream there. This would also give you the chance to call EndWrite as recommended.
I've got a method that streams files by returning a System.IO.FileStream pointing to a file opened for reading. What I want to do at this point is store the stream into a System.IO.MemoryStream as well.
The simplest option would be to first read the FileStream into the MemoryStream, and then return the MemoryStream to the caller. However this means that I'll have to buffer the entire file into memory before returning, thereby delaying the streaming response to the caller.
What I'd like to do (if possible) is read the FileStream into a MemoryStream and also stream it to the caller simultaneously. This way, the file doesn't have to be buffered before being returned, and still ends up getting stored into a MemoryStream.
You can create a custom implementation of the Stream class in which you write away the data red to a memory stream, or use my version of that which can be found at: http://upreader.codeplex.com/SourceControl/changeset/view/d287ca854370#src%2fUpreader.Usenet.Nntp%2fEncodings%2fRecordStream.cs
This can be used in the following way:
using (FileStream fileStream = File.Open("test.txt", FileMode.Open))
using (RecordStream recordStream = new RecordStream(fileStream))
{
// make sure we record incoming data
recordStream.Record();
// do something with the data
StreamReader reader = new StreamReader(recordStream);
string copy1 = reader.ReadToEnd();
// now reset
recordStream.Playback();
// do something with the data again
StreamReader reader = new StreamReader(recordStream);
string copy2 = reader.ReadToEnd();
Assert.AreEqual(cop1, copy2);
}
I Built this class particularly for Network stream but it works equally well with a fileStream and it only reads the file once without buffering it first before returning
A simple implementation would be
class RecordStream : Stream
{
public Stream BaseStream { get; }
public MemoryStream Record { get; }
....
public override int Read(byte[] buffer, int offset, int count)
{
int result = BaseStream.Read(buffer, offset, count);
// store it
Record.Write(buffer, offset, count);
return result;
}
}