StreamReader from MemoryStream

10,276

Solution 1

You can initialize the MemoryStream from an array to begin with; then you don't have to write anything to a stream. Since Base64, by definition, is pure ascii text, you just convert the input string to bytes using ASCII encoding.

Though, if you're parsing CSV, there are better output options than just text read line by line. Technically, CSV format can contain line breaks inside fields, a feature supported by pretty much anything that writes CSV from spreadsheet files (like MS Excel). To support this, the line-by-line-reading approach is too simple. The .Net framework contains a native CSV reader, though, albeit hidden quite well in the Microsoft.VisualBasic classes. Since .Net is one framework, though, there's nothing preventing you from adding the reference and using it in C#. The class is TextFieldParser, from Microsoft.VisualBasic.FileIO.

public static List<String[]> ParseBase64Csv(String data, Encoding encoding, Char separator, Boolean ignoreEmptyLines)
{
    List<String[]> splitLines = new List<String[]>();
    using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(data)))
    using (FromBase64Transform tr = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces))
    using (CryptoStream cs = new CryptoStream(ms, tr, CryptoStreamMode.Read))
    using (StreamReader sr = new StreamReader(cs, encoding))
    using (TextFieldParser tfp = new TextFieldParser(sr))
    {
        tfp.TextFieldType = FieldType.Delimited;
        tfp.Delimiters = new String[] { separator.ToString() };
        while (true)
        {
            try
            {
                String[] curLine = tfp.ReadFields();
                if (curLine == null)
                    break;
                if (ignoreEmptyLines && (curLine.Length == 0 || curLine.All(x => String.IsNullOrEmpty(x) || String.IsNullOrEmpty(x.Trim()))))
                    continue;
                splitLines.Add(curLine);
            }
            catch (MalformedLineException mfle)
            {
                // do something with errors here.
            }
        }
    }
    return splitLines;
}

Solution 2

Do not bother converting to array, just reset memory stream position to 0 and then pass the memory stream to the reader and then read to end.

using (var ms = new MemoryStream()) {
    using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write)) {
        using (var tr = new StreamWriter(cs)) {
            tr.Write(data);
            tr.Flush();
            ms.Position = 0;
            using (var reader = new StreamReader(ms, Encoding.GetEncoding(1251), true)) {
                string csv = reader.ReadToEnd();
                //OR
                //while (!reader.EndOfStream) {
                //    var line = reader.ReadLine();
                //}
            }
        }
    }
}

Here is another option

byte[] input;
using (var ms = new MemoryStream()) {
    using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write)) {
        using (var tr = new StreamWriter(cs)) {
            tr.Write(data);
            tr.Flush();
            input = ms.ToArray();
        }
    }
}
using (var ms = new MemoryStream(input)) {
    using (var reader = new StreamReader(ms, Encoding.GetEncoding(1251), true)) {
        string csv = reader.ReadToEnd();
        //OR
        //while (!reader.EndOfStream) {
        //    var line = reader.ReadLine();
        //}
    }
}
Share:
10,276
shmnff
Author by

shmnff

Updated on June 19, 2022

Comments

  • shmnff
    shmnff about 2 years

    I'm decoding csv-file from base64 string:

    byte[] input;
    using (var ms = new MemoryStream())
    using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write))
    using (var tr = new StreamWriter(cs))
    {
        tr.Write(data);
        tr.Flush();
        input = ms.ToArray();
    }
    

    How to simply read decoded file by string? For example, similar way like how we can read a file from HttpWebResponse stream:

    using (StreamReader input = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(1251), true))
    {
        while (!input.EndOfStream)
        {
             string row = input.ReadLine();
        }
    }
    
  • Stevo
    Stevo about 5 years
    I had been reading into a MemoryStream, then needed to read from it and was constantly getting ReadLine() return null in my stream reader. The 'Yyou've got to be joking' moment I had when I saw you set the position to 0 in the memory stream... Can't beleive it doesn't default to reading from the beginning of the memory stream in the stream reader. Thank you so much for this answer!