开发者

StreamReader ReadToEnd() returns empty string on first attempt

开发者 https://www.devze.com 2023-01-31 03:12 出处:网络
I know this question has been asked before on Stackoverflow, but could not find an explanation. When I try to read a string from a compressed byte array I get an empty string on the first attempt, on

I know this question has been asked before on Stackoverflow, but could not find an explanation.

When I try to read a string from a compressed byte array I get an empty string on the first attempt, on the second I succed and get the string.

Code example:

public static string Decompress(byte[] gzBuffer)
{
    if (gzBuffer == null)
        return null;
    using (var ms = new MemoryStream(gzBuffer))
    {
        using (var decompress = new GZipStream(ms, CompressionMode.Decompress))
        {
            using (var sr = new StreamReader(decompress, Encoding.UTF8))
            {
                string r开发者_如何学Cet = sr.ReadToEnd();
                // this is the extra check that is needed !?
                if (ret == "")
                    ret = sr.ReadToEnd();
                return ret;
            }
        }
    }
}

All suggestions are appreciated. - Victor Cassel


I found the bug. It was as Michael suggested in the compression routine. I missed to call Close() on the GZipStream.

public static byte[] Compress(string text)
{
    if (string.IsNullOrEmpty(text))
        return null;

    byte[] raw = Encoding.UTF8.GetBytes(text);
    using (var ms = new MemoryStream())
    {
        using (var compress = new GZipStream (ms, CompressionMode.Compress))
        {
            compress.Write(raw, 0, raw.Length);
            compress.Close();

            return ms.ToArray();
        }
    } 
}

What happened was that the data seemed to get saved in a bad state that required two calls to ReadToEnd() in the decompression routine later on to extract the same data. Very odd!


try adding ms.Position = 0 before string ret = sr.ReadToEnd();


Where is gzBuffer coming from? Did you also write the code that is producing the compressed data?

Perhaps the buffer data you have is invalid or somehow incomplete, or perhaps it consists of multiple deflate streams concatenated together.


I hope this helps.

For ByteArray:

static byte[] CompressToByte(string data)
{
    MemoryStream outstream = new MemoryStream();
    GZipStream compressionStream =
    new GZipStream(outstream, CompressionMode.Compress, true);
    StreamWriter writer = new StreamWriter(compressionStream);
    writer.Write(data);
    writer.Close();
    return StreamToByte(outstream);
}

static string Decompress(byte[] data)
{
    MemoryStream instream = new MemoryStream(data);
    GZipStream compressionStream =
    new GZipStream(instream, CompressionMode.Decompress);
    StreamReader reader = new StreamReader(compressionStream);
    string outtext = reader.ReadToEnd();
    reader.Close();
    return outtext;
}

public static byte[] StreamToByte(Stream stream)
{
    stream.Position = 0;
    byte[] buffer = new byte[128];
    using (MemoryStream ms = new MemoryStream())
    {
        while (true)
        {
            int read = stream.Read(buffer, 0, buffer.Length);
            if (!(read > 0))
                return ms.ToArray();
            ms.Write(buffer, 0, read);
        }
    }
}

You can replace if(!(read > 0)) with if(read <= 0). For some reason if(read <= 0) isn't displayed corret above.

For Stream:

static Stream CompressToStream(string data)
{
    MemoryStream outstream = new MemoryStream();
    GZipStream compressionStream =
    new GZipStream(outstream, CompressionMode.Compress, true);
    StreamWriter writer = new StreamWriter(compressionStream);
    writer.Write(data);
    writer.Close();
    return outstream;
}

static string Decompress(Stream data)
{
    data.Position = 0;
    GZipStream compressionStream =
    new GZipStream(data, CompressionMode.Decompress);
    StreamReader reader = new StreamReader(compressionStream);
    string outtext = reader.ReadToEnd();
    reader.Close();
    return outtext;
}


The MSDN Page on the function mentions the following:

If the current method throws an OutOfMemoryException, the reader's position in the underlying Stream object is advanced by the number of characters the method was able to read, but the characters already read into the internal ReadLine buffer are discarded. If you manipulate the position of the underlying stream after reading data into the buffer, the position of the underlying stream might not match the position of the internal buffer. To reset the internal buffer, call the DiscardBufferedData method; however, this method slows performance and should be called only when absolutely necessary.

Perhaps try calling DiscardBufferedData() before your ReadToEnd() and see what it does (I know you aren't getting the exception, but it's all I can think of...)?

0

精彩评论

暂无评论...
验证码 换一张
取 消