I'm writing a program that uses text files in C#.
I use a parser class as an interface between the file structure and the program.
This class contains a StreamReader, a StreamWriter and a FileStream. I use the FileStream as a common stream for the reader and the writer, else these two will conflict when both of them have the file open.
The parser class has a class variable called m_path, this is the path to the file. I've checked it extensively, and the path is correct. OpenStreams() and and ResetStreams() work perfectly, however after calling CloseStreams() in the delete() function, the program goes to the catch clause, so File.Delete(m_path) won't get executed. In other situations the CloseStreams() function works perfectly. It goes wrong when I'm trying to close the StreamReader (m_writer), but it does give an exception (File is Already Closed).
/**
* Function to close the streams.
*/
private void closeStreams() {
if (m_streamOpen) {
m_fs.Close();
m_reader.Close();
m_writer.Close(); // Goes wrong
m_streamOpen = false;
}
}
/**
* Deletes the file.
*/
public int delete() {
try {
closeStreams(); // Catch after this
File.Delete(m_path);
return 0;
}
catch { return -1; }
}
I call the function like this:
parser.delete();
Could anybody give me some tips?
Your File.Delete(m_path); will never be called, because you get an exception here:
private void closeStreams() {
if (m_streamOpen) {
m_fs.Close();
m_reader.Close();
m_writer.Close(); // throws an exception here
m_streamOpen = false;
}
}
The exception is "Cannot access a closed file"
The cause is explained in the documentation of Close() in StreamReader:
Closes the System.IO.StreamReader object and the underlying stream, and releases any system resources associated with the reader.
There are also some articles about this behaviour:
Does disposing streamreader close the stream?
Is there any way to close a StreamWriter without closing its BaseStream?
Can you keep a StreamReader from disposing the underlying stream?
Avoiding dispose of underlying stream
You should consider re-writing your code and use using() statements.
However, I experimented a bit with your code, and it worked with calling Close() in other order:
m_writer.Close();
m_reader.Close();
m_fs.Close();
However, I assume that this works only by coincidence (I used .NET 4.0 and probably this will not work in another .NET version). I would strongly advice to not do it in this way.
I tested this:
using (FileStream fs = new FileStream(m_path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
using (StreamReader reader = new StreamReader(fs))
using (StreamWriter writer = new StreamWriter(fs))
{
// so some work here
}
File.Delete(m_path);
But, I know that this may not be for you, since you may want the read and write streams available as fields in your class.
At least, you have some samples to start with ...
File.Delete should work, either you didn't call your delete method, or m_path is an invalid path
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)
I'm merging some of my cvs reading code into a single class, and I'm thinking of just making it override streamreader. However, I want to keep the class private values I added (delimiter, recordcount, etc) and be able to close and reopen the file.
The reason I need to be able to is to do a quick pass to determine various things such as the delimiter, whether there are embedded line breaks in the data, actual record count, field count, etc.
Obviously I can't use using (streamreader sr = new streamreadder(filename)) because that will destroy the object at the end but can I close the file and reopen it? Can I do cvsstreamclass sr = new cvsstreamclass(filename), and then sr.close() and sr.open()? I understand that streamreader seek has problems so I probably shouldn't just use that.
Or am I going about this all wrong and should I just pass in the streamreader object to a class that handles the parsing and whatnot??
btw, I'm not looking at switching to an opensource cvs class or other library. I've already got a lot of this code written, and it works. No need to suggest that.
A CSV parser is not a StreamReader. The two are not related and there should not be an inheritance relationship.
Your CsvReader class should have a StreamReader member. You can the set and manipulate that member however you like. For example, you can close the existing reader and create a new one at any time.
I recommend you actually store the StreamReader in your reader class. There is no point in subclassing StreamReader unless you're going to expose it to some other code in the form of a StreamReader. I would do something like this:
public class CSVReader
{
private StreamReader reader;
private string fileName;
//Your other properties and fields here
public CSVSReader(string filename)
{
this.fileName = fileName;
InitReader();
}
public void CloseFile()
{
if (reader != null)
{
reader.Close();
reader = null;
}
}
public void OpenFile()
{
CloseFile();
reader = new StreamReader(File.OpenRead(fileName));
}
//Your other methods here
}
Obviously, I'm not using any try-catch blocks for opening the file, but that's just for the sake of readability.
You could also inherit from IDisposable, making your class usable inside a using () block.
I'm attempting to use StreamReader and StreamWriter to grab a temporary output log (.txt format) from another application.
The output log is always open and constantly written to.
Unhelpfully if the application closes or crashes, the log file ends up deleted - hence the need for a tool that can grab the information from this log and save it.
What my program currently does is:
Create a new .txt file, and stores the path of that file as the
string "destinationFile".
Finds the .txt log file to read, and stores the path of that file as
the string "sourceFile"
It then passes those two strings to the method below.
Essentially I'm trying to read the sourceFile one line at a time.
Each time one line is read, it is appended to destinationFile.
This keeps looping until the sourceFile no longer exists (i.e. the application has closed or crashed and deleted its log).
In addition, the sourceFile can get quite big (sometimes 100Mb+), and this program may be handling more than one log at a time.
Reading the whole log rather than line by line will most likely start consuming a fair bit of memory.
private void logCopier(string sourceFile, string destinationFile)
{
while (File.Exists(sourceFile))
{
string textLine;
using (var readerStream = File.Open(sourceFile,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
using (var reader = new StreamReader(readerStream))
{
while ((textLine = reader.ReadLine()) != null)
{
using (FileStream writerStream = new FileStream(destinationFile,
FileMode.Append,
FileAccess.Write))
using (StreamWriter writer = new StreamWriter(writerStream))
{
writer.WriteLine(textLine);
}
}
}
}
}
The problem is that my WPF application locks up and ceases to respond when it reaches this code.
To track down where, I put a MessageBox just before the writerStream line of the code to output what the reader was picking up.
It was certainly reading the log file just fine, but there appears to be a problem with writing it to the file.
As soon as it reaches the using (FileStream writerStream = new FileStream part of the code, it stops responding.
Is using the StreamWriter in this manner not valid, or have I just gone and dome something silly in the code?
Am also open to a better solution than what I'm trying to do here.
Simply what I understand is you need to copy a file from source to destination which may be deleted at any time.
I'll suggest you to use FileSystemWatcher to watch for source file changed event, then just simply copy the whole file from source to destination using File.Copy.
I've just solved the problem, and the issue was indeed something silly!
When creating the text file for the StreamWriter, I had forgotten to use .Dispose();. I had File.Create(filename); instead of File.Create(filename).Dispose(); This meant the text file was already open, and the StreamWriter was attempting to write to a file that was locked / in use.
The UI still locks up (as expected), as I've yet to implement this on a new thread as SteenT mentioned. However the program no longer crashes and the code correctly reads the log and outputs to a text file.
Also after a bit of refinement, my log reader/writer code now looks like this:
private void logCopier(string sourceFile, string destinationFile)
{
int num = 1;
string textLine = String.Empty;
long offset = 0L;
while (num == 1)
{
if (File.Exists(sourceFile))
{
FileStream stream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using (new StreamReader(stream))
{
stream.Seek(offset, SeekOrigin.Begin);
TextReader reader2 = new StreamReader(stream);
while ((textLine = reader2.ReadLine()) != null)
{
Thread.Sleep(1);
StreamWriter writer = new StreamWriter(destinationFile, true);
writer.WriteLine(textLine);
writer.Flush();
writer.Close();
offset = stream.Position;
}
continue;
}
}
else
{
num = 0;
}
}
}
Just putting this code up here in case anyone else is looking for something like this. :)
This question already has answers here:
Is there a way to check if a file is in use?
(20 answers)
Closed 6 years ago.
Is there a way to find if a file is already open or not?
protected virtual bool IsFileinUse(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
return false;
}
As #pranay rana, but we need to make sure we close our file handle:
public bool IsFileInUse(string path)
{
if (string.IsNullOrEmpty(path))
throw new ArgumentException("'path' cannot be null or empty.", "path");
try {
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { }
} catch (IOException) {
return true;
}
return false;
}
If you mean that you want to check if a file is open before you try to open it, then no. (At least not without going low level and examine every file handle that is open in the system.)
Besides, the information would be old when you get it. Even if the test would return that the file is not open, it could have been opened before you have a chance to use the return value.
So, the proper way to handle the situation is to try to open the file, and handle any error than may occur.
Agreed. I would create a designated class which wraps the open file logic or at least the test (IsFileAvailable). This will allow you to place the exception management with a class specifically responsible and make it reusable. You may even apply further logic, such as testing the file size to see if the file is being written to etc, to give a more detailed response. It will also make your consuming code much cleaner.