views:

202

answers:

1

Dear Stackoverflow community.

Development Platform: .NET 2.0 Platform: ASP.NET Spreadsheetgear: 2008 Language: C#

Is there a way to retrieve the Length in bytes of a workbook without copying it/saving it to another object?

I went through the documentation and several attempts with no success.

I am saving the workbook by using the SaveToStream method which is writing the workbook directly to the Page.Response.OutputStream which then is flushed out of the browser. But since the type of this object is Stream, this abstract class doesn't implement the Length property and casting it to a child class like MemoryStream will return null. In both cases the app will throw an Exception.

I need to capture the length in bytes in order to log it for performance review purposes in our application.

My purpose is to avoid copying that Stream to another object and if possible using only reference casts because we need to optimize the memory footprint of the module that exports to Excel spreadsheets in out application.

Thanks a lot in Advance. Einar.

+1  A: 

If the Length property is not implemented you can copy the entire stream to a MemoryStream, get the length of that, then send the stream from the memory stream.

The disadvantage of this is that you must wait for the entire copy to complete before you know the length, which breaks the streaming aspect. So instead, you can implement a new stream which counts the bytes as they pass through and keeps a running total which you can ask for at the end. Here's how you could implement it:

public class LengthLoggingStream : Stream
{
    private Stream stream;
    public long TotalBytesRead { get; private set; }
    public long TotalBytesWritten { get; private set; }

    public LengthLoggingStream(Stream stream)
    {
        this.stream = stream;
    }

    public override bool CanRead
    {
        get { return stream.CanRead; }
    }

    public override bool CanSeek
    {
        get { return stream.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return stream.CanWrite; }
    }

    public override void Flush()
    {
        stream.Flush();
    }

    public override long Length
    {
        get { return stream.Length; }
    }

    public override long Position
    {
        get
        {
            return stream.Position;
        }
        set
        {
            stream.Position = value;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        int bytesRead = stream.Read(buffer, offset, count);

        if (bytesRead > 0)
            TotalBytesRead += bytesRead;

        return bytesRead;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return stream.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        stream.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        TotalBytesWritten += count;

        stream.Write(buffer, offset, count);
    }
}

You can wrap the Response.OutputStream with this class, flush it, and then see how many bytes were written:

    LengthLoggingStream loggingStream = new LengthLoggingStream(Response.OutputStream);
    workbook.SaveToStream(loggingStream, /*other parameters */);
    log("Bytes written: " + loggingStream.TotalBytesWritten);
Mark Byers