Reputation: 129
I recently run into an issue i wasn't able to find a solution for, that suits my needs. So I am trying to read a textfile line by line and check if the line is a specific string. If the file doesn't contain that string yet it should be written to the file. This is my current approche on this.
int i = 0;
using (var sw = new StreamWriter(this.filePath))
{
foreach (SimplePlaylist playlist in myPlaylists)
{
this.PlaylistTracks[i] = new List<PlaylistTrack>();
this.PlaylistTracks[i] = GetPlaylistTracks(playlist.Owner.Id, playlist.Id);
foreach (PlaylistTrack tr in this.PlaylistTracks[i])
{
string write = tr.Track.Name + " // " + string.Join(",", tr.Track.Artists.Select(source => source.Name)) + " // " + tr.Track.Album.Id;
string line = "";
bool found = false;
using (var sr = new StreamReader(this.filePath))
{
while ((line = sr.ReadLine()) != null)
{
if (line.Equals(write))
{
found = true;
break;
}
}
sr.Close();
}
if (!found)
{
sw.WriteLine(write);
}
}
i++;
}
sw.Close();
}
I've read about the problematic of reading and writing to a file at the same time, but i'm wondering if there is a way to achieve this. Any help is appreciated!
Upvotes: 3
Views: 5384
Reputation: 6035
Be aware that your current approach is very inefficient, requiring your code to read through the file from disk to search for every string.
You are not going to be able to read and write to the same file at the same time with two different streams like you are attempting to do. Here are a couple of strategies I suggest without knowing more:
If the file is small, load the while file into a List, and close the reader. You can then search the list for each string:
if(!list.Any(write))
// Write the string to the file
This will be pretty fast, as the list is in memory and the file is read only once (provided it is fairly small - say < 5000 lines, though it will also work on much larger files).
Another approach is to add the missing strings to a List and once you have identified all missing strings, close the reader and use the writer to add the strings. This will still be inefficient, because you are reading the through the file (which may be large) for every lookup, so
A refinement of this approach is to Read through the file and check each line against all the lines you might want to add. This means you only read the file once and run through your playlist collection for each line, which will be more efficient because it is in memory. Assuming you only have a few lines you are checking for - say for some new songs which you are adding, this will improve efficiency many times.
If the file gets really large you probably need some kind of index lookup approach.
Upvotes: 1
Reputation: 1764
Another option not suggested is to open the reader on the original file, a writer on a temp file. Read from the original write to the temp file and add the missing lines, then replace the original file with the temp file.
Upvotes: 1
Reputation:
Use a FileStream and use it for both, StreamReader and StreamWriter, here is an example of adding or changing lines of a textFile:
public static void ChangeOrAddLine(string filePath, string newLine, string oldLine = "")
{
using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read))
using (StreamReader sr = new StreamReader(fs))
using (StreamWriter sw = new StreamWriter(fs))
{
List<string> lines = sr.ReadToEnd().Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();
fs.Position = 0;
bool lineFound = false;
if (oldLine != "")
for (int i = 0; i < lines.Count; i++)
if (lines[i] == oldLine)
{
lines[i] = newLine;
lineFound = true;
break;
}
if (!lineFound)
lines.Add(newLine);
sw.Write(string.Join("\r\n", lines));
fs.SetLength(fs.Position);
}
}
FileAccess.ReadWrite opens the File for reading and writing
FileShare.Read let the be read by other programs as well
Upvotes: 4