Writing System.IO.Stream derived from a DIME attachment to a file

  • Thread starter Scott, Killer of all Ninjas
  • Start date
S

Scott, Killer of all Ninjas

It seems incredulous to me that it is so difficult to write the
contents of a memory stream to a file. I'm certain that I'm missing
something simple.

I am retrieving a memory stream from a DIME attachment:

MyDimeService svc = new MyDimeService();
svc.CreateDimedImage();
if (svc.ResponseSoapContext.Attachments.Count == 1)
{
System.IO.Stream dimeStream =
svc.ResponseSoapContext.Attachments[0].Stream;
SaveStreamToFile(ref dimeStream);
}

In SaveStreamToFile I'm simply attempting to write the stream to a
file similar to the way it's done in the MSDN help:

private void SaveStreamToFile(ref System.IO.Stream pStreamToSave)
{
System.IO.FileStream fs = new
System.IO.FileStream(@"c:\images\new\new.gif",
System.IO.FileMode.Create);
System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fs);

for (int i=0; i<=pStreamToSave.Length; i++)
{
bw.Write(pStreamToSave.ReadByte());
}
bw.Close();
fs.Close();
}


Unfortunately, my file ends up four times the size of the original.

There has to be some standard method of creating a binary file from a
stream.

I've looked through the newsgroups and really haven't found anything
other than the method I'm doing.

Any help would be greatly appreciated.

Thanks...
 
J

Jon Skeet [C# MVP]

Scott said:
It seems incredulous to me that it is so difficult to write the
contents of a memory stream to a file. I'm certain that I'm missing
something simple.

I am retrieving a memory stream from a DIME attachment:

MyDimeService svc = new MyDimeService();
svc.CreateDimedImage();
if (svc.ResponseSoapContext.Attachments.Count == 1)
{
System.IO.Stream dimeStream =
svc.ResponseSoapContext.Attachments[0].Stream;
SaveStreamToFile(ref dimeStream);
}

Why are you passing the stream reference by reference?
In SaveStreamToFile I'm simply attempting to write the stream to a
file similar to the way it's done in the MSDN help:

private void SaveStreamToFile(ref System.IO.Stream pStreamToSave)
{
System.IO.FileStream fs = new
System.IO.FileStream(@"c:\images\new\new.gif",
System.IO.FileMode.Create);
System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fs);

for (int i=0; i<=pStreamToSave.Length; i++)
{
bw.Write(pStreamToSave.ReadByte());
}
bw.Close();
fs.Close();
}

Using a using block or two would be much better - and there's actually
no need for a BinaryWriter either.
Unfortunately, my file ends up four times the size of the original.

Yes - that's because you're calling BinaryWriter.Write(int) for each
byte of the original.
There has to be some standard method of creating a binary file from a
stream.

I've looked through the newsgroups and really haven't found anything
other than the method I'm doing.

The simplest way is to read chunks of data and write them out. It's
also more efficient than the above, it'll get the right length, it
doesn't require the Length property of the stream (which you may have
in this case, but not in others, such as with network streams), and it
also still closes the file stream even if an exception is thrown.
Here's some sample code:

using (FileStream stream = new FileStream (filename, FileMode.Create))
{
byte[] buffer = new byte[32768];
int chunkLength;

while((chunkLength=pStreamToSave.Read(buffer,0,buffer.Length)) > 0)
{
stream.Write (buffer, 0, chunkLength);
}
}
 
S

Scott, Killer of all Ninjas

Excellent.

Simple, straight forward. I was able to find something similar to
this shortly after I left my message, but there was a lot more code
involved.

That being said, I started by passing a .gif file through (for easy
verification of the destination file), and in either case, after I
create the file from the attachment, it is no longer a valid gif file.

I have tried it with the chunk size you had, with a much smaller one
(256), with a REALLY small one (1) and the one directly from the DIME
attachment (pDimgeAttachment.ChunkSize). None of this made any
difference in the destination file.

The file sizes vary slightly:

Source File Info: 124,742 bytes actual, 126,976 bytes on disk
Destination File Info: 123,961 bytes actual, 126,976 bytes on disk

This is how it comes across regardless of the chunk size

Any ideas? Thanks.

my new function:

private string SaveAttachment(
DimeAttachment pDimgeAttachment)
{

string sFileName = @"c:\images\new\" +
pDimgeAttachment.Id.ToString().Split(':')[1].ToString();

using (FileStream stream = new FileStream (sFileName,
FileMode.Create))
{
byte[] buffer = new byte[pDimeAttachment.ChunkSize];
int chunkLength;

while((chunkLength = pDimgeAttachment.Stream.Read(buffer, 0,
buffer.Length)) > 0)
stream.Write (buffer, 0, chunkLength);
}
return sFileName;
}
-
DM

Jon Skeet said:
Using a using block or two would be much better - and there's actually
no need for a BinaryWriter either.
Unfortunately, my file ends up four times the size of the original.

Yes - that's because you're calling BinaryWriter.Write(int) for each
byte of the original.
There has to be some standard method of creating a binary file from a
stream.

I've looked through the newsgroups and really haven't found anything
other than the method I'm doing.

The simplest way is to read chunks of data and write them out. It's
also more efficient than the above, it'll get the right length, it
doesn't require the Length property of the stream (which you may have
in this case, but not in others, such as with network streams), and it
also still closes the file stream even if an exception is thrown.
Here's some sample code:

using (FileStream stream = new FileStream (filename, FileMode.Create))
{
byte[] buffer = new byte[32768];
int chunkLength;

while((chunkLength=pStreamToSave.Read(buffer,0,buffer.Length)) > 0)
{
stream.Write (buffer, 0, chunkLength);
}
}
 
J

Jon Skeet [C# MVP]

Scott said:
Excellent.

Simple, straight forward. I was able to find something similar to
this shortly after I left my message, but there was a lot more code
involved.

That being said, I started by passing a .gif file through (for easy
verification of the destination file), and in either case, after I
create the file from the attachment, it is no longer a valid gif file.

I have tried it with the chunk size you had, with a much smaller one
(256), with a REALLY small one (1) and the one directly from the DIME
attachment (pDimgeAttachment.ChunkSize). None of this made any
difference in the destination file.

The file sizes vary slightly:

Source File Info: 124,742 bytes actual, 126,976 bytes on disk
Destination File Info: 123,961 bytes actual, 126,976 bytes on disk

This is how it comes across regardless of the chunk size

Any ideas? Thanks.

Hmm... no immediate ideas come to mind. Are you sure that the DIME
attachment has been created correctly to start with? (I'm afraid I have
very little knowledge of DIME myself.)

If you have a look at the original and final files with a binary
editor, does anything obvious strike you in terms of where they differ?
For instance, is there a load of header information at the start or
anything like that?
 
S

Scott, Killer of all Ninjas

Jon Skeet said:
Hmm... no immediate ideas come to mind. Are you sure that the DIME
attachment has been created correctly to start with? (I'm afraid I have
very little knowledge of DIME myself.)

If you have a look at the original and final files with a binary
editor, does anything obvious strike you in terms of where they differ?
For instance, is there a load of header information at the start or
anything like that?

I looked at the two files and the "new" file is actually completely
missing the GIF89a header. I'm not sure what the problem with it is.

I've actually looked into using BITS (Background Intelligent Transfer
Service) to do the file transfer since DIME has been such a hassle,
but BITS seems even more complicated, and the client has to have BITS
1.5 installed in order to do uploads.

Anyone with DIME Attachment experience know why my attachment is
missing the first ~496 bytes?
-
dm
 

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

Top