File IO using multiple writers in sequence

S

SurturZ

OK maybe I'm missing something obvious.

Look at the following code:
Using fs As New
FileStream(My.Computer.FileSystem.SpecialDirectories.Desktop & "\junk.txt",
FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Using sw As New StreamWriter(fs, System.Text.Encoding.ASCII)
sw.WriteLine("abc")
sw.WriteLine("def")
sw.WriteLine("ghi")
End Using
Using bw As New BinaryWriter(fs) 'throws an error right here
bw.Write(CByte(&H4A)) 'J
bw.Write(CByte(&H4B)) 'K
bw.Write(CByte(&H4C)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
bw.Write(CByte(&H4D)) 'J
bw.Write(CByte(&H4E)) 'K
bw.Write(CByte(&H4F)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
End Using
End Using

It crashes on the line indicated with a "Stream not writeable" exception.

I'm assuming the StreamWriter is closing the underlying FileStream when it
is disposed. Where's the Filestream.Open command??
 
K

kimiraikkonen

OK maybe I'm missing something obvious.

Look at the following code:
        Using fs As New
FileStream(My.Computer.FileSystem.SpecialDirectories.Desktop & "\junk.txt",
FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
            Using sw As New StreamWriter(fs, System.Text.Encoding.ASCII)
                sw.WriteLine("abc")
                sw.WriteLine("def")
                sw.WriteLine("ghi")
            End Using
            Using bw As New BinaryWriter(fs) 'throws an error right here
                bw.Write(CByte(&H4A)) 'J
                bw.Write(CByte(&H4B)) 'K
                bw.Write(CByte(&H4C)) 'L
                bw.Write(CByte(&HA)) '[CR]
                bw.Write(CByte(&HD)) '[LF]
                bw.Write(CByte(&H4D)) 'J
                bw.Write(CByte(&H4E)) 'K
                bw.Write(CByte(&H4F)) 'L
                bw.Write(CByte(&HA)) '[CR]
                bw.Write(CByte(&HD)) '[LF]
            End Using
        End Using

It crashes on the line indicated with a "Stream not writeable" exception.

I'm assuming the StreamWriter is closing the underlying FileStream when it
is disposed. Where's the Filestream.Open command??

Are you missing "FileMode.open" ?

Example:

Dim mystream as new
System.io.FileStream("yourfile.xxx",FileMode.Open,FileAccess.Write,......)
 
G

Guru

SurturZ said:
OK maybe I'm missing something obvious.

Look at the following code:
Using fs As New
FileStream(My.Computer.FileSystem.SpecialDirectories.Desktop &
"\junk.txt",
FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Using sw As New StreamWriter(fs, System.Text.Encoding.ASCII)
sw.WriteLine("abc")
sw.WriteLine("def")
sw.WriteLine("ghi")
End Using
Using bw As New BinaryWriter(fs) 'throws an error right here
bw.Write(CByte(&H4A)) 'J
bw.Write(CByte(&H4B)) 'K
bw.Write(CByte(&H4C)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
bw.Write(CByte(&H4D)) 'J
bw.Write(CByte(&H4E)) 'K
bw.Write(CByte(&H4F)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
End Using
End Using

It crashes on the line indicated with a "Stream not writeable" exception.

I'm assuming the StreamWriter is closing the underlying FileStream when it
is disposed. Where's the Filestream.Open command??

You whacking great ignoramus. Do you get paid for writing code? Learn about
scope, you less than useless spaghetti-jockey; the freaking streamwriter is
derefenced as soon as the Using sw block terminates. For crying out loud.
BWAHAHAHAHAH!
 
M

Michael D. Ober

Guru said:
SurturZ said:
OK maybe I'm missing something obvious.

Look at the following code:
Using fs As New
FileStream(My.Computer.FileSystem.SpecialDirectories.Desktop &
"\junk.txt",
FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Using sw As New StreamWriter(fs, System.Text.Encoding.ASCII)
sw.WriteLine("abc")
sw.WriteLine("def")
sw.WriteLine("ghi")
End Using
Using bw As New BinaryWriter(fs) 'throws an error right here
bw.Write(CByte(&H4A)) 'J
bw.Write(CByte(&H4B)) 'K
bw.Write(CByte(&H4C)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
bw.Write(CByte(&H4D)) 'J
bw.Write(CByte(&H4E)) 'K
bw.Write(CByte(&H4F)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
End Using
End Using

It crashes on the line indicated with a "Stream not writeable" exception.

I'm assuming the StreamWriter is closing the underlying FileStream when
it
is disposed. Where's the Filestream.Open command??

You whacking great ignoramus. Do you get paid for writing code? Learn
about scope, you less than useless spaghetti-jockey; the freaking
streamwriter is derefenced as soon as the Using sw block terminates. For
crying out loud. BWAHAHAHAHAH!


Maybe you should look at the code again - the BinaryWriter isn't based on
the StreamWriter, it's based on the FileStream.

fs is a FileStream
{
sw is a StreamWriter based on fs
{
}
bw is a BinaryWriter based on fs
{
}
}

I would look at the underlying stream for fs immediately after the disposal
of sw. I suspect the FileStream has been closed. I have run into this
situation in other cases with Dispose.

Mike Ober.
 
S

SurturZ

Yeah I'm 99.9% certain that what is happening is that the Dispose on the
StreamWriter (triggered by the End Using) is closing the Stream.

Which wouldn't be such a problem except that none of the Stream classes have
a .Open method. The only way to open a Stream seems to be in the constructor,
which makes it difficult to combine BinaryWriter and StreamWriter objects on
the same Stream.

Seems like a design flaw in System.IO to me.



--
David Streeter
Synchrotech Software
Sydney Australia


Michael D. Ober said:
Guru said:
SurturZ said:
OK maybe I'm missing something obvious.

Look at the following code:
Using fs As New
FileStream(My.Computer.FileSystem.SpecialDirectories.Desktop &
"\junk.txt",
FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Using sw As New StreamWriter(fs, System.Text.Encoding.ASCII)
sw.WriteLine("abc")
sw.WriteLine("def")
sw.WriteLine("ghi")
End Using
Using bw As New BinaryWriter(fs) 'throws an error right here
bw.Write(CByte(&H4A)) 'J
bw.Write(CByte(&H4B)) 'K
bw.Write(CByte(&H4C)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
bw.Write(CByte(&H4D)) 'J
bw.Write(CByte(&H4E)) 'K
bw.Write(CByte(&H4F)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
End Using
End Using

It crashes on the line indicated with a "Stream not writeable" exception.

I'm assuming the StreamWriter is closing the underlying FileStream when
it
is disposed. Where's the Filestream.Open command??

You whacking great ignoramus. Do you get paid for writing code? Learn
about scope, you less than useless spaghetti-jockey; the freaking
streamwriter is derefenced as soon as the Using sw block terminates. For
crying out loud. BWAHAHAHAHAH!


Maybe you should look at the code again - the BinaryWriter isn't based on
the StreamWriter, it's based on the FileStream.

fs is a FileStream
{
sw is a StreamWriter based on fs
{
}
bw is a BinaryWriter based on fs
{
}
}

I would look at the underlying stream for fs immediately after the disposal
of sw. I suspect the FileStream has been closed. I have run into this
situation in other cases with Dispose.

Mike Ober.
 
S

SurturZ

FileMode.Create "contains" FileMode.Open.

I've tried FileMode.Open and I get the same problem.
 
G

Guru

Michael D. Ober said:
Guru said:
SurturZ said:
OK maybe I'm missing something obvious.

Look at the following code:
Using fs As New
FileStream(My.Computer.FileSystem.SpecialDirectories.Desktop &
"\junk.txt",
FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Using sw As New StreamWriter(fs, System.Text.Encoding.ASCII)
sw.WriteLine("abc")
sw.WriteLine("def")
sw.WriteLine("ghi")
End Using
Using bw As New BinaryWriter(fs) 'throws an error right here
bw.Write(CByte(&H4A)) 'J
bw.Write(CByte(&H4B)) 'K
bw.Write(CByte(&H4C)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
bw.Write(CByte(&H4D)) 'J
bw.Write(CByte(&H4E)) 'K
bw.Write(CByte(&H4F)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
End Using
End Using

It crashes on the line indicated with a "Stream not writeable"
exception.

I'm assuming the StreamWriter is closing the underlying FileStream when
it
is disposed. Where's the Filestream.Open command??

You whacking great ignoramus. Do you get paid for writing code? Learn
about scope, you less than useless spaghetti-jockey; the freaking
streamwriter is derefenced as soon as the Using sw block terminates. For
crying out loud. BWAHAHAHAHAH!


Maybe you should look at the code again - the BinaryWriter isn't based on
the StreamWriter<BITCHSLAP>

Nitwit. The problem is, as I already asserted, caused by the Using sw
clause.

When the StreamWriter is disposed by the End Using on its head-long rush
into the total oblivion of Nothingness, it takes the FileStream along for
the ride; even Blind Bart can see that the BinaryWriter is trying to
reference the now obliterated FileStream.

Need proof? Yes? No? Don't know? Don't care? Considering suicide?
fs is a FileStream
{
sw is a StreamWriter based on fs
{
}
bw is a BinaryWriter based on fs
{
}
}

Maybe you should look at the code again - it is written in VB, not C.

That's your free cloo, clooboi. Don't take up coding for a living; you'll
starve.

The fix is simple. Change Using sw... into Dim sw... and remove the block
end. The intelligent reader, that would obviously not include you, will note
that the code now executes correctly; viz. the StreamWriter is not disposed,
therefore the FileStream is not disposed.

HTH, BegginerBoi.
 
B

Bill McCarthy

Hi David,

SurturZ said:
Yeah I'm 99.9% certain that what is happening is that the Dispose on the
StreamWriter (triggered by the End Using) is closing the Stream.

Which wouldn't be such a problem except that none of the Stream classes
have
a .Open method. The only way to open a Stream seems to be in the
constructor,
which makes it difficult to combine BinaryWriter and StreamWriter objects
on
the same Stream.

Seems like a design flaw in System.IO to me.

No. You need to question why the Using block in the first place. a Using
block, which equates to an IDisposable.Dispose is desgined to release
*unmanaged* resources . You migth also do toehr code cleanup in that, but
the primary goal is to release unmanaged resources in a timely fashion. And
in this case, the unmanaged resource is the underlying stream. He should
not be using using blocks on the writers, only on the filestream.
 
G

Guru

Bill McCarthy said:
Hi David,



No. You need to question why the Using block in the first place. a Using
block, which equates to an IDisposable.Dispose is desgined to release
*unmanaged* resources . You migth also do toehr code cleanup in that, but
the primary goal is to release unmanaged resources in a timely fashion.
And in this case, the unmanaged resource is the underlying stream. He
should not be using using blocks on the writers, only on the filestream.

BWAHAHAHAHAHAHA! Suck eggs, SurturZ and Michael D. Ober.
 
S

SurturZ

No. You need to question why the Using block in the first place. a Using
block, which equates to an IDisposable.Dispose is desgined to release
*unmanaged* resources . You migth also do toehr code cleanup in that, but
the primary goal is to release unmanaged resources in a timely fashion. And
in this case, the unmanaged resource is the underlying stream. He should
not be using using blocks on the writers, only on the filestream.

I have to disagree with you there.

In my opinion if a class implements IDisposable then you should always
Dispose it (or use Using) when you are finished. As a consumer of the Writer
classes, I have no idea what unmanaged resources they encapsulate - nor
should I have to, as part of the principle of encapsulation.

Now, probably, IDisposable is implemented on the Writer classes to support
the constructors that do not require a Stream (e.g. the file name ones).
Really, the Writer classes should be smart enough to remember which
constructor was used, whether the stream was open or closed at construction,
and clean up accordingly.

Imagine if I hand the Stream object to a series of methods that each contain
a Writer objects (in fact, this is what I am doing in my real world app). If
I do not Dispose the Writers, I don't know when GC will happen. So I will
have a bunch of Writers falling out of scope, which potentially might get
GCed while another Writer is writing to the Stream. If the Finalizer of the
first Writer class closes the stream at a random point during the second
Writer's operation, you have intermittent failures for no obvious reason and
a debugging nightmare of project failure proportions!

In any case I don't really care that the Writers are closing the stream. The
issue is that I cannot re-open it without a constructor.
 
B

Bill McCarthy

Hi David,

The scenario you map out below is non existent. StreamWriter and
BinaryWriter do NOT call finalize that disposes of the stream, only the
stream itself does that.

Calling IDisposable on *any* object without knowing it's origins or what
that does it very dangerous. You need to consider Shared (aka static)
instances, where obviously if you release the unmanaged resources you impact
on any other code that may be referencing that.

The simple rule of thumb is: if you didn't allocate it, don't release it.

In this example, opening another stream does not solve the problem as the
stream is closed, it's position reset. If you could re-open you'd end up
writing over the data you just wrote. And you also would not know if
something else had modified the underlying data in the meantime because
you've let go of any locks you may have had on the file as soon as you
closed it. The correct code for the OP's problem is to use a Using block
for the stream, not for the writers.
 
C

Cor Ligthert[MVP]

Surtur,

Your answer is a dead horse in the dotNet newsgroups.

Somebody started with your answer once to say that if there is something in
a class that you should use it.
Nobody told this from the methods from object which are in every class,
however the dispose seems to have for some its background in the needed
deconstruction in program languages before there was managed code.

The dispose is implemented by the component class which is inherrited by 20%
of the classes, which are however probably even the most used ones.

The dispose can be overriden to create your own disposing of unmanaged
resources.

Managed resources don't have to be disposed extra as that is done during the
Garbage Collection automaticly.

That is exactly why Net program languages are called managed code program
languages.

Cor
 
S

Stephany Young

We can all disagree and/or agree all we want.

It doesn't change the documented fact that calling close on a StreamWriter
object also closes it's underlying stream, (in this case the FileStream
object).

Also note that the documentation for StreamWriter explicity states that you
must call the Close method otherwise the integrity of the underlying stream
cannot be garaunteed. (Note that you are simply disposing of the objects and
not actuially calling Close.)

And, yes, you are correct that there is no Open method. Creating an instance
of such on object iswhat causes it to be 'opened'.

Now, whether or not the objects is question should or should not behave in
this way is a whole different debate and one that is not really appropriate
to this newsgroup.
 
M

Michael D. Ober

Guru said:
Michael D. Ober said:
Guru said:
OK maybe I'm missing something obvious.

Look at the following code:
Using fs As New
FileStream(My.Computer.FileSystem.SpecialDirectories.Desktop &
"\junk.txt",
FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
Using sw As New StreamWriter(fs, System.Text.Encoding.ASCII)
sw.WriteLine("abc")
sw.WriteLine("def")
sw.WriteLine("ghi")
End Using
Using bw As New BinaryWriter(fs) 'throws an error right here
bw.Write(CByte(&H4A)) 'J
bw.Write(CByte(&H4B)) 'K
bw.Write(CByte(&H4C)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
bw.Write(CByte(&H4D)) 'J
bw.Write(CByte(&H4E)) 'K
bw.Write(CByte(&H4F)) 'L
bw.Write(CByte(&HA)) '[CR]
bw.Write(CByte(&HD)) '[LF]
End Using
End Using

It crashes on the line indicated with a "Stream not writeable"
exception.

I'm assuming the StreamWriter is closing the underlying FileStream when
it
is disposed. Where's the Filestream.Open command??

--
David Streeter
Synchrotech Software
Sydney Australia

You whacking great ignoramus. Do you get paid for writing code? Learn
about scope, you less than useless spaghetti-jockey; the freaking
streamwriter is derefenced as soon as the Using sw block terminates. For
crying out loud. BWAHAHAHAHAH!


Maybe you should look at the code again - the BinaryWriter isn't based on
the StreamWriter<BITCHSLAP>

Nitwit. The problem is, as I already asserted, caused by the Using sw
clause.

When the StreamWriter is disposed by the End Using on its head-long rush
into the total oblivion of Nothingness, it takes the FileStream along for
the ride; even Blind Bart can see that the BinaryWriter is trying to
reference the now obliterated FileStream.

Need proof? Yes? No? Don't know? Don't care? Considering suicide?
fs is a FileStream
{
sw is a StreamWriter based on fs
{
}
bw is a BinaryWriter based on fs
{
}
}

Maybe you should look at the code again - it is written in VB, not C.

That's your free cloo, clooboi. Don't take up coding for a living; you'll
starve.

The fix is simple. Change Using sw... into Dim sw... and remove the block
end. The intelligent reader, that would obviously not include you, will
note that the code now executes correctly; viz. the StreamWriter is not
disposed, therefore the FileStream is not disposed.

HTH, BegginerBoi.

Guru,

You're an ass. My pseudo code was simply to show the lexical blocking of
the variables. Also, there is _NO_ documentation in the System.IO class
that I can find that says when a stream is derived from another stream that
closing or disposing the derived stream will close the original stream. As
for coding, I get paid very well to code in VMS Basic, C++, C#, VB 6, and
VB.Net, so I'm no slouch in the coding area.

By the way, since you are unable to post using your real name, you're not
only an ass but also a coward.

Mike Ober
 
M

Michael D. Ober

Bill McCarthy said:
Hi David,



No. You need to question why the Using block in the first place. a Using
block, which equates to an IDisposable.Dispose is desgined to release
*unmanaged* resources . You migth also do toehr code cleanup in that, but
the primary goal is to release unmanaged resources in a timely fashion.
And in this case, the unmanaged resource is the underlying stream. He
should not be using using blocks on the writers, only on the filestream.

Bill, this appears to be an undocumented "feature" that is contrary to most
other languages. The StreamWriter is derived from the FileStream. In most
languages, closing a derived stream doesn't close the source.

Mike.
 
B

Bill McCarthy

Hi Mike,

Michael D. Ober said:
Bill, this appears to be an undocumented "feature" that is contrary to
most other languages. The StreamWriter is derived from the FileStream.
In most languages, closing a derived stream doesn't close the source.

StreamWriter derives from TextWriter. Neither derives from a Stream, they
instead hold a reference to a stream, either one passed to it, or one it
creates internally. If you pass to it a stream, you don't call dispose
unless you want dispose called on the stream as well. If you passed to it a
filename, you should call dispose as there are no external references that
are at risk if you do.

Yes it probably does require a greater knowledge of the inner workings than
what the documents provide.
 
S

SurturZ

Well this code is more similar to the real world problem I'm having:

Imports System.IO

Module Module1
Sub Main()
Using s As New FileStream("C:\Temp\junk.tmp", FileMode.Create,
FileAccess.ReadWrite, FileShare.None)
Call WriteADog(s)
Call WriteADad(s)
Call WriteADog(s)
Call WriteADog(s)
Call WriteADad(s)
End Using
Console.WriteLine("Finished")
Console.ReadKey()
End Sub

Private Sub WriteADog(ByVal s As Stream)
Dim sw As New StreamWriter(s, System.Text.Encoding.ASCII)
sw.WriteLine("Dog")
End Sub

Public Sub WriteADad(ByVal s As Stream)
Dim bw As New BinaryWriter(s)
bw.Write(CByte(&HD))
bw.Write(CByte(&HA))
bw.Write(CByte(&HD))
End Sub
End Module

As you can see I have got rid of the Using blocks for the Writers.

Now, the code *does* work, but how do I now that Garbage Collection won't
fire in the middle of one of the subsequent Calls and close the stream? To
me, leaving the Writers undisposed is asking for an intermittent crash.

***brainwave***

I put in a GC.Collect thus:

Call WriteADog(s)
Call WriteADad(s)
Call WriteADog(s)
GC.Collect()
Call WriteADog(s)
Call WriteADad(s)

....and the code still works!

I guess the Finalizer doesn't close the underlying stream, while the Dispose
call does. Well, that is a solution to my problem. It requires me to know
undocumented behaviour of the Writer classes, though.

I still think it is bad design on Microsoft's part, but I guess you can
argue the toss on that.

I guess that is case closed. Thanks all.
 
S

SurturZ

I never said that Disposing the Writer disposes the underlying stream.
However, doing so CLOSES the underlying stream, which cannot be reopened. See
my reply elsewhere for a different code example which illustrates my problem
better.
 
B

Bill McCarthy

Hi Surturz,

Right, that is as I explained. BinaryWriter and StreamWriter don't even
register themselves for finalize, but a Stream does.
 
B

Bill McCarthy

Hi SurturZ,

<inline>

SurturZ said:
I never said that Disposing the Writer disposes the underlying stream.
However, doing so CLOSES the underlying stream, which cannot be reopened.

When Dispose is called on the Writer, it calls Close on the Stream which in
turn calls the stream's Dispose.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Reading EBCDIC Files. 9

Top