views:

396

answers:

3

Hi,

In C#/.NET (on Windows) is there a way to read a "growing" file using a file stream? The length of the file will be very small when the filestream is opened, but the file will be being written to by another thread. If/when the filestream "catches up" to the other thread (i.e. when Read() returns 0 bytes read), I want to pause to allow the file to buffer a bit, then continue reading.

I don't really want to use a FilesystemWatcher and keep creating new file streams (as was suggested for log files), since this isn't a log file (it's a video file being encoded on the fly) and performance is an issue.

Thanks, Robert

+2  A: 

The way i solved this is using the DirectoryWatcher / FilesystemWatcher class, and when it triggers on the file you want you open a FileStream and read it to the end. And when im done reading i save the position of the reader, so next time the DirectoryWatcher / FilesystemWatcher triggers i open a stream set the position to where i was last time.

Calling FileStream.length is actualy very slow, i have had no performance issues with my solution ( I was im reading a "log" ranging from 10mb to 50 ish).

To me the solution i describe is very simple and easy to maintain, i would try it and profile it. I dont think your going to get any performance issues based on it. I do this when ppl are playing a multi threaded game, taking their entire CPU and nobody has complained that my parser is more demanding then the competing parsers.

EKS
The question specifically discounts using a watcher, because of performance concerns.
Vinay Sajip
Yea i noticed. added more to my reply regarding preformance.
EKS
You don't necessarily have to call FileStream.Length in the reader if all you are doing is reading as far as you can, then waiting for more data. What sort of latency are you seeing for the watcher triggering? Does that change depending on machine load?
Vinay Sajip
You're right; I haven't profiled it yet :-)
Robert Fraser
I'm going with this for now and if I need to do something else later, I will.
Robert Fraser
+5  A: 

You can do this, but you need to keep careful track of the file read and write positions using Stream.Seek and with appropriate synchronization between the threads. Typically you would use an EventWaitHandle or subclass thereof to do the synchronization for data, and you would also need to consider synchronization for the access to the FileStream object itself (probably via a lock statement).

Update: In answering this question I implemented something similar - a situation where a file was being downloaded in the background and also being uploaded at the same time. I used memory buffers, and posted a gist which has working code. (It's GPL but that might not matter for you - in any case you can use the principles to do your own thing.)

Vinay Sajip
Robert Fraser
+3  A: 

One other thing that might be useful is the FileStream class has a property on it called ReadTimeOut which is defined as:

Gets or sets a value, in miliseconds, that determines how long the stream will attempt to read before timing out. (inherited from Stream)

This could be useful in that when your reads catch up to your writes the thread performing the reads may pause while the write buffer gets flushed. It would certianly be worth writing a small test to see if this property would help your cause in any way.

Are the read and write operations happening on the same object? If so you could write your own abstractions over the file and then write cross thread communication code such that the thread that is performing the writes and notify the thread performing the reads when it is done so that the thread doing the reads knows when to stop reading when it reaches EOF.

Michael Mann