Skip to content
AgileLogics
6 min read

Working with Files

Prerequisites: Exception handling

File access goes through the System.IO namespace. The File class does most everyday jobs in one call:

Imports System.IO

Module Program
    Sub Main()
        File.WriteAllText("notes.txt", "first line" & vbLf & "second line" & vbLf)
        File.AppendAllText("notes.txt", "third line" & vbLf)

        Console.Write(File.ReadAllText("notes.txt"))

        Dim lines = File.ReadAllLines("notes.txt")
        Console.WriteLine($"{lines.Length} lines, last: {lines(lines.Length - 1)}")
        Console.WriteLine($"{File.Exists("notes.txt")} {File.Exists("missing.txt")}")
    End Sub
End Module
first line
second line
third line
3 lines, last: third line
True False

Imports System.IO at the top of the file lets you write File instead of System.IO.File. Relative paths are relative to the current directory; AppContext.BaseDirectory gives the folder the program runs from.

Reading and writing line by line

Imports System.IO

Module Program
    Sub Main()
        Using writer As New StreamWriter("log.txt")
            writer.WriteLine("started")
            writer.WriteLine("processing")
            writer.WriteLine("finished")
        End Using

        Using reader As New StreamReader("log.txt")
            Dim lineNumber = 0
            Do
                Dim line = reader.ReadLine()
                If line Is Nothing Then Exit Do
                lineNumber += 1
                Console.WriteLine($"{lineNumber}: {line}")
            Loop
        End Using
    End Sub
End Module
1: started
2: processing
3: finished

Using closes the file even if an exception occurs. For big files, File.ReadLines(path) (not ReadAllLines) reads lazily, one line at a time, so it works on files larger than memory.

Processing a CSV file

Imports System.IO

Module Program
    Sub Main()
        File.WriteAllLines("sales.csv", {
            "region,product,amount",
            "North,Tea,120",
            "South,Coffee,340",
            "North,Coffee,90"
        })

        Dim totals As New Dictionary(Of String, Integer)
        For Each line In File.ReadLines("sales.csv").Skip(1)
            Dim fields = line.Split(","c)
            Dim region = fields(0)
            Dim amount = Integer.Parse(fields(2))
            totals(region) = If(totals.ContainsKey(region), totals(region), 0) + amount
        Next

        For Each pair In totals
            Console.WriteLine($"{pair.Key}: {pair.Value}")
        Next
    End Sub
End Module
North: 210
South: 340

Simple Split breaks on quoted fields that contain commas; for real CSV data, Microsoft.VisualBasic.FileIO.TextFieldParser (built in) or the CsvHelper package handle quoting correctly.

Directories and paths

Imports System.IO

Module Program
    Sub Main()
        Directory.CreateDirectory("data/archive")
        File.WriteAllText(Path.Combine("data", "a.txt"), "A")
        File.WriteAllText(Path.Combine("data", "b.log"), "B")

        For Each f In Directory.GetFiles("data", "*.txt")
            Console.WriteLine(Path.GetFileName(f))
        Next

        Console.WriteLine(Path.GetExtension("report.final.csv"))
        Console.WriteLine(Path.GetFileNameWithoutExtension("report.final.csv"))
        Console.WriteLine(Path.ChangeExtension("photo.jpeg", ".jpg"))
        Console.WriteLine(Directory.GetDirectories("data").Length)
    End Sub
End Module
a.txt
.csv
report.final
photo.jpg
1

Use Path.Combine to build paths; it inserts the right separator for the operating system.

My.Computer.FileSystem

Windows Forms and older VB projects also have the My namespace, with shortcuts like My.Computer.FileSystem.ReadAllText(path) and My.Computer.FileSystem.CopyDirectory(source, target). In modern console projects, System.IO is the standard choice.

Common mistakes

  • Forgetting Using on streams — the file stays locked, and buffered text may never be written.
  • Not handling FileNotFoundException, UnauthorizedAccessException, and IOException for files you don't control.