Exists, Read and Write in just one step - c#

I'm trying to find out if a file exists, if it does, verify if the css style already exists, if not, write them at the end of the file ...
I'm doing all this already but in 3 steps:
Does the file exist?
FileInfo fi= new FileInfo(Path.Combine(rootPath, "DefaultStyles.css");
If it does, I use TextReader to get the contents
using (TextReader tr = new StreamReader(file))
{
r = tr.ReadToEnd().Contains(".onebyonecard");
tr.Close();
}
Then I write into it if style was not found
using (TextWriter tw = new StreamWriter(file))
{
tw.Write(cssStyle);
tw.Close();
}
Is there a way to do this in one easy open / close, instead needed to open the file over and over?

Well you can open a single stream for read and write - but given that you're reading the whole file, I would personally just open it twice. Note that your current code will overwrite the file, not append to it.
I would personally use the static methods in the File class:
// Elide this into the "if" condition if you want. I've separated it out here,
// but obviously it makes no difference.
bool present = File.Exists(path) &&
File.ReadAllText(path).Contains(".onebyonecard);
if (!present)
{
File.AppendAllText(path, cssStyle);
}
This is simpler than having a read/write stream and creating both a TextReader and a TextWriter over it.
A couple of notes:
By separating the file access, there is a slight risk of a race condition. We could open the file, read the contents, then it could be updated while we decide what to do next. Likewise the file could exist when we perform the check, but then be deleted before it's read. In most applications this risk is so slight as to be irrelevant - only you can say for sure.
The code above could still throw an exception, if the file exists but can't be read/written by the relevant user, or is in use by another process. Normal exception handling style applies - decide to what extent you think you can actually recover from such situations, and act appropriately.

Well, since you are using ReadToEnd() you might as well use:
if (!File.Exists(file) || !File.ReadAllText(file).Contains(".onebyonecard"))
File.AppendAllText(file, cssStyle);
but this still opens it twice. There are APIs that would allow it to be opened once only, but those are binary APIs (Stream etc) - which will work, but are probably overkill for your scenario.

try
{
TextReader tr = new StreamReader(file);
r = tr.ReadToEnd().Contains(".onebyonecard");
tr.Close();
tr.Dispose ();
}
catch { //File is not exists or is used by another application
}

Related

C# Windows Service keeps file locked using FlatDocument an example from MSDN "Find and Replace text in a Word document"

I have a Windows Service to copy files to a folder and replace Text in Word documents. For the replace in the documents I use this code: Find and Replace text in a Word document
The problem is: The files stay in use until I copy the next files to another folder (and fill out Word document).
My code for the Search and Replace looks like this:
using (var flatDocument = new FlatDocument(fullpath))
{
flatDocument.FindAndReplace("ValueA", "ValueB");
// Save document on Dispose.
}
if I Skip this code the Service runs fine and the Files are not in use after copy. How come it stays in use even after the using clause?
Maybe someone has a clue?
I think there might be a bug in the Developer Center Sample Code Find and Replace text in a Word document.
In short, its keeping the File Handle open by not calling Dispose on the Underlying FileStream in the FlatDocument class. This seems weird as you would think Package.Dispose would clean up this handle, yet it doesn't.
If you modify the code in the FlatDocument class (as i have done in the following), it should fix it
In the constructor
private Stream _stream; // Add this
public FlatDocument(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
_stream = stream; // Add this
documents = XDocumentCollection.Open(stream);
ranges = new List<FlatTextRange>();
CreateFlatTextRanges();
}
In Dispose
public void Dispose()
{
documents.Dispose();
_stream.Dispose(); // Add this
}

Best approach to replace specific lines in a text file in c#

For the following operation:
Open a text file
Search and replace all searching characters with new characters
I'd like to achieve above in c#, here is my code:
using (StreamReader sr = new StreamReader(#"S:\Personal Folders\A\TESTA.txt"))
{
using (StreamWriter sw = new StreamWriter(#"S:\Personal Folders\A\TESTB.txt"))
{
string line;
while ((line = sr.ReadLine())!= null)
{
if (!line.Contains("before"))
{
sw.WriteLine(line);
}
else if (line.Contains("before"))
{
sw.WriteLine(line.Replace("before", "after"));
}
}
}
}
Basically, the above code will generate a new file with the desired replace operation, but as you can see, the way I am doing is read each line of the original file and write to a new file. This could achieve my goal, but it may have system IO issue because it is reading and writing for each line. Also, I cannot read all the lines to an array first, and then write, because the file is large and if I try to write to an string[], replace all, then write the array to the file, will bring about the memory timeout issue.
Is there any way that I can just locate to the specific lines, and just replace those lines and keep all the rest? Or What is the best way to solve the above problem? Thanks
I don't know what IO issue you are worried about, but your code should work ok. You can code more concisely as follows:
using (StreamReader sr = new StreamReader(#"S:\Personal Folders\A\TESTA.txt"))
{
using (StreamWriter sw = new StreamWriter(#"S:\Personal Folders\A\TESTB.txt"))
{
while ((string line = sr.ReadLine())!= null)
{
sw.WriteLine(line.Replace("before", "after"));
}
}
}
This will run a bit faster because it searches for "before" only once per line. By default the StreamWriter buffers your writes and does not flush to the disk each time you call WriteLine, and file IO is asynchronous in the operating system, so don't worry so much about IO.
In general, what you are doing is correct, possibly followed by some renames to replace the original file. If you do want to replace the original file, you should rename the original file to a temporary name, rename the new file to the original name, and then either leave or delete the original file. You must handle conflicts with your temporary name and errors in all renames.
Consider you are replacing a six character string with a five character string - if you write back to the original file, what will you do with the extra characters? Files are stored on disk as raw bytes of data, there is no "text" file on disk. What if you replace a string with a longer one - you then potentially have to move the entire rest of the file to make room to write the longer line.
You can imagine the file on disk as letters written on graph paper in the boxes. The end of each line is noted by a special character (or characters - in Windows, that is CRLF), the characters fill all the boxes horizontally. If you tried to replace words on the graph paper you would have to erase and re-write lots of letters. Writing on a new sheet will be easiest.
Well, your approach is basically fine... but I wouldn't check if the line contains the word before... the trade-off is not good enough:
using (StreamReader sr = new StreamReader(#"S:\Personal Folders\A\TESTA.txt"))
{
using (StreamWriter sw = new StreamWriter(#"S:\Personal Folders\A\TESTB.txt"))
{
String line;
while ((line = sr.ReadLine()) != null)
sw.WriteLine(line.Replace("before", "after"));
}
}
Try following :
else if (line.Contains("before"))
{
sw.WriteLine(line.Replace("before", "after"));
sw.Write(sr.ReadToEnd());
break;
}

Is it necessary to close a file after calling ReadAllText?

I am doing the following:
if (File.Exists(filePath))
{
string base64 = File.ReadAllText(filePath);
return new ImageContentDTO
{
ImageContentGuid = imageContentGuid,
Base64Data = base64
};
}
This works perfectly fine. What I want to ask is if I need to Close the file or anything similar after I am done reading from it. And if so, how?
No, you don't have to explicitly close the file, File.ReadAllText takes care of that for you.
The documentation contains this information very explicitly:
This method opens a file, reads each line of the file, and then adds each line as an element of a string. It then closes the file.
[...]
The file handle is guaranteed to be closed by this method, even if exceptions are raised.
You don't need to close anything when using File.ReadAllText since the underling stream reader is closed implicitely.
MSDN: File.ReadAllText
Opens a text file, reads all lines of the file, and then closes the
file.
Here's the implementation in .NET 4 (ILSpy):
string result;
using (StreamReader streamReader = new StreamReader(path, encoding))
{
result = streamReader.ReadToEnd();
}
return result;
The using statement disposes the StreamReader (even on error), that also closes it.
I know this question has been answered and this is almost a year now but for those who search and read this question, I would like to suggest you close a file when done with it, or at least do an investigation like my answer shows.
I am no programming expert but I have come across this situation recently.
I created a WinForms c# program and used File.ReadAllText to copy text to a string. Afterwards I tried to delete the file, directly from the folder not through the program, but I got an error that the file was still open in another program. I then stopped running the program and was able to delete the file.
That's my experience in Visual Studio 2012 Ultimate. It might be supposed to do something different, but that's what it did for me.
When I used StreamReader.ReadToEnd then StreamReader.Close on the same file, I had no problem deleting the file while running the program.
You have to close IDisposable instances only, usually by means of using, e.g.:
// StreamReader is IDisposable and should be Closed/Disposed
// either explicitly or by using
using (StreamReader sr = new StreamReader(filePath)) {
String base64 = sr.ReadToEnd();
...
}
since you don't have an IDisposable instance in your code (File.ReadAllText
returns String which is not IDisposable) you have nothing to Close/Dispose
StreamWriter outputFile = new StreamWriter(#"C:\Users\Marc\Desktop\_App\files\Data" + dat1 + ".txt");
outputFile.WriteLine(sb.ToString());
outputFile.Close();
StreamWriter outputFileex = new StreamWriter(#"C:\Users\Marc\Desktop\_App\files\DataEx" + dat1 + ".txt");
outputFileex.WriteLine(sbex.ToString());
outputFileex.Close();
Here's a working example I just did with a stringbuilder: "sb". If I remove one of those closes' the file gets generated but the file shows up blank with no data. I had to add in a close to get it to work properly.

Using C# File class to edit file, but throwing exception

I am using the File class to edit an HTML file. I need to delete a line of code from it. The way I am doing it is:
if (selectedFileType.Equals("html"))
{
string contentsOfHtml = File.ReadAllText(paramExportFilePath);
//delete part that I don't want
string deletedElement = "string I need to delete";
contentsOfHtml.Replace(deletedElement, "");
File.WriteAllText(paramExportFilePath, contentsOfHtml);
}
However it is throwing the exception: The process cannot access the file 'path\to\file.html' because it is being used by another process.
I am worried that this is happening because either the File.ReadAllText or File.WriteAllText methods are running on the file, even though in the documentation it specifies that they do close the file. So does anyone know what could be causing this?
If this is a file on a live site then there's a good chance that the web server has a lock on it.
Assuming your working in Windows, try using Process Explorer to see what has a lock on the file.
Whenever you are dealing with Stream based objects, you are always better off wrapping in using statements:
String s1;
using (StreamReader r = new StreamReader(paramExportFilePath, Encoding.ASCII))
{
s1 = r.ReadToEnd();
}
String s2 = s1.Replace("string to delete", "replacement string");
using (StreamWriter w = new StreamWriter(paramExportFilePath, false, Encoding.ASCII))
{
w.Write(s2);
}
The using statements ensure that objects are properly closed and, more importantly, disposed.
Note: replace Encoding.ASCII with whatever you like (perhaps UTF8 if it's HTML code).

Debug file used by another process

Using Visual Studio 2010 and im getting "File is used by another process" almost randomly when trying to read a file. Im reading about 10 xml files into memory with the same procedure
The code that breaks is
private static TextReader CreateTextReader(IsolatedStorageFile isolatedStorageFolder, string path)
{
TextReader textReader = null;
if (isolatedStorageFolder == null)
textReader = new StreamReader(path);
else
textReader = new StreamReader(new IsolatedStorageFileStream(path, FileMode.Open, isolatedStorageFolder));
return textReader;
}
The code breaks 10 percent of the time on
textReader = new StreamReader(path);
I personally think its some kind of garbage collection problem, anyone has any tips on how to debug this kind of problem.
Be sure to call .Dispose or .Close on all steam reader operations that could lock the file. That might be your problem as that code works for me as a flat program.
You need to dispose of the TextReader. Use the using statement like
using (TextReader r = CreateTextReader(...))
{
}
Otherwise the file will remain open when you close your application.
EDIT
You're saying in your comments to the question that you're actually already using using - could it be that the file you're trying to read is actually opened by another application? Sometimes antivir solutions lock files while scanning them or stuff like that - will it work after a short while or do you have to reboot or something like that?

Categories

Resources