How to write data to buffer before writing on to disk in C#

2.8k views Asked by At

In C++ it is possible to write buffered i/o using setvbuf. how to achieve the same in C#. Is there any method available to write buffered i/o in C#

2

There are 2 answers

1
Marco On

As already commented there is a BufferedStream class

Adds a buffering layer to read and write operations on another stream. This class cannot be inherited.

Example code from MSDN:

Server side:

    // This is a Windows Sockets 2 error code. 
    const int WSAETIMEDOUT = 10060;

    Socket serverSocket;
    int bytesReceived, totalReceived = 0;
    byte[] receivedData = new byte[2000000];

    // Create random data to send to the client. 
    byte[] dataToSend = new byte[2000000];
    new Random().NextBytes(dataToSend);

    IPAddress ipAddress =
        Dns.Resolve(Dns.GetHostName()).AddressList[0];

    IPEndPoint ipEndpoint = new IPEndPoint(ipAddress, 1800);

    // Create a socket and listen for incoming connections. 
    using(Socket listenSocket = new Socket(
        AddressFamily.InterNetwork, SocketType.Stream, 
        ProtocolType.Tcp))
    {
        listenSocket.Bind(ipEndpoint);
        listenSocket.Listen(1);

        // Accept a connection and create a socket to handle it.
        serverSocket = listenSocket.Accept();
        Console.WriteLine("Server is connected.\n");
    }

    try
    {
        // Send data to the client.
        Console.Write("Sending data ... ");
        int bytesSent = serverSocket.Send(
            dataToSend, 0, dataToSend.Length, SocketFlags.None);
        Console.WriteLine("{0} bytes sent.\n", 
            bytesSent.ToString());

        // Set the timeout for receiving data to 2 seconds.
        serverSocket.SetSocketOption(SocketOptionLevel.Socket,
            SocketOptionName.ReceiveTimeout, 2000);

        // Receive data from the client.
        Console.Write("Receiving data ... ");
        try
        {
            do
            {
                bytesReceived = serverSocket.Receive(receivedData,
                    0, receivedData.Length, SocketFlags.None);
                totalReceived += bytesReceived;
            }
            while(bytesReceived != 0);
        }
        catch(SocketException e)
        {
            if(e.ErrorCode == WSAETIMEDOUT)
            {
                // Data was not received within the given time. 
                // Assume that the transmission has ended.
            }
            else
            {
                Console.WriteLine("{0}: {1}\n", 
                    e.GetType().Name, e.Message);
            }
        }
        finally
        {
            Console.WriteLine("{0} bytes received.\n",
                totalReceived.ToString());
        }
    }
    finally
    {
        serverSocket.Shutdown(SocketShutdown.Both);
        Console.WriteLine("Connection shut down.");
        serverSocket.Close();
    }
}

Client side:

public class Client
{
    const int dataArraySize    =   100;
    const int streamBufferSize =  1000;
    const int numberOfLoops    = 10000;

    static void Main(string[] args)
    {
        // Check that an argument was specified when the 
        // program was invoked. 
        if(args.Length == 0)
        {
            Console.WriteLine("Error: The name of the host computer" +
                " must be specified when the program is invoked.");
            return;
        }

        string remoteName = args[0];

        // Create the underlying socket and connect to the server.
        Socket clientSocket = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);

        clientSocket.Connect(new IPEndPoint(
            Dns.Resolve(remoteName).AddressList[0], 1800));

        Console.WriteLine("Client is connected.\n");

        // Create a NetworkStream that owns clientSocket and 
        // then create a BufferedStream on top of the NetworkStream. 
        // Both streams are disposed when execution exits the 
        // using statement. 
        using(Stream
            netStream = new NetworkStream(clientSocket, true),
            bufStream =
                  new BufferedStream(netStream, streamBufferSize))
        {
            // Check whether the underlying stream supports seeking.
            Console.WriteLine("NetworkStream {0} seeking.\n",
                bufStream.CanSeek ? "supports" : "does not support");

            // Send and receive data. 
            if(bufStream.CanWrite)
            {
                SendData(netStream, bufStream);
            }
            if(bufStream.CanRead)
            {
                ReceiveData(netStream, bufStream);
            }

            // When bufStream is closed, netStream is in turn 
            // closed, which in turn shuts down the connection 
            // and closes clientSocket.
            Console.WriteLine("\nShutting down the connection.");
            bufStream.Close();
        }
    }

    static void SendData(Stream netStream, Stream bufStream)
    {
        DateTime startTime;
        double networkTime, bufferedTime;

        // Create random data to send to the server. 
        byte[] dataToSend = new byte[dataArraySize];
        new Random().NextBytes(dataToSend);

        // Send the data using the NetworkStream.
        Console.WriteLine("Sending data using NetworkStream.");
        startTime = DateTime.Now;
        for(int i = 0; i < numberOfLoops; i++)
        {
            netStream.Write(dataToSend, 0, dataToSend.Length);
        }
        networkTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes sent in {1} seconds.\n",
            numberOfLoops * dataToSend.Length,
            networkTime.ToString("F1"));

        // Send the data using the BufferedStream.
        Console.WriteLine("Sending data using BufferedStream.");
        startTime = DateTime.Now;
        for(int i = 0; i < numberOfLoops; i++)
        {
            bufStream.Write(dataToSend, 0, dataToSend.Length);
        }
        bufStream.Flush();
        bufferedTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes sent in {1} seconds.\n",
            numberOfLoops * dataToSend.Length,
            bufferedTime.ToString("F1"));

        // Print the ratio of write times.
        Console.WriteLine("Sending data using the buffered " +
            "network stream was {0} {1} than using the network " +
            "stream alone.\n",
            (networkTime/bufferedTime).ToString("P0"),
            bufferedTime < networkTime ? "faster" : "slower");
    }

    static void ReceiveData(Stream netStream, Stream bufStream)
    {
        DateTime startTime;
        double networkTime, bufferedTime = 0;
        int bytesReceived = 0;
        byte[] receivedData = new byte[dataArraySize];

        // Receive data using the NetworkStream.
        Console.WriteLine("Receiving data using NetworkStream.");
        startTime = DateTime.Now;
        while(bytesReceived < numberOfLoops * receivedData.Length)
        {
            bytesReceived += netStream.Read(
                receivedData, 0, receivedData.Length);
        }
        networkTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes received in {1} seconds.\n",
            bytesReceived.ToString(),
            networkTime.ToString("F1"));

        // Receive data using the BufferedStream.
        Console.WriteLine("Receiving data using BufferedStream.");
        bytesReceived = 0;
        startTime = DateTime.Now;

        int numBytesToRead = receivedData.Length;

        while (numBytesToRead > 0)
        {
            // Read may return anything from 0 to numBytesToRead. 
            int n = bufStream.Read(receivedData,0, receivedData.Length);
            // The end of the file is reached. 
            if (n == 0)
                break;
            bytesReceived += n;
            numBytesToRead -= n;
        }

        bufferedTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes received in {1} seconds.\n",
            bytesReceived.ToString(),
            bufferedTime.ToString("F1"));

        // Print the ratio of read times.
        Console.WriteLine("Receiving data using the buffered network" +
            " stream was {0} {1} than using the network stream alone.",
            (networkTime/bufferedTime).ToString("P0"),
            bufferedTime < networkTime ? "faster" : "slower");
    }
}
0
xanatos On

Both FileStream and StreamWriter are internally buffered (they have a default buffer size of 4096 and 1024 bytes and constructors able to modify it).

The complex question would be how to write to a file without using a buffer :-) And note that, thanks to how they work, a StreamWriter that writes to a file will be double-buffered (the buffer of StreamWriter is independent of the one of FileStream). At least StreamWriter has an AutoFlush property that, when set to true, will flush after each write.