Search code examples
c#filestream

Why does FileStream sometimes ignore invisible characters?


I have two blocks of code that I've tried using for reading data out of a file-stream in C#. My overall goal here is to try and read each line of text into a list of strings, but they are all being read into a single string (when opened with read+write access together)...

I am noticing that the first block of code correctly reads in all of my carriage returns and line-feeds, and the other ignores them. I am not sure what is really going on here. I open up the streams in two different ways, but that shouldn't really matter right? Well, in any case here is the first block of code (that correctly reads-in my white-space characters):

StreamReader sr = null;
StreamWriter sw = null;
FileStream fs = null;
List<string> content = new List<string>();
List<string> actual = new List<string>();
string line = string.Empty;

// first, open up the file for reading
fs = File.OpenRead(path);
sr = new StreamReader(fs);

// read-in the entire file line-by-line
while(!string.IsNullOrEmpty((line = sr.ReadLine())))
{
    content.Add(line);
}
sr.Close();

Now, here is the block of code that ignores all of the white-space characters (i.e. line-feed, carriage-return) and reads my entire file in one line.

StreamReader sr = null;
StreamWriter sw = null;
FileStream fs = null;
List<string> content = new List<string>();
List<string> actual = new List<string>();
string line = string.Empty;

// first, open up the file for reading/writing
fs = File.Open(path, FileMode.Open);
sr = new StreamReader(fs);

// read-in the entire file line-by-line
while(!string.IsNullOrEmpty((line = sr.ReadLine())))
{
    content.Add(line);
}
sr.Close();

Why does Open cause all data to be read as a single line, and OpenRead works correctly (reads data as multiple lines)?

UPDATE 1

I have been asked to provide the text of the file that reproduces the problem. So here it is below (make sure that CR+LF is at the end of each line!! I am not sure if that will get pasted here!)

;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
;$$$$$$$$$                                                                $$$$$$$
;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
;
;
;

UPDATE 2

An exact block of code that reproduces the problem (using the text above for the file). In this case I am actually seeing the problem WITHOUT trying Open and only using OpenRead.

StreamReader sr = null;
StreamWriter sw = null;
FileStream fs = null;
List<string> content = new List<string>();
List<string> actual = new List<string>();
string line = string.Empty;

try
{
    // first, open up the file for reading/writing
    fs = File.OpenRead(path);
    sr = new StreamReader(fs);

    // read-in the entire file line-by-line
    while(!string.IsNullOrEmpty((line = sr.ReadLine())))
    {
        content.Add(line);
    }
    sr.Close();

    // now, erase the contents of the file
    File.WriteAllText(path, string.Empty);

    // make sure that the contents of the file have been erased
    fs = File.OpenRead(path);
    sr = new StreamReader(fs);
    if (!string.IsNullOrEmpty(line = sr.ReadLine()))
    {
        Trace.WriteLine("Failed: Could not erase the contents of the file.");
        Assert.Fail();
    }
    else
    {
        Trace.WriteLine("Passed: Successfully erased the contents of the file.");
    }

    // now, attempt to over-write the contents of the file
    fs.Close();
    fs = File.OpenWrite(path);
    sw = new StreamWriter(fs);
    foreach(var l in content)
    {
        sw.Write(l);
    }

    // read back the over-written contents of the file
    fs.Close();
    fs = File.OpenRead(path);
    sr = new StreamReader(fs);
    while (!string.IsNullOrEmpty((line = sr.ReadLine())))
    {
        actual.Add(line);
    }

    // make sure the contents of the file are correct
    if(content.SequenceEqual(actual))
    {
        Trace.WriteLine("Passed: The contents that were over-written are correct!");
    }
    else
    {
        Trace.WriteLine("Failed: The contents that were over-written are not correct!");
    }
}
finally
{
    // close out all the streams
    fs.Close();

    // finish-up with a message
    Trace.WriteLine("Finished running the overwrite-file test.");
}

Solution

  • Your new file generated by

    foreach(var l in content)
    {
        sw.Write(l);
    }
    

    does not contain end-of-line characters because end-of-line characters are not included in content.

    As @DaveKidder points out in this thread over here, the spec for StreamReader.ReadLine specifically says that the resulting line does not include end of line.

    When you do

    while(!string.IsNullOrEmpty((line = sr.ReadLine())))
    {
        content.Add(line);
    }
    sr.Close();
    

    You are losing end of line characters.