System.IO.FileStream FileAccess vs FileShare
FileAccess says what you are going to do with the file. Pretty easy to understand, you'll know you are going to read or write.
FileShare is the much trickier one since it requires you to step into the shoes of another programmer. It determines what another process can do if it also has the file opened. Two processes accessing a file can be very troublesome, you'll need to reason through the possible failure modes. The value you pick is strongly correlated to the type of the file and the access you want. Breaking it down by what you are going to do:
FileAccess.Read
There is never any trouble if another process also reads from the file. So FileShare.Read is the default choice.
You may need FileShare.ReadWrite if another process has already opened the file for writing. It already gained write access so you can never open the file yourself with just FileShare.Read, you can't deny writing since that other process was first, you'll be denied access instead. This generally only comes to a good on a text file, the kind where you can be sure that the other process is only ever appending text to the end of the file. A log file is the very common scenario. Still possibly tricky, it matters exactly when that process flushes changes to the file. You might observe partially written lines of text, beware of this.
FileAccess.Write
You cannot use FileShare.Write or FileShare.ReadWrite. Since that would allow two processes writing to the file at the same time, the file content will be a jumble of output from both programs. A possible workaround is these processes arbitrating access to the file, ensuring only one of them can ever access the file at the same time. Normally implemented by a named mutex.
You can use FileShare.Read if it is text file, same scenario I described above with the log file. The default choice otherwise should be FileShare.None
FileAcces.ReadWrite
Not that common, only used if you write binary data and use Seek(). There is no hope that any other process could ever read the file correctly while you are doing this, assuming they don't arbitrate access themselves, you must use FileShare.None.
File access differences between FileStream and System.IO.File method
The FileStream
constructor passes off to another constructor overload.. namely this one:
internal FileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, string msgPath, bool bFromProxy, bool useLongPath, bool checkHost)
The FileAccess
it passes by default is FileAccess.ReadWrite
. If your application does not have write permissions.. chances are this will fail.
On the other hand, File.ReadAllBytes
does this:
using (var fileStream = new FileStream(..., ..., FileAccess.Read, ...
// ^^^^ this
Notice File.ReadAllBytes
uses the FileAccess.Read
value.
So that's the difference. FileStream.ctor
uses FileAccess.ReadWrite
, File.ReadAllBytes
uses FileAccess.Read
.
TLDR: Your app needs write permissions to use that basic constructor for FileStream
. Remember there is a File.Exists
method that is meant for this exact purpose. Opening and closing a file to see if it exists is not the right way to go about it.
FileShare.ReadWrite in System.IO.Packaging
It's not clear why you want to do this, but you can try specifying options on file stream directly like this:
using (var file = new FileStream(@"myfile", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
var myPackage = Package.Open(file);
}
UPDATE to elaborate a bit more about when this might be useful. Suppose you try to do something like this:
using (var fs1 = new FileStream("myfile", FileMode.Append, FileAccess.Write, FileShare.Read))
using (var fs2 = new FileStream("myfile", FileMode.Open, FileAccess.Read, FileShare.Read)) {
}
So first file is opened for writing, with FileShare = Read. Then there is another attempt to open file, for reading, again with FileShare = Read. This won't work, because if file has already been opened for write, any request with FileShare = read will fail. To make this work you have to do it like this:
using (var fs1 = new FileStream("myfile", FileMode.Append, FileAccess.Write, FileShare.Read))
using (var fs2 = new FileStream("myfile", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
}
Here you request FileShare.ReadWrite which allows you to read file opened by fs1 for writing.
Now, if writing and reading the same file concurrently is a good idea is completely dependent of what you want to achieve and if you know what you are doing. In most cases it's not a good idea, but again it depends.
UPDATE 2. It's perfectly possible to use code above to achieve your goal (open .docx for reading while MS Word has it open for writing:
using (var file = new FileStream(@"my.docx", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
var myPackage = Package.Open(file);
// here do what you want with your .docx
}
File sharing not working as expected
var fileStream2 = new FileStream(..., FileShare.Read)
This trips up lots of programmers. Everybody assumes that this added read sharing. It didn't, the original file access request already allowed reading and specifying it again doesn't change anything. Instead it denies write sharing. And that cannot work because somebody already got write access. And is using it, you cannot remove that right. So your request to access the file will fail.
You must include FileShare.Write.
System.IO effects on OS's file system performance in C#
According to reflector, File.Create(path)
is just:
new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.None);
and new FileStream(@"file.dat", FileMode.Create, FileAccess.Write)
also gets the 4096 buffer - so no, it is just the FileAccess.ReadWrite
which is different.
And I don't think FileAccess.Write
is much better than FileAccess.ReadWrite
because they both locks the file - but I may be wrong.
to comment: because FileShare
is set to None
and it is write access you want they properly (=I don't know for sure) ain't much of a difference. However, if you wanted Read
access the new FileStream(path, mode, access)
approach is different because FileShare
is set to Read
as a default. However, in this case you want to create a file, and therefore it does not make much sense to only read ;-)
FileStream in app cannot access file locked by service despite FileShare.Read option
On the non-service application, it also needs the FileShare.ReadWrite
parameter, resulting:
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
The problem you're having isn't that the service isn't allowing the non-service application to open the file, but that your non-service application tries to read the file, declaring that it cannot be read/written/deleted by other processes at the same, when some other process already has it open.
FileStream keeps saying that the file is busy while it's not opened by any application at all
Your process is conflicting with itself.
You're opening it here (in a way that would be simpler with File.CreateText
, by the way) - but never actually using the writer you've created:
FileStream stream = new FileStream("DATA.txt", FileMode.Create, FileAccess.Write);
StreamWriter writer = new StreamWriter(stream);
... then you're separately trying to append to it here, even though stream
is already open:
File.AppendAllText("DATA.txt", studentID + Environment.NewLine);
Pick one way of writing to the file, and stick to it. Personally, I'd suggest creating a List<string>
or an array for all the lines you want to write, and just call File.WriteAllLines
once, but you could continue to use either the writer approach or the File.AppendAllText
approach... just not together like this.
Here's a simpler implementation of your saveFile
method (renamed to follow normal naming conventions):
public static void SaveFile(string studentId, string studentName, string subjectA, string subjectB)
{
var lines = new[] { studentId, studentName, subjectA, subjectB };
// (Write the lines to the console here if you want.)
File.WriteAllLines("DATA.txt", lines);
}
If you want to append data instead of recreating the file, just use File.AppendAllLines
instead.
Is there a limit for System.IO.FileShare?
I don't know the exact limit imposed by .NET/windows, so I have created a real test for you. I ran the following test code for few minutes and I found that up to 635908 counts of system.io.fileshare
usage, it still functional, i.e. you can still read the flat database file's content.
Here is the code (it is a winform application, .Net 4):
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim filepath As String = "c:\database.txt"
Dim filestream As System.IO.FileStream
Dim count As Int32
For count = 0 To System.Int32.MaxValue
filestream = New System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)
AppendLog(count, filestream.ReadByte)
Next
End Sub
Private LogFilepath As String = "C:\LogInfo.txt"
Private Enter As String = Chr(13) & Chr(10)
Private Space As String = " "
Private Sub AppendLog(ByVal Sequence As Int32, ByVal info As Byte)
System.IO.File.AppendAllText(LogFilepath, Enter & Sequence & Space & CStr(info))
End Sub
End Class
Related Topics
How to Check If an Ip Address Is Within a Particular Subnet
Async Always Waitingforactivation
In C# Why Can't a Conditional Operator Implicitly Cast to a Nullable Type
How to Get an Extension Method to Change the Original Object
How to Get a Dimension (Slice) from a Multidimensional Array
Wpf: the Name Does Not Exist in the Namespace
No Itemchecked Event in a Checkedlistbox
Check If Datetime Instance Falls in Between Other Two Datetime Objects
How to Avoid a System.Runtime.Interopservices.Comexception
Visualizing an Ast Created with Antlr (In a .Net Environment)
When Is Using the C# Ref Keyword Ever a Good Idea
Sqlite .Net Performance, How to Speed Up Things
How to Implement the Sieve of Eratosthenes Using Multithreaded C#