Я использую метод ниже, чтобы удалить все пустые строки из файла, но это по какой-то причине добавить дополнительную строку в конце документа?

var tempFileName = Path.GetTempFileName();
try
{
    using (var streamReader = new StreamReader(file))
        using (var streamWriter = new StreamWriter(tempFileName))
    {
        string line;
        while ((line = streamReader.ReadLine()) != null)
        {
            if (!string.IsNullOrWhiteSpace(line))
                streamWriter.WriteLine(line);
        }
    }
    File.Copy(tempFileName, file, true);
}
finally
{
    File.Delete(tempFileName);
}

Как я могу это исправить?

Также можно ли сделать код короче?

c#
0
Bumba 7 Мар 2018 в 19:06

3 ответа

Лучший ответ

StreamWriter.WriteLine() всегда будет добавлять новую строку (возврат каретки, пара перевода строки) после строки, поэтому я предполагаю, что вы на это ссылаетесь. Для меня это нормально и лучше, когда за последней строкой следует новая строка. Но если ты не хочешь этого, не пиши.

Что касается длины вашего кода, он выглядит примерно для меня. Если кажется, что это отвлекает от логики вашей программы, просто переместите ее в свой собственный метод.

Для эффективности вы можете попробовать удалить исходный файл и затем переименовать временный файл. Это было бы более эффективно, чем копирование всего файла.

var tempFileName = Path.GetTempFileName();
try
{
    using (var streamReader = new StreamReader(file))
    using (var streamWriter = new StreamWriter(tempFileName))
    {
        string line;
        bool isFirstLine = true;
        while ((line = streamReader.ReadLine()) != null)
        {
            if (!string.IsNullOrWhiteSpace(line))
            {
                if (!isFirstLine)
                    streamWrite.WriteLine();
                streamWriter.Write(line);
                isFirstLine = false;
            }
        }
    }
    File.Delete(file);
    File.Move(tempFileName, file);
}
finally
{
    File.Delete(tempFileName);
}
1
Jonathan Wood 7 Мар 2018 в 16:29

Проблема в том, что StreamReader.ReadLine не возвращает сами разрывы строк, тем самым уничтожая информацию о разрыве строк. Другими словами, эти два входных файла:

File 1: A\r\nB\r\n
File 2: A\r\nB

Даст такой же вклад в ваш метод. Вы не можете определить таким образом, был ли окончательный разрыв строки или нет.

Если вам никогда не нужен окончательный разрыв строки, используйте Write вместо WriteLine и вручную добавляйте разрыв строки в начале вашего цикла в каждой итерации, кроме первой:

...
    string line;
    bool first = true;
    while ((line = streamReader.ReadLine()) != null)
    {
        if (string.IsNullOrWhiteSpace(line))
            continue;

        if (!first)
            streamWriter.WriteLine();

        streamWriter.Write(line);
        first = false;
    }
...
0
Heinzi 7 Мар 2018 в 16:32

Также можно ли сделать код короче?

Более эффективное решение другого ответа:

File.WriteAllLines(file, File.ReadLines("some/path").Where(l => !string.IsNullOrWhiteSpace(l)));

File.ReadLines() более эффективен, чем File.ReadAllLines(), потому что он позволяет запрашивать IEnumerable<string> без предварительного чтения всего этого в память.

Затем мы берем полученный IEnumerable<string> из нашего Where() метода и передаем его перегрузке в File.WriteAllLines(), который принимает IEnumerable<string> в качестве второго параметра.

1
maccettura 7 Мар 2018 в 16:18