Im trying to load some stuff from a text file, do some processing and write them to a new text file in C#.
Please have a look at my code below:
Everything seems to be working fine, I can load the stuff, edit them and save them into the text file. however, in the middle of saving them it just stops saving them into the text file for some reason, the while loop runs, I can know this because I'm also logging stuff in the console, and everything's fine in there. but after some point (like 80 lines or something), it just stops adding the new lines to the file.
Any idea?
Thanks in advance
StreamReader SR;
StreamWriter SW;
string S;
double temp1;
double temp2;
SR = File.OpenText("C:\...Address");
SW = File.CreateText("C:\...Address");
S = SR.ReadLine();
while (S!=null)
{
string[] words = S.Split(' ');
//editing stuff
SW.WriteLine("{0} {1} {2}", temp1, temp2, words[2]);
Console.WriteLine("{0} {1} {2}", temp1, temp2, words[2]);
S= SR.ReadLine();
}
Two possible issues:
It's not clear whether there's one file involved or two. You'll find it tricky to read from the same file you're writing to
You're not closing the writer, which means it won't get flushed. That may well be the issue - it would certainly explain the symptoms.
The second bullet is best handled with a using statement:
using (TextWriter writer = File.CreateText(...))
{
// Code here
} // writer will automatically be disposed here
You should do the same thing for the reader as well. It's less important in terms of data loss, but in general you should dispose anything which implements IDisposable, typically to allow resources to be cleaned up deterministically.
Related
I have a WPF Application which takes an input file path from user and then at the backend open the text file and try to read single character from the file.
fs = File.OpenRead(fileName);
var sr = new StreamReader(fs);
int c;
while ((c = sr.Read()) != -1)
{
Console.Write((char)c); //to check character read from file
try
{
frequencyMap.Add((char)c, 1);
}
catch
{
frequencyMap[(char)c] += 1;
}
}
Here frequencyMap is the dictionary in which character and it's frequency is stored.
This is one method no matter whatever i do the reading from file is always slow even if i try to read the whole text. On output window i see
Area selected is the part of input from the file.
Files upto 2KBs are fine but reading from files like 20KB really gives a hard time.
Now I read that using threads can solve this problem i just don't know how.
My Question is how can i read data from files fastly? if using threads is the solution then how to implement it?
i am new to this so kindly help me.
Thanks
Don't read it by character, read it for example by line, and process each string in a loop. Also Exception is not a way to check if the key exists in the Dictionary.
using (var sr = new StreamReader(fileName))
{
while (!sr.EndOfStream)
{
string s = sr.ReadLine();
Debug.WriteLine(s); //to check string read from file
foreach (char c in s)
{
if (frequencyMap.ContainsKey(c))
frequencyMap[c]++;
else
frequencyMap.Add(c, 1);
}
}
}
Firstly I hope the Console.WrieLine is purely test code. Writing to the console for every character will slow down your processing considerably.
Secondly, it appears from the screen shot you shared that your application is throwing a lot of exceptions. Throwing exceptions is not cheap either in a tight loop.
Thirdly I would recommend you profile your application (visual studio provides a profiler) to help you pin point where exactly your application is spending it’s time.
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;
}
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.
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).
We are having an issue with one server and it's utilization of the StreamWriter class. Has anyone experienced something similar to the issue below? If so, what was the solution to fix the issue?
using( StreamWriter logWriter = File.CreateText( logFileName ) )
{
for (int i = 0; i < 500; i++)
logWriter.WriteLine( "Process completed successfully." );
}
When writing out the file the following output is generated:
Process completed successfully.
... (497 more lines)
Process completed successfully.
Process completed s
Tried adding logWriter.Flush() before close without any help. The more lines of text I write out the more data loss occurs.
Had a very similar issue myself. I found that if I enabled AutoFlush before doing any writes to the stream and it started working as expected.
logWriter.AutoFlush = true;
sometimes even u call flush(), it just won't do the magic. becus Flush() will cause stream to write most of the data in stream except the last block of its buffer.
try
{
// ... write method
// i dont recommend use 'using' for unmanaged resource
}
finally
{
stream.Flush();
stream.Close();
stream.Dispose();
}
Cannot reproduce this.
Under normal conditions, this should not and will not fail.
Is this the actual code that fails ? The text "Process completed" suggests it's an extract.
Any threading involved?
Network drive or local?
etc.
This certainly appears to be a "flushing" problem to me, even though you say you added a call to Flush(). The problem may be that your StreamWriter is just a wrapper for an underlying FileStream object.
I don't typically use the File.CreateText method to create a stream for writing to a file; I usually create my own FileStream and then wrap it with a StreamWriter if desired. Regardless, I've run into situations where I've needed to call Flush on both the StreamWriter and the FileStream, so I imagine that is your problem.
Try adding the following code:
logWriter.Flush();
if (logWriter.BaseStream != null)
logWriter.BaseStream.Flush();
In my case, this is what I found with output file
Case 1: Without Flush() and Without Close()
Character Length = 23,371,776
Case 2: With Flush() and Without Close()
logWriter.flush()
Character Length = 23,371,201
Case 3: When propely closed
logWriter.Close()
Character Length = 23,375,887 (Required)
So, In order to get proper result, always need to close Writer instance.
I faced same problem
Following worked for me
using (StreamWriter tw = new StreamWriter(#"D:\Users\asbalach\Desktop\NaturalOrder\NatOrd.txt"))
{
tw.Write(abc.ToString());// + Environment.NewLine);
}
Using framework 4.6.1 and under heavy stress it still has this problem. I'm not sure why it does this, though i found a way to solve it very differently (which strengthens my feeling its indeed a .net bug).
In my case i tried write huge jagged arrays to disk (video caching).
Since the jagged array is quite large it had to do lot of repeated writes to store a large set of video frames, and despite they where uncompressed and each cache file got exact 1000 frames, the logged cash files had all different sizes.
I had the problem when i used this
//note, generateLogfileName is just a function to create a filename()
using (FileStream fs = new FileStream(generateLogfileName(), FileMode.OpenOrCreate))
{
using (StreamWriter sw = new StreamWriter(fs)
{
// do your stuff, but it will be unreliable
}
}
However when i provided it an Encoding type, all logged files got an equal size, and the problem was gone.
using (FileStream fs = new FileStream(generateLogfileName(), FileMode.OpenOrCreate))
{
using (StreamWriter sw = new StreamWriter(fs,Encoding.Unicode))
{
// all data written correctly, no data lost.
}
}
Note also read the file width the same encoding type!
This did the trick for me:
streamWriter.flush();