Search code examples
vb.nettext-fileslinestreamreaderstreamwriter

How to remove a blank line at the end of a text file after deleting a line?


I borrowed four lines of code from Stack Overflow, regarding removing a specific line from my text file in vb.net. Here they are:

 Dim delLine As Integer = 4
 Dim lines As List (Of String) = File.ReadAllLines ("c:\essai.librarie", Encoding.UTF8).ToList()
 lines.RemoveAt(delLine - 1)
 File.WriteAllLines("c:\outfile.librairie", lines, Encoding.UTF8)

It works fine but after deleting my line 4, I have an empty line in the last position of the file with the number 11! (see screenshot).

How to avoid this blank line?

enter image description here


Solution

  • File.WriteAllLines() add a line terminator - defined by the protected CoreNewLine Field in the base class, TextWriter, and returned by the TextWriter.NewLine virtual property - to each line it writes, including the last.

    You have different method to remove this terminator:

    Imports System.IO
    
    Dim sourcePath = Path.Combine([Source Path], "SomeFile.txt")
    Dim destinationPath = Path.Combine([Dstination Path], "SomeOtherFile.txt")
    Dim lineToDelete As Integer = 3
    
    Dim lines As List(Of String) = File.ReadAllLines(sourcePath, Encoding.UTF8).ToList()
    lines.RemoveAt(lineToDelete - 1)
    

    ▶ Simplified method, using File.WriteAllText() and rebuilding the Lines with String.Join():

    File.WriteAllText(destinationPath, String.Join(Environment.NewLine, lines), Encoding.UTF8)
    

    String.Join() doesn't add the separator to the last element in the array.

    ▶ Using a StreamWriter, looping the lines in the array to the one before the last, then change the line terminator, setting the TextWriter.NewLine property to a null String (not a null Char):

    Using stream As New StreamWriter(destinationPath, False, Encoding.UTF8)
        Dim index As Integer = 0
        For index = 0 To lines.Count - 2
            stream.WriteLine(lines(index))
        Next
        stream.NewLine = String.Empty
        ' index is set to the closure, lines.Count - 1
        stream.WriteLine(lines(index))
    End Using
    

    ▶ With File.WriteAllLines() - which will add the NewLine chars to the last line - then use a FileStream to remove the trailing chars by setting the length of the File, calling FileStream.SetLength():

    [Stream].Length = [Stream].Length - [Line terminator].Length`
    

    Setting the Stream.Length to a lower value truncates the file.

    File.WriteAllLines(destinationPath, lines, Encoding.UTF8)
    Using fStream As New FileStream(destinationPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
        fStream.SetLength(fStream.Length - Environment.NewLine.Length)
    End Using
    

    ▶ Using a FileStream, to write the bytes returned by Encoding.UTF8.GetBytes(), adding a line terminator to all lines except the last one:

    Using fStream As New FileStream(destinationPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
        Dim lastLine = lines.Count - 1
        For index As Integer = 0 To lines.Count - 1
            Dim line As String = lines(index) & If(index <> lastLine, Environment.NewLine, "")
            Dim bytes = Encoding.UTF8.GetBytes(line)
            fStream.Write(bytes, 0, bytes.Length)
        Next
    End Using
    

    And many more...

    As a note, you could simply ignore it, since when you read it back:

     lines = File.ReadAllLines(destinationPath, Encoding.UTF8).ToList()
    

    You won't find an empty line in the collection. But, of course, this depends on the specific use-case (what these files are for).