Search code examples
c#asp.netstreamreader

Can I get StreamReader.EndOfStream to return false after the first time I read a file?


---short version: When I get to the while (!checkReader.EndOfStream) every time after the first, it says EndOfStream = true.

---more detail: A user will upload a file using an Ajax AsyncFileUpload control. I take that file, ensure it's a very specific format of csv that we use and spit it out into a GridView. This all works great the first time through: I get the file, parse it out, and it displays great.
But, if I call this same code again anytime during the user's session the StreamReader.EndOfStream = true.

For example, a user uploads a file and I spit it out into the GridView. Oops! User realizes there are headers... I have a checkbox available with an event handler that will call the method below to re-read the original file (it's stored in a session variable). User checks the box, event fires, method gets called, but my EndOfStream is now true.

I thought that using () would change that flag and I have tried adding checkReader.DiscardBufferedData just after the while loop below, but neither of those seem to have any affect.

What am I doing wrong?

 private void BuildDataFileGridView(bool hasHeaders)
{   
    //read import file from the session variable
    Stream theStream = SessionImportFileUpload.PostedFile.InputStream;
    theStream.Position = 0;

    StringBuilder sb = new StringBuilder();

    using (StreamReader checkReader = new StreamReader(theStream))
    {
        while (!checkReader.EndOfStream)
        {
            string line = checkReader.ReadLine();
            while (line.EndsWith(","))
            {
                line = line.Substring(0, line.Length - 1);
            }
            sb.AppendLine(line);
        }
    }

    using (TextReader reader = new StringReader(sb.ToString()))
    { 
        //read the file in and shove it out for the client
        using (CsvReader csv = new CsvReader(reader, hasHeaders, CsvReader.DefaultDelimiter))
        {
            sDataInputTable = new DataTable();

            try
            {
                //Load the DataTable with csv values  
                sDataInputTable.Load(csv);
            }
            catch
            {
                DisplayPopupMessage("ERROR: A problem was encountered");
            }

            //Copy only the first 10 rows into a temp table for display.  
            DataTable displayDataTable = sDataInputTable.Rows.Cast<System.Data.DataRow>().Take(10).CopyToDataTable();

            MyDataGridView.DataSource = displayDataTable;
            MyDataGridView.DataBind();
        }
    }
}

Edit: SessionImportFileUpload is the actual Ajax AsyncFileUpload control being stored as a session variable (this was already the case as a previous person wrote other stuff in that uses it).


Solution

  • You are storing the posted file stream in Session. This is not correct, because the stream is not the data, but rather the mechanism to read the data. The file is uploaded only once, during a single POST request, and you won't be able to read from the same stream again later. Usually you even cannot rewind the stream to re-read it.

    That's why I suggest to read the posted file stream only once and put the whole content into Session - this way the content will be reusable, and you'll be able to reprocess it as many times as you need.