I'm working on an application that should store some PDF for later printing. I have an implementation that is checking what size the PDF is and according to the size I choose between Memory or File Streams (<2GB = MemStream and >2GB = FileStream).
When I am using the FileStream the performance varies and I just noticed that this is caused by the Windows Memory Cache. Basically everything i am using to write/read to/from a FileStream will get into this cache and after saving 6 PDFs I get really low performance (30 seconds compared to 60s+)
I declare my FileStream in the following way:
FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 524288, FileOptions.WriteThrough))
I just added the WriteThrough option but it does not seem to fix the issue.
Is there a possibility that after I save the file to disk and close/dispose the FileStream I get the cache memory cleared?
Thank you in advance!
__________edit___________
adding code snippets.
loadStream = new FileStream(#"C:\temp\FileStream_test.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None, 524288);
request.InputStream.CopyTo(loadStream);
loadStream.Flush();
loadStream.Position = 0;
and 2nd one
using (var mimePDL = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 524288, FileOptions.WriteThrough))
{
mimeParts[contentID].Content.DecodeTo(mimePDL);
mimePDL.Position = 0;
mimePDL.Flush(true);
mimePDL.Close();
mimePDL.Dispose();
}
And for the first one I dispose of it this way
loadStream.Close();
loadStream.Dispose();
File.Delete(((FileStream)loadStream).Name);
In my opinion you shouldn't store PDFs in memory if you aren't manipulating them.
After manipulations, just save the file and dispose the stream.
If you need some metadata, just take them in your application instead of the entire file.
Related
I'm appending data to a file using Filestream buffer, see below:
using (FileStream filestream = new FileStream(stringPathFile, FileMode.Append, FileAccess.Write, FileShare.None))
{
filestream .Write(stuff.buffer, 0, stuff.bytesRead);
}
As debuging, when writing a larger file, I saw the file being written to the destination by every 4096 bytes, and i was able to move the file to somewhere else. How do I block file being moved around until i complete writing to the file?
Thanks
Use FileShare.ReadWrite instead of FileShare.None.
EDIT: after some testing in VB.NET 2010 (I don't have access to C# at the moment), I replicated your problem. What seems to fix the problem is avoid using using...
FileStream filestream = new FileStream(stringPathFile, FileMode.Append, FileAccess.Write, FileShare.None)
{
filestream.Write(stuff.buffer, 0, stuff.bytesRead);
}
Is this syntax
FileStream fs = new FileStream(strFilePath, FileMode.Create);
the same as this?
FileStream fs = File.Create(strFilePath);
When yes, which one is better?
It does matter, according to JustDecompile, because File.Create ultimately calls:
new FileStream(path,
FileMode.Create,
FileAccess.ReadWrite,
FileShare.None,
bufferSize,
options);
With a bufferSize of 4096 (default) and FileOptions.None (also the same as with the FileStream constructor), but the FileShare flag is different: the FileStream constructor creates the Stream with FileShare.Read.
So I say: go for readability and use File.Create(string) if you don't care about the other options.
In my opinion, I use this one:
using (FileStream fs = new FileStream(strFilePath, FileMode.Create))
{
fs.Write("anything");
fs.Flush();
}
They basically doing the same thing, but this one create the file and opens it in create / write mode, and you can set your buffer size and all params.
new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize, options);
With File.Create it wraps all those default buffer and params.. You will have a way better flexibility and management with my new FileStream(strFilePath, FileMode.Create);
But at this point it's more a personnal choice, if you want more readability or management options!
The second one uses just a different FileMode for the stream: take a look to this article
http://msdn.microsoft.com/en-us/library/47ek66wy.aspx
to manage default values of this method!
But use a using statement, so any resource will be released in the correct way!
using (FileStream fs = new FileStream(strFilePath, FileMode.Create))
{
// HERE WHAT YOU WANT TO DO!
}
They do exactly the same thing. The only real difference is that the former would let you use a different FileMode at runtime if you wanted to (controlling it with a variable) and the latter will only ever be doing a Create operation.
As a side note, convention is to handle things like a filestream in a using block to automatically dispose of them when they are out of scope.
using (var fs = new FileStream(strFilePath, FileMode.Create))
{
//do some stuff
}
First one creates or overwrites file with sharing Read access second with None. So it depends do you want to allow to give access while processing file or not.
With the first one you have more options to do like : handle, file access, file mode, int buffer size,.... but with the second one you have less options to do.
In VB.NET or C#, I'm trying to read the contents of a text file that is in use by another program (that's the point, actually, I can't stop the program or it stops writing to the text file, and I want to periodically read out what is currently in the text file in another program).
This is the code I'm using (VB.NET)
Dim strContents As String
Dim objReader As StreamReader
objReader = New StreamReader(FullPath)
strContents = objReader.ReadToEnd()
objReader.Close()
Or in C#:
var objReader = new StreamReader(FullPath);
var strContents = objReader.ReadToEnd();
objReader.Close();
The above, however, throws the IO exception "The process cannot access the file 'file.txt' because it is being used by another process." Are there any workarounds in this scenario?
FileStream logFileStream = new FileStream("c:\test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader logFileReader = new StreamReader(logFileStream);
while (!logFileReader.EndOfStream)
{
string line = logFileReader.ReadLine();
// Your code here
}
// Clean up
logFileReader.Close();
logFileStream.Close();
Original source for code
I'll do the fish. The FileShare mode is critical, you must allow for write sharing. That cannot be denied since the process that is writing the file already obtained write access. The StreamReader() constructor uses FileShare.Read and doesn't have an option to use a different value. Using the StreamReader(Stream) constructor is instead is indeed the workaround.
Beware however that this sharing mode also has implications for your code. You cannot predict when the other process flushes the file. The last line you read may contain only part of a line of text. When it flushes is file buffer again, later, you'll get the rest of the line. Clearly this can mess up your logic.
It depends on the FileShare mode with which the file was opened by the other application that is appending to the file. When the other application was opening the file, it specified a FileShare mode for other applications to access the file. This FileShare mode could have been read, write, both, delete, all of these, or none.
You have to specify the very same FileShare mode that the other application specified. If the other application allowed only reading, use FileShare.Read; if it allowed both reading and writing, use FileShare.ReadWrite.
StreamReader uses only FileShare.Read mode, so you can already assume that that's not the right one. So, try ReadWrite, like so:
FileStream fs = new FileStream(FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader reader = new StreamReader(fs);
Not sure how this will behave with an already open file, but this will prevent your application from locking it:
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader sr = new StreamReader(fs);
Hope it helps!
How do I read and write on a text file without getting the exception that "File is already in use by another app"??
I tried File.readalltext() and File.Appendalltext() functions..I'm just starting out with filestream.
Which would work out best in my scenario? I would appreciate some code snipplets too ..
Thanks
This is all to do with the lock and sharing semantics that you request when opening the file.
Instead of using the shortcut approach of File.ReadAllText(), try looking into using a System.IO.FileStream and a System.IO.StreamReader / System.IO.StreamWriter.
To open a file:
using (var fileStream = new FileStream(#"c:\myFile", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var streamReader = new StreamReader(fileStream))
{
var someText = streamReader.ReadToEnd();
}
Note the FileShare.ReadWrite - this is telling the stream to allow sharing to either other readers or other writers.
For writing try something like
using (var fileStream = new FileStream(#"c:\myFile", FileMode.Create, FileAccess.Write, FileShare.Read))
using (var streamWriter = new StreamWriter(fileStream))
{
streamWriter.WriteLine("some text");
}
Note the FileShare.Read - this is telling the stream to allow sharing to readers only.
Have a read around the System.IO.FileStream and its constructor overloads and you can tailor exactly how it behaves to suit your purpose.
You need to make sure the file is not being used by any other application.
With your own application, you cannot read from a file multiple times without closing the stream between reads.
You need to find out why the file is in use - a tool like FileMon can help finding out.
I've been using File.ReadAllText() to open a CSV file, but every time I forget to close the file in Excel, the application throws an exception because it can't get access to the file.
(Seems crazy to me, I mean the READ in ReadAllText seems pretty clear)
I know that there is File.Open with all the bells and whistles, but is there an 'intermediate' method which doesn't involve messing around with buffers and char arrays?
I think you just want the following:
using (var fileStream = new FileStream("foo.bar", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var textReader = new StreamReader(fileStream))
{
var content = textReader.ReadToEnd();
}
The FileAccess.Read parameter is what is important, to indicate that you only want to read the file. Of course, even to do this, the file must have been opened by Excel in read-share mode (see the FileShare enum in .NET). I haven't tested, so I can't guarantee that Excel does this, though I would expect it does.
[edit]
Here's a method version:
static string ReadAllText(string file)
{
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var textReader = new StreamReader(fileStream))
return textReader.ReadToEnd();
}
If you want to specify file sharing flags in order to open a file that's in use, you're stuck with File.Open().