-1

How to set a timeout for a StreamReader operation that reads a file?

I tried the accepted answer here but I'm getting the exception: "Timeouts are not supported on this stream."

This is the sample code:

using System.IO;

...

using (StreamReader reader = new StreamReader(@"C:\test.txt"))
{
    reader.BaseStream.ReadTimeout = 1;
    string result = reader.ReadToEnd();
    reader.Close();                
}

Thanks in advance.

AlexC
  • 383
  • 8
  • 17
  • What sort of project are you writing in? – IronAces Aug 18 '17 at 12:12
  • 4
    this is `FileStream` under that `StreamReader` which doesn't support Timeouts. If you're worrying about timeout reading local file, you probably have bad design of your application – Nino Aug 18 '17 at 12:13
  • 4
    You can consider `reader.ReadToEndAsync()` and then apply the solutions for waiting on a `Task` with a timeout, but this will not cancel the I/O operation itself. It may be enough if all you need is responsiveness and you don't mind that the operation is still continuing in the background. I know of no (simple) way to cancel file I/O in .NET. – Jeroen Mostert Aug 18 '17 at 12:14
  • 3
    Why do you need a timeout for a file read operation? If you just want to skip files that takes more than a fixed amount of time you should avoid the use of `ReadToEnd` and read the file in chunks. – Federico Dipuma Aug 18 '17 at 12:17
  • I want to check for the presence of a certain piece of text in a file: if (reader.Contains("some piece of text")){//perform certain action} But it's possible that the file is large, and that it may take a long time. To prevent that, want to set a timeout, so that if it is taking too much time, the search gets interrupted, and program continues doing other things, – AlexC Aug 18 '17 at 12:55
  • Try this approach: https://stackoverflow.com/questions/17436132/passing-a-filestream-to-wcf-throws-timeouts-are-not-supported-on-this-stream-e – Tagetek Aug 18 '17 at 12:56
  • 1
    @AlexC: then calling `.ReadToEnd` is a bad approach to begin with since it loads the whole file in memory -- call `ReadLine` in a loop that checks a flag on every iteration. Reading single lines should not require any timeout considerations. – Jeroen Mostert Aug 18 '17 at 13:26
  • @JeroenMostert , you're totally right. When I first wrote the code I haven't anticipated for the eventuality of the file being large. I changed it to check for the presence of the piece of text at each ReadLine(), and break the loop when or if it finds it. But that still doesn't solve me the problem of the long time it might take, and therefore the need of canceling the operation if it takes more than some seconds... – AlexC Aug 18 '17 at 15:02
  • 1
    Then wrap it in a `Task.Run` and check the `CancellationToken` in the loop. If `async`/`await` is too complicated, you can implement a poor man's timeout in the loop itself by checking the `.Elapsed` of a `Stopwatch`. The key thing is that if individual iterations of the loop are short, you can check termination conditions in each iteration. – Jeroen Mostert Aug 18 '17 at 15:06
  • @JeroenMostert besides changing the code to use ReadLine() within a loop (that made an huge difference in terms of speed - reading a 60MB file with ReadToEnd() the operation took more than 40 seconds; with ReadLine() within a loop it takes 0.3 seconds), I used a Stopwatch as you suggested. Thanks a lot for everyone's help. – AlexC Aug 19 '17 at 14:52

1 Answers1

0
using System.IO;
using System.Diagnostics;

...

using (StreamReader str = new StreamReader(@"C:\test.txt"))
{
    string holder;
    Stopwatch sw = new Stopwatch();
    sw.Start();
    while ((holder = str.ReadLine()) != null)
    {
        if (holder.Contains("some piece of text that I'm looking for"))
        {
            //do something
            break;
        }                    
        if (sw.ElapsedMilliseconds > 3000) { break; }
    }
    sw.Stop();
    str.Close();
}

Thanks a lot for everyone's help, and in particular to @JeroenMostert

AlexC
  • 383
  • 8
  • 17