473,545 Members | 2,073 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

writing an advanced filestream class

I am trying to create a stream that writes text to a file and:

- automatically creates a new file once the current file exceeds a
certain size
- makes it possible to be used by multiple threads and/or processes so
that multiple threads/processes can write to the same file (all threads
use the same instance of the stream, processes use a different instance
but still may point to the same file)

Could you point me in the correct direction how this would ideally be
implemented? What class should I drive from? How would I solve the
problem of multiple threads acessing the same stream or multiple
processes acess the same file?

Additional information that might be helpful: The stream will be used
with TraceListener (passed in the ctor of the TraceListener).

Oct 25 '06 #1
6 2162
First; note that my example only covers in-process (shared instance)
usage. For multi-process, you would presumably have to open/close the
file each time (possibly open it in shared write mode?) and use a Mutex
to sync access between all processes instead of a lock.

I also have "issues" with multiple processes writing in binary
(interleaved) to a single file; this could lead to partial characters
getting written to a file / files; e.g. a multi-byte character (which
means "most of them" unless you are limiting yourself to ASCII or a
single-byte codepage) gets it's first byte written; another
thread/process then adds some data; then the rest of the character is
written, possibly (disjointed) to the same file, possibly to a
different file. Either way you just knackered the encoding
good'n'proper. You would certainly be splitting up words / sentances.

Perhaps you should be performing this function at the StreamWriter /
TextWriter level, so that character (or better: strings) are written in
their entirety. You should also probably not split a string between
files (hard to read), so I'd allow it to overflow the capped limit as
needed, and then start a new file.

Unfortunately, when writing bytes at the stream level, you can't
guarantee that the current buffer represents complete characters (they
could legitimately a byte at a time), and without a *lot* of inspection
(and knowledge of encodings) it would be hard to keep integrity at the
stream level.

Anyway, "as presented", I would derive from Stream, and encapsulate
(contain) a FileStream; something like below; note the main code is the
Write method; this syncs all access to one thread at a time, and works
in a loop, writing as much as we can from the input buffer to each
successive file until we run out of data.

I haven't tested it at all - but something along those lines may be
close.

Again: If you need strings to remain intact in files, then you may want
to write a StreamWriter instead.

Marc
public class MultiFileStream : Stream
{
private Stream current;
private long totalLength;
private readonly string path;
private readonly int maxFileLength;
private int currentSpace;
private readonly object SyncLock = new object();
private int fileCounter;

public override bool CanRead {get { return false; }} // write-only
stream
public override bool CanSeek {get { return false; }} // write to
end only
public override bool CanWrite {get { return true; }}
public override void Flush()
{
if (current != null) current.Flush() ;
}

public override long Length {get { return totalLength; }}
public override long Position {
get { return totalLength; }
set { if (value != Position) throw new NotSupportedExc eption();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedExc eption();
}

public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedExc eption();
}

public override void SetLength(long value)
{
throw new NotSupportedExc eption();
}
protected override void Dispose(bool disposing)
{
if (disposing && current!=null)
{
current.Dispose ();
current = null;
}
base.Dispose(di sposing);
}
public override void Close()
{
if (current != null)
{
current.Close() ;
current = null;
}
base.Close();
}
public override void Write(byte[] buffer, int offset, int count)
{
lock (SyncLock)
{
while (count 0)
{
if (current == null || currentSpace == 0)
GetNextFile();
int writeThisPass = currentSpace < count ? currentSpace
: count;
current.Write(b uffer, offset, writeThisPass);
offset += writeThisPass;
count -= writeThisPass;
totalLength += writeThisPass;
}
}
}
private void GetNextFile()
{
if (current != null)
{
current.Close() ;
current = null;
}
while (File.Exists(Pa th.Combine(path , fileCounter.ToS tring())))
{
fileCounter++;
}
current = File.Create(Pat h.Combine(path,
fileCounter.ToS tring()));
fileCounter++;
currentSpace = maxFileLength;
}
public MultiFileStream (string path, int maxFileLength)
{
this.path = path;
this.maxFileLen gth = maxFileLength;
currentSpace = 0;

}
}

Oct 25 '06 #2
Forgot to add; for multi-process you must expect the size to change
without notice... so you'd probably drop both the current and
currentSpace fields and check them on the fly within the Write method.
Lots of opening and closing :-(

Alternatively - you could perhaps use remoting so all processes talk to
a single instance? Of course, then it has to remote the buffer...

Marc

Oct 25 '06 #3
On 25 Oct 2006 00:32:15 -0700, Marc Gravell wrote:
protected override void Dispose(bool disposing)
{
if (disposing && current!=null)
{
current.Dispose ();
current = null;
}
base.Dispose(di sposing);
}
Is a lock not needed in your Dispose method? What if this method is called
while another thread is creating a new stream? What if you dispose a stream
which is currently being written to?
Oct 25 '06 #4
Hi bonk,

As I understood from your requirement. There are two key problems you want
to solve.
1. Write to a file from multiple threads in the same process
2. Write to a file from multiple threads from multiple processes

The 1st problem can be solved quite easily. But the second problem may need
a re-thinking on your end to see if the approach itself is correct. I say so
because writing to the same file from multiple process without any mediating
process is difficult to manage. The main issue would be to synchronize the
access to the file by multiple processes so that the final file content won't
look as garbage data due to mix up of data from multiple processes. And
synchronizing actions from multiple processes will un-doubtedly and severly
degrade the performance of the application. Probably if you want to use the
same file name to write content then you could as well think of creating one
file per process with the following format.
<filename>_<pro cess-id>.<ext>

Anyway coming to the 1st problem (Write to a file from multiple threads in
the same process), here also you need to synchronize the writing of data to
your FileStream class from mutiple threads so that the data won't get
mixed-up. For this you can use lock on the FileStream object representing
your file inside your "Write" method. This technique uses locks and may still
pose performance issues. I have created some free C# libraries that can
assist in performing such operations without causing performance degradation.

Take a look at my recent library that I posted on CodeProject.com
http://www.codeproject.com/cs/librar...codeblocks.asp

Using this library you can implement the Write method of your FileStream as
shown below (only Pseudo code).

class AdvancedFileStr eam
{
int AdvancedFileStr eam::Write(byte[] data,....)
{
new async(delegate { this.InternalWr ite(data,...) }, _myThreadPool);
}

Sonic.Net.Threa dPool _myThreadPool = new Sonic.Net.Threa dPool(1,1);
}

You can use one ThreadPool (defined in my library) with one maximum and one
concurrent thread to do all writing of the data to the underlying file stream
represented by the AdvancedFileStr eam object. When multiple threads call into
Write the method will post a delegate to the _myThreadPool and will return
immediately to the calling code. Later the delegate will be executed on the
ThreadPool thread dedicated for this instance of the AdvancedFileStr eam
object. Since there is only one thread in this ThreadPool only one write
request will be handled at any given point of time thus protecting the
sequence of the writes to the file from multiple threads.

There is one issue that you need to be aware of in this approach. The byte
array supplied to the AdvancedFileStr eam::Write method should not be re-used
as we do not know when the ThreadPool thread gets a chance to perform the
actual write. There are ways to overcome it. I leave this to you as you can
figure out several options after reading my article on ACB.

Hope this helps.

--
Regards,
Aditya.P
"bonk" wrote:
I am trying to create a stream that writes text to a file and:

- automatically creates a new file once the current file exceeds a
certain size
- makes it possible to be used by multiple threads and/or processes so
that multiple threads/processes can write to the same file (all threads
use the same instance of the stream, processes use a different instance
but still may point to the same file)

Could you point me in the correct direction how this would ideally be
implemented? What class should I drive from? How would I solve the
problem of multiple threads acessing the same stream or multiple
processes acess the same file?

Additional information that might be helpful: The stream will be used
with TraceListener (passed in the ctor of the TraceListener).

Oct 25 '06 #5
Possibly so; however, I would be reasonably happy for it to go bang in
this scenario, as they *really* shouldn't be individually disposing
this stream, since they don't own it!

A better option would be for me to have included an "isDisposed " field,
and barf if *anything* happens after Dispose() [except Dispose()].

If the caller is using e.g. a Writer that rudely insists on
Dispose()ing the base stream when itself disposed, then this can be
managed; I believe Jon Skeet has a non-closing stream example in his
bag of tricks on his site.

Marc

Oct 25 '06 #6
Marc Gravell <ma**********@g mail.comwrote:
Possibly so; however, I would be reasonably happy for it to go bang in
this scenario, as they *really* shouldn't be individually disposing
this stream, since they don't own it!

A better option would be for me to have included an "isDisposed " field,
and barf if *anything* happens after Dispose() [except Dispose()].

If the caller is using e.g. a Writer that rudely insists on
Dispose()ing the base stream when itself disposed, then this can be
managed; I believe Jon Skeet has a non-closing stream example in his
bag of tricks on his site.
Yup - it's in MiscUtil:
http://www.pobox.com/~skeet/csharp/miscutil

--
Jon Skeet - <sk***@pobox.co m>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Oct 25 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
6122
by: Wilfried Hoermann | last post by:
Presumably a trivial question... I want to write trace information from a web service to a log file using the Trace Class. Is this possible without closing and opening the Trace in every single web method? Code: public Webservice() System.IO.FileStream ts = new System.IO.FileStream(traceFile,System.IO.FileMode.Append);...
3
2716
by: Joshua Russell | last post by:
Hi, I've got a program (see source below) that makes a file and fills it with random binary values (from 0 to 255). The source below works, however the program creates files at a rate of about 0.5MB per second. There is a serious performance issue with this program. There is a loop within the main loop that generates a buffer of 500 Bytes...
5
4320
by: Phil Kelly | last post by:
Hi I need to write the contents of a structure to a binary file - there is one string and 2 integers, but I can't seem to figure out how to write the data correctly. If I am simply writing text to a file there is no problem - that starts when I attempt to write the structure. Can someone help me out, please?
2
6772
by: simonc | last post by:
Is there an easy way of writing a number in 32 bit integer format into four bytes of a file? I am experimenting with FilePut but I can only make it work by defining a four byte array and doing some simple calculations to work out from my integer what the individual values of the four bytes have to be. Surely there must be a short cut to...
2
2400
by: Robert Reijntjes | last post by:
Hi, I need to read/write data from/to binary files that have an already defined. This means I can't define classes with the attribute. The files also have arrays with variable length. This means I can't use the StructLayout attribute like in here: http://www.builderau.com.au/architect/webservices/0,39024590,20277904,00.htm
8
10492
by: Raghu | last post by:
Is it possible to write a new file and after writing few bytes, is it possible to read from it from another file stream while write continues? Is there another steam for this type of operation? Thanks. Raghu/..
6
2049
by: bonk | last post by:
I am trying to create a stream that writes text to a file and: - automatically creates a new file once the current file exceeds a certain size - makes it possible to be used by multiple threads and/or processes so that multiple threads/processes can write to the same file (all threads use the same instance of the stream, processes use a...
2
2255
by: Author | last post by:
I am exploring the DeflateStream class as a practice. I thought it is fun to compress a text file and write it to a disk file. So I created the following method. If you don't bother reading the small code snippet, here is a summary of what I did: 1. Read the text content into a buffer through FileStream.Read. 2. Create a DeflateStream...
0
7659
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
7811
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7428
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
7760
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
5975
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
0
4949
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3455
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3444
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1019
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.