0

I have a program that will write to a text file if recognition engine recognize any word in the keywords[]. However i want to check if the .txt file already contains (ts.Hours + ts.Minutes + ts.Seconds) , the current timespan already exists in the file. I do not want to write to it because i dont want an output with the same timespan like 5 times in a row.. so the way to fix this is to read the file first and check if that value already contains. However now i am stuck. I cant get around having the streamwriter inside the streamreader. is there anyway i can do this?

foreach (string x in keywords)
{
    using (var reader = new StreamReader(pathToTextFile))
    {      
        if (e.PartialResult.ToLower().Contains(x))
        {
            while ((line = reader.ReadLine()) != ts.Hours.ToString() + ts.Minutes.ToString() + ts.Seconds.ToString())
            {
                //reader.Close(); This line will allow me to write to the text file but when it loops up again it cant read from a closed reader. 
                using (StreamWriter sw = File.AppendText(string.Format(textBox1.Text + @"\SpyTrouble Logs\Keywords {0} {1}-{2}.txt", Environment.UserName, now.Day, now.Month)))
                {
                    string elapsedTime = string.Format("{0:00}:{1:00}:{2:00} Found keyword here", ts.Hours, ts.Minutes, ts.Seconds);
                    sw.WriteLine(elapsedTime);
                }
            }
        }
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194

2 Answers2

0

If I understood correctly, the entries in your log are always ordered, and you need to check if the latest entry is the one you need to check (to see if it the same as the one you want to enter).

How about storing just that time in a different file, say "lastFoundKeyWordAtTime.txt", and you rewrite this every time you write something new in the log which has a different date than the contents of this one file. It's not the most elegant solution, but it would get you "unstuck", focusing on the recognition engine. :)

If you insist on using just the logfile you currently have, you can use a single FileSteam to read and write:

  FileStream fileStream = new FileStream(filePath, 
                                         FileMode.OpenOrCreate, 
                                         FileAccess.ReadWrite, 
                                         FileShare.None);

Caution: use Stream.Position carefully if using this approach :)

UPDATE I might be misunderstanding the intent of the code. Can you just... not write if you already wrote a message for that timespan - I'm guessing that's what ts stands for? Something like:

       //declare this somewhere
       TimeSpan? lastWrite = null;

        foreach (string x in keywords)
        {
            if (e.PartialResult.ToLower().Contains(x))
            {
                if (!TimeSpan.Equals(lastWrite, ts) || lastWrite == null )
                {
                    using (StreamWriter sw = File.AppendText(string.Format(textBox1.Text + @"\SpyTrouble Logs\Keywords {0} {1}-{2}.txt", Environment.UserName, now.Day, now.Month)))
                    {
                        string elapsedTime = string.Format("{0:00}:{1:00}:{2:00} Found keyword here", ts.Hours, ts.Minutes, ts.Seconds);
                        lastWrite = ts;
                        sw.WriteLine(elapsedTime);
                    }
                }
            }
        }

Since I don't know the higher level logic, or what you want to achieve, I am unsure this code will be exactly what you need, but I hope you get my point! (For example, you can modify TimeSpan.Equals with conditions on TimeSpn.Hours, Minutes and Seconds)

Alexandru Clonțea
  • 1,746
  • 13
  • 23
  • Hey! in my code i have set the TimeSpan (ts) equal to stopwatch.elapsed; –  Mar 03 '18 at 00:58
  • the stopwatch.start(); is launched whenever the audio file is created to sync time correctly between the audio file and input that gets written into the .txt file –  Mar 03 '18 at 00:59
  • keywordWatch.Start(); // The stopwatch, ts = keywordWatch.Elapsed; // The timespan –  Mar 03 '18 at 01:00
  • If there is way to read the file and get the last line in the .txt file and check if that line is equal to ts.Hours + ts.Minutes + ts.Seconds and then write if the time is not equal to the current time span? –  Mar 03 '18 at 01:03
  • Aha! I understand now. It is possible to use a single file stream to read and write to the file, as I mentioned look for stream.Position samples. Or you can recreate another file every time a new line is written to your full log with just that last line! It would simplify things! I can try to write some code Mondayish, laptopless for now :) – Alexandru Clonțea Mar 03 '18 at 07:15
  • @Weird random: check https://dotnetfiddle.net/UXrEio written on iPhone will need some correcting for quote chars at least, but I hope you get the point! Seems highly inefficient to go this route to me, but if this is what you want, that is how it can be acheived! – Alexandru Clonțea Mar 03 '18 at 08:54
0

I believe i found the solution. May not be pretty, but works alright.

if (e.PartialResult.ToLower().Contains(x))
{
     string lastLine = File.ReadLines(pathToTextFile).Last();

     if(string.Format("{0:00}:{1:00}:{2:00} Found keyword here", ts.Hours, ts.Minutes, ts.Seconds) != lastLine)
     {
          using (StreamWriter sw = File.AppendText(string.Format(textBox1.Text + @"\SpyTrouble Logs\Keywords {0} {1}-{2}.txt", Environment.UserName, now.Day, now.Month)))
          {
              string elapsedTime = string.Format("{0:00}:{1:00}:{2:00} Found keyword here", ts.Hours, ts.Minutes, ts.Seconds);
              sw.WriteLine(elapsedTime);
          }
     }                     
}
Alexandru Clonțea
  • 1,746
  • 13
  • 23
  • If it works for you, that’s fine! Similar to what I suggested in my last comment, I had not noticed your answer. I still feel this is overkill (reading all lines all the time). – Alexandru Clonțea Mar 03 '18 at 09:24
  • Ye i know it is overkill, just dont know anyway around it :/ , i am up for more better solutions but this is what i can come up with –  Mar 03 '18 at 20:43
  • Did you look at dotnetfiddle.net/MwuVjK ? That can be modified to start from position = length -1, read 1 char and check if it's \r for the start of the last line, if not decrement the position by 2 – Alexandru Clonțea Mar 03 '18 at 20:56
  • instead of the section between line 12 and 21 – Alexandru Clonțea Mar 03 '18 at 20:58
  • Check https://social.msdn.microsoft.com/Forums/vstudio/en-US/ff6c07e2-9c36-4490-a989-f24dcff76145/how-to-read-only-the-last-line-out-of-a-very-big-text-file?forum=netfxbcl for inspiration! – Alexandru Clonțea Mar 03 '18 at 20:58
  • You can probably just use that function instead of File.ReadLines(pathToTextFile).Last(); – Alexandru Clonțea Mar 03 '18 at 21:00
  • But!!! you would need to share the FIleStream between the read and write operations! I.e. do not use File.AppendText, but a StreamWriter – Alexandru Clonțea Mar 03 '18 at 21:01
  • Oh nice thanks appriciate it! Do you know the way to implement it? seems a bit unclear to me :O –  Mar 03 '18 at 21:04
  • Also, isn't string.Format(textBox1.Text + @"\SpyTrouble Logs\Keywords {0} {1}-{2}.txt" the same as pathToTextFile? (otherwise I suspect you would not be having the problem, no? – Alexandru Clonțea Mar 03 '18 at 21:30