Хобрук: Ваш путь к мастерству в программировании

Почему FileStream иногда игнорирует невидимые символы?

У меня есть два блока кода, которые я пытался использовать для чтения данных из файлового потока на С#. Моя общая цель здесь - попытаться прочитать каждую строку текста в список строк, но все они читаются в одну строку (при открытии с доступом для чтения и записи вместе)...

Я замечаю, что первый блок кода правильно читается во всех моих возвратах каретки и переводах строк, а другой их игнорирует. Я не уверен, что на самом деле происходит здесь. Я открываю потоки двумя разными способами, но это не должно иметь большого значения, верно? Что ж, в любом случае вот первый блок кода (который правильно читается в моих пробельных символах):

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();

Теперь вот блок кода, который игнорирует все символы пробела (например, перевод строки, возврат каретки) и читает весь мой файл в одной строке.

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();

Почему Open заставляет все данные считываться как одну строку, а OpenRead работает правильно (считывает данные как несколько строк)?

ОБНОВЛЕНИЕ 1

Меня попросили предоставить текст файла, который воспроизводит проблему. Итак, ниже (убедитесь, что CR+LF стоит в конце каждой строки!! Я не уверен, что это будет здесь вставлено!)

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

ОБНОВЛЕНИЕ 2

Точный блок кода, воспроизводящий проблему (используя приведенный выше текст для файла). В этом случае я на самом деле вижу проблему БЕЗ попытки Open и только с использованием 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.");
}
26.10.2016

  • FileStream не игнорирует невидимые символы, он не заботится о них. StreamReader — это класс, который читает текст и обрабатывает новые строки, но он их не игнорирует. Является ли файл одинаковым в обоих случаях? содержание такое же? Можете ли вы опубликовать код, который воспроизводит проблему? 26.10.2016
  • @PanagiotisKanavos Очевидно, у меня проблема с XY. Да, конечно могу, спасибо за вопрос. Надеюсь, это поможет разобраться, что здесь происходит. 26.10.2016
  • Я не могу воспроизвести проблему с этим кодом в .NET 4.6.2 в Windows. Обе части кода выдают строки по отдельности вплоть до первой пустой строки, как и следовало ожидать, поскольку и File.Open, и File.OpenRead являются простыми оболочками конструктора FileStream. 26.10.2016
  • @JeroenMostert подождите, опубликует код, который воспроизводится. Можете пока попробовать .NET 4.5? 26.10.2016
  • Ни на 4.5, ни на 4.6.2 такой проблемы нет. Это такая простая операция, что люди уже заметили бы. FileStream вообще не работает с символами, он просто возвращает байты. Это StreamReader, который интерпретирует байты как символы. Скорее всего, содержимое не то же самое, возможно, потому, что поток, который записывает файл, был оставлен открытым? 26.10.2016
  • @PanagiotisKanavos Я действительно не знаю, что еще добавить, нет больше кода, чем то, что я показываю здесь ... :( 26.10.2016
  • @StevieV добавьте код, который создает файл, затем читает его и приводит к ошибке. Не сам файл. Например, вы можете использовать один и тот же поток в обоих случаях, или один файл имеет кодировку UTF8, а другой — кодировку ASCII. Или что-нибудь. 26.10.2016
  • Кажется, что один открывает файл в двоичном режиме, а другой в текстовом режиме. В текстовом режиме разрывается после новой строки, в бинарном не проверяет. 26.10.2016
  • @PanagiotisKanavos Вы подняли интересный / ценный вопрос, однако этот файл набран вручную. Можно ли как-то изменить способ чтения файла? 26.10.2016
  • Нет, содержимое вашего файла также не имеет значения, и я тестировал как окончания CR/LF, так и окончания только LF. Почти невозможно представить, чтобы какая-либо ошибка в фреймворке или самом JIT-компиляторе могла вызвать такое поведение. Пожалуйста, попробуйте сами с точным кодом, который вы разместили в вопросе. 26.10.2016
  • @mcNets Вы видели/заметили разницу!!? 26.10.2016
  • В соответствии с результатом OpenRead() обнаруживает символ конца строки, но если вы читаете текстовые файлы, я бы использовал специфические для текста функции. msdn.microsoft.com /en-us/библиотека/ 26.10.2016
  • Вы не указываете Encoding, поэтому по умолчанию это будет UTF-8. Вы уверены, что файл в UTF-8? Если это какая-то национальная кодовая страница, отличная от ASCII, символы за пределами диапазона ASCII могут быть интерпретированы как многобайтовые символы, что нарушит все. Используйте правильную кодировку при чтении текстовых файлов. 26.10.2016
  • @mcNets нет двоичного режима, когда речь идет о потоках. FileStream, как и любой другой поток, имеет только методы чтения байтов. Если есть какая-либо разница, это будет из-за различий ASCII/UTF8/UNICODE между одним файлом и другим. 26.10.2016
  • @mcNets, это неправильный метод. Вы упомянули метод, который возвращает StreamReader, а не поток. ОП спрашивает о Open и OpenRead, оба из которых открывают FileStream. 26.10.2016
  • @PanagiotisKanavos Я думаю, ты что-то задумал. Как я могу попробовать разные кодировки при обработке этого файла? 26.10.2016
  • Ваша проблема должна быть где-то в другом месте. Это точный код, который создает проблему, или он сводится к минимуму? Вы использовали этот точный код из потока в новом проекте? Работает ли это одинаково на машинах, настроенных с разными локалями? Одинаково ли это работает с файлами, созданными в разных текстовых редакторах? 26.10.2016
  • Вы, случайно, не путаете File.Open с File.OpenText и т.п., что требует конфигурации StreamReader? Независимо от того, как вы открываете FileStream, вы получаете одни и те же данные. Но то, как вы получаете StreamReader, имеет гораздо большее значение. 26.10.2016
  • @StevieV, ты все-таки пытаешься прочитать тот же файл или нет? Поскольку изменение кодировки для одного и того же файла ничего не исправит — два потока одинаковы, и StreamReader использует одну и ту же кодировку по умолчанию. 26.10.2016
  • конструкторы StreamReader имеют перегрузки, которые принимают параметр Encoding. Класс также может определять кодировки Unicode, такие как UTF8, UTF16, из спецификации файла (если она существует). 26.10.2016
  • @JeroenMostert Если я запускаю именно этот код, я вообще не вижу проблемы. Я, должно быть, запутался, когда выкладывал это. Но я все еще вижу проблему, и у меня есть блок кода, который воспроизводит проблему. Позвольте мне опубликовать это. Извините за путаницу. 26.10.2016
  • Хорошо, обновлено, теперь вы, ребята, обязательно увидите проблему, я уверен. Попробуй это. 26.10.2016
  • @StevieV, твоя проблема не в процедуре открытия, а в обработке текста из файла. 26.10.2016

Ответы:


1

Ваш новый файл, сгенерированный

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

не содержит символов конца строки, поскольку символы конца строки не включены в content.

Как указывает @DaveKidder в этой ветке, спецификация для StreamReader.ReadLine конкретно говорит, что результирующая строка не включает конец строки.

Когда вы делаете

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

Вы теряете символы конца строки.

26.10.2016
  • Второй раз пытаюсь прочитать, что правда, но первый раз читаю, на примере работает. 26.10.2016
  • @StevieV В первый раз, когда вы читаете его, в строке с 15 по 17, вы читаете файл, который был создан с символами конца строки вне вашего приложения. Во второй раз, когда вы читаете его, в строке с 50 по 53, вы читаете файл, созданный вашим приложением без символов конца строки. Это не имеет ничего общего с методами чтения, когда вы читаете data1 в первый раз, когда вы читаете data2 во второй раз, байты data1 отличаются от data2. После строки 11 вы можете сохранить массив байтов, затем сделать то же самое после строки 48 и изучить их, это будут разные наборы байтов. 26.10.2016
  • Новые материалы

    Dall-E 2: недавние исследования показывают недостатки в искусстве, созданном искусственным интеллектом
    DALL-E 2 — это всеобщее внимание в индустрии искусственного интеллекта. Люди в списке ожидания пытаются заполучить продукт. Что это означает для развития креативной индустрии? О применении ИИ в..

    «Очень простой» эволюционный подход к обучению с подкреплением
    В прошлом семестре я посетил лекцию по обучению с подкреплением (RL) в моем университете. Честно говоря, я присоединился к нему официально, но я редко ходил на лекции, потому что в целом я нахожу..

    Освоение информационного поиска: создание интеллектуальных поисковых систем (глава 1)
    Глава 1. Поиск по ключевым словам: основы информационного поиска Справочная глава: «Оценка моделей поиска информации: подробное руководство по показателям производительности » Глава 1: «Поиск..

    Фишинг — Упаковано и зашифровано
    Будучи старшим ИТ-специалистом в небольшой фирме, я могу делать много разных вещей. Одна из этих вещей: специалист по кибербезопасности. Мне нравится это делать, потому что в настоящее время я..

    ВЫ РЕГРЕСС ЭТО?
    Чтобы понять, когда использовать регрессионный анализ, мы должны сначала понять, что именно он делает. Вот простой ответ, который появляется, когда вы используете Google: Регрессионный..

    Не зря же это называют интеллектом
    Стек — C#, Oracle Опыт — 4 года Работа — Разведывательный корпус Мне пора служить Может быть, я немного приукрашиваю себя, но там, где я живу, есть обязательная военная служба на 3..

    LeetCode Проблема 41. Первый пропущенный положительный результат
    LeetCode Проблема 41. Первый пропущенный положительный результат Учитывая несортированный массив целых чисел, найдите наименьшее пропущенное положительное целое число. Пример 1: Input:..