How to write the content of one stream into another stream in .net?
Asked Answered
U

7

42

I often run into the problem that I have one stream full of data and want to write everything of it into another stream.

All code-examples out there use a buffer in form of a byte-array.

Is there a more elegant way to this?

If not, what's the ideal size of the buffer. Which factors make up this value?

Unicuspid answered 24/9, 2008 at 19:25 Comment(0)
E
16

Regarding the ideal buffer size:

"When using the Read method, it is more efficient to use a buffer that is the same size as the internal buffer of the stream, where the internal buffer is set to your desired block size, and to always read less than the block size. If the size of the internal buffer was unspecified when the stream was constructed, its default size is 4 kilobytes (4096 bytes)."

Any stream-reading process will use Read(char buffer[], int index, count), which is the method this quote refers to.

http://msdn.microsoft.com/en-us/library/9kstw824.aspx (Under "Remarks").

Era answered 24/9, 2008 at 19:28 Comment(0)
U
74

In .NET 4.0 we finally got a Stream.CopyTo method! Yay!

Unicuspid answered 22/10, 2009 at 17:31 Comment(3)
I decompiled into the Stream.CopyTo method and it makes a call to "this.InternalCopyTo(destination, 81920);" The integer value being the buffer size. Seems like a crazy buffer size compared the standard 4k that most buffering techniques seem to employ. Can anyone comment on this?Gilbertina
Looks like that number is just trying to avoid using the large object heap, which would kick in slightly north of that amount.Thomasenathomasin
81920 almost looks like a typo but I suspect @JamesWorld is right, that they've chosen a value small enough to avoid the LOH, but big enough to be efficient for long streams and not too bad for short streams. If you do have a short stream then you can just use the overload of CopyTo() that accepts a buffer size.Meteoric
E
16

Regarding the ideal buffer size:

"When using the Read method, it is more efficient to use a buffer that is the same size as the internal buffer of the stream, where the internal buffer is set to your desired block size, and to always read less than the block size. If the size of the internal buffer was unspecified when the stream was constructed, its default size is 4 kilobytes (4096 bytes)."

Any stream-reading process will use Read(char buffer[], int index, count), which is the method this quote refers to.

http://msdn.microsoft.com/en-us/library/9kstw824.aspx (Under "Remarks").

Era answered 24/9, 2008 at 19:28 Comment(0)
O
8

I'm not sure if you can directly pipe one stream to another in .NET, but here's a method to do it with an intermediate byte buffer. The size of the buffer is arbitrary. The most efficient size will depend mostly on how much data you're transferring.

static void CopyStream(Stream input, Stream output){
    byte[] buffer = new byte[0x1000];
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0) 
        output.Write(buffer, 0, read);
}
Oosphere answered 24/9, 2008 at 19:32 Comment(1)
You could implement this as an extension method in C# 3.0, and have it as something like static void CopyTo(this Stream input, Stream output)...Hazaki
C
5

BufferedStream.CopyTo(Stream)

Candycecandystriped answered 19/5, 2010 at 16:34 Comment(0)
I
2

Read data in FileStream into a generic Stream

will probably have some directions to go in

Instantly answered 24/9, 2008 at 19:28 Comment(0)
E
2

I'm not aware of a more elegant way, than using a buffer.

But the size of a buffer can make a difference. Remember the issues about Vista's File Copy? It's reason was (basically) changing the buffer size. The changes are explained in this blogpost. You can learn the main factors from that post. However, this only applies for file copying. In applications probably you do a lot of memory copies, so in that case, the 4KB could be the best buffer size, as recommended by the .NET documentation.

Ebberta answered 3/10, 2008 at 11:22 Comment(0)
R
0

As some people have suggested, CopyTo and CopyToAsync should do the job. Here is an example of a TCP server that listens for external connections on port 30303 and pipes them with local port 8085 (written in .NET 5). Most streams should work the same, just pay attention if they are bi-directional or single-direction.

using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var externalConnectionListener = new TcpListener(IPAddress.Any, 30303);
            externalConnectionListener.Start();

            while (true)
            {
                var externalConnection = await externalConnectionListener.AcceptTcpClientAsync().ConfigureAwait(false);

                _ = Task.Factory.StartNew(async () =>
                  {
                      using NetworkStream externalConnectionStream = externalConnection.GetStream();
                      using TcpClient internalConnection = new TcpClient("127.0.0.1", 8085);
                      using NetworkStream internalConnectionStream = internalConnection.GetStream();

                      await Task.WhenAny(
                                externalConnectionStream.CopyToAsync(internalConnectionStream),
                                internalConnectionStream.CopyToAsync(externalConnectionStream)).ConfigureAwait(false);

                  });

            }
        }
    }
}
Regeneration answered 24/1, 2021 at 23:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.