Search code examples
c#parsingtextfieldparser

TextFieldParser Not Setting EndOfData field


I have a Validate(Stream inputStream) method. This method calls several other validation methods by passing the inputStream to each one. Each of these creates a new TextFieldParser and reads/validates the file.

When the first ValidateA(inputStream) is called, it works. But, when the 2nd ValidateB(inputStream) is called, the parser.EndOfData is true so, it does not read the fields.

I've tried to clean up the code to its simplest form.

public int Validate(Stream inputStream, ref List<string> errors)
{
    inputStream.Seek(0, SeekOrigin.Begin);  
    errors.AddRange(ValidateA(inputStream));

    // The 2nd time, the EndOfData is true, so it doesn't read the fields
    inputStream.Seek(0, SeekOrigin.Begin);
    errors.AddRange(ValidateB(inputStream));
...
}

private List<string> ValidateA(Stream inputStream)
{
    List<string> errors = new List<string>();
    // Works fine the first time
    using (var parser = new TextFieldParser(inputStream))
    {
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");
        parser.TrimWhiteSpace = true;
        int lineNumber = 0;

        while (!parser.EndOfData)
        {
            string[] fields = parser.ReadFields();
            // Processing....
        }

        if (lineNumber < 2)
            errors.Add(string.Format("There is no data in the file"));
    }
    return errors;
}

Here is where the problem occurs. The ValidateB method cannot process the file because the EndOfData field does not get reset.

private List<string> ValidateB(Stream inputStream)
{
    List<string> errors = new List<string>();
    using (var parser = new TextFieldParser(inputStream))
    {
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");
        parser.TrimWhiteSpace = true;
        int LineNumber = 0;
        while (!parser.EndOfData)
        {
          // Processing....
        }
    }

    return errors;
}       

Solution

  • The comment by @HansPassant is correct and lead me to change the way I was passing data around. Instead of passing a Stream around, I converted the MemoryStream to a byte[].

    Then, in the ValidateX(byte[] fileByteArray) method, I would create a new MemoryStream from the byte array and use it.

    Example:

    Stream stream = model.PostedFile.InputStream;
    MemoryStream memStream = new MemoryStream();
    stream.CopyTo(memStream);
    byte[] data = memStream.ToArray();
    var result = ValidateB(data);
    

    And then,

    private List<string> ValidateB(byte[] fileByteArray)
    {
        List<string> errors = new List<string>();
        MemoryStream ms = new MemoryStream(fileByteArray);
        ms.Position = 0;
        ms.Seek(0, SeekOrigin.Begin);
        using (var parser = new TextFieldParser(ms))
        {
            // Processing...
        }
    
    }
    

    This prevented problems with the EndOfData and trying to access a Stream that was closed.