🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA FreeFile & the Open Statement in Excel — Get a File Number, Open a Text File (Not a Workbook)

|

VBA FreeFile & the Open Statement in Excel — Get a File Number, Open a Text File (Not a Workbook)

TL;DR — To read or write a text file with built-in VBA you open a numbered channel: Open path For Output As #n. The number n is a handle every later Print #n and Close #n refers to — take it from FreeFile, never hardcode #1. Two hardcoded #1 files raise error 55, For Output truncates an existing file to empty, and a channel you never Close stays locked until Excel quits.

Sub WriteReport()
    Dim n As Integer
    n = FreeFile                      ' get the next free channel number
    Open "C:\Reports\out.txt" For Output As #n
    Print #n, "Hello"                 ' every write refers to that number
    Close #n                          ' always release the channel
End Sub

Reaching a text file in VBA does not start with the text — it starts with a number. The Open statement attaches your file to a channel, and from that point on every write, read, and close names the channel by its number, not its path. FreeFile exists to hand you a number that is safe to use. Get that one idea right and the whole built-in file API stops being fiddly; get it wrong — by picking the number yourself — and you have written a bug that only shows up once a second file is open.

What you'll learn

  • The mental model — FreeFile hands you a channel number; catch it in a variable
  • Why hardcoding #1 raises error 55 the moment two files are open
  • The three modes — For Output (truncate), For Append (add), For Input (read) — and which one silently wipes data
  • Why the Open statement is not Workbooks.Open
  • Why a channel you never Close locks the file until Excel quits
  • The On Error cleanup pattern that always releases the channel

The mental model: FreeFile hands you a channel number

The key insight is that built-in file I/O works through a channel, and the channel is identified by a small integer. Open ... As #n binds your file to number n; after that, Print #n, Input #n, and Close #n all talk to that file by number. The path appears exactly once — in the Open.

FreeFile returns the next channel number that is not currently in use. The rule that trips people up: store it before you open. Until a file is actually open on that number, FreeFile keeps returning the same value, so you must capture it once and reuse the variable:

Dim n As Integer
n = FreeFile                 ' capture it ONCE
Open "C:\data.txt" For Output As #n
' ... use #n ...
Close #n

Think of FreeFile as "give me a free channel" and n as the ticket. You would never staple two customers to the same ticket number; FreeFile is how you avoid doing that with files.

Why hardcoding #1 raises error 55

The everyday shortcut — Open path For Output As #1 — works perfectly in a demo, because only one file is ever open. It becomes a bug the instant a routine opens a second file (or calls another routine that does) while #1 is still open:

Open "a.txt" For Output As #1
Open "b.txt" For Output As #1    ' error 55 — "File already open"

error 55 means "that channel number is already in use." Nested macros, a logger that writes while your main routine has its own file open, a loop that forgets to close — all of them collide on the hardcoded number. FreeFile removes the whole class of bug because it never hands out a number that is taken:

Dim nA As Integer, nB As Integer
nA = FreeFile: Open "a.txt" For Output As #nA
nB = FreeFile: Open "b.txt" For Output As #nB    ' a different, free number

The moment you type a literal #1, you have decided the channel number by hand — which is exactly the decision FreeFile was built to make for you.

The three modes: Output truncates, Append adds, Input reads

Open ... For <mode> takes one of three modes for sequential text, and choosing the wrong one is the single most common way to lose data:

  • For Output — creates the file if it is missing, and truncates it to empty if it already exists. Opening an existing file For Output deletes its contents before you write a single line. This is the classic "my log file keeps getting wiped" bug.
  • For Append — creates the file if missing, otherwise adds to the end. This is what you want for a running log.
  • For Input — opens an existing file for reading; a missing file raises error 53 File not found, so guard with Dir first.
Open logPath For Append As #n     ' keeps history
Open logPath For Output As #n     ' SAME file — wipes history first

The two write modes look almost identical and do opposite things to an existing file. If a file should grow over time, it is always For Append; For Output is for a file you intend to rewrite from scratch every run.

The Open statement is not Workbooks.Open

Open is a statement that attaches a text file to a channel number. It has nothing to do with loading a spreadsheet. Opening an .xlsx with Open ... For Input gives you the raw bytes of a zip container, not a workbook you can read cells from:

Open "Book.xlsx" For Input As #n   ' raw bytes — NOT a usable workbook

To load an actual workbook you use the method Workbooks.Open, which returns a Workbook object with sheets and cells. The naming collision is a frequent source of confusion: Open (the statement) is for text channels; Workbooks.Open (the method) is for workbooks. If your file is a .csv you want as rows and columns, opening it as a workbook is usually simpler than parsing the text yourself.

Why an unclosed channel locks the file

Every Open must be paired with a Close. A channel you never close keeps the file locked — you cannot re-open it, delete it with Kill, or open it in Excel — until the workbook or Excel itself shuts down. The trap is an error between Open and Close: the error jumps past your Close line, and the channel leaks.

The robust shape puts the Close in an error handler so it runs whether the write succeeds or fails:

Sub SafeWrite(ByVal path As String, ByVal text As String)
    Dim n As Integer
    n = FreeFile
    On Error GoTo Cleanup
    Open path For Output As #n
    Print #n, text
Cleanup:
    Close #n                 ' runs on success AND on error
End Sub

Close #n releases one channel; a bare Close with no number closes every open file at once, which is a useful last resort but a blunt one. See On Error for the full pattern of guaranteed cleanup.

The honest verdict: FreeFile, a variable, and a guaranteed Close

The built-in Open/Close API is fast and dependency-free — it just asks you to respect the channel. Four rules cover it:

  • Never hardcode the numbern = FreeFile once, then use #n everywhere. A literal #1 is a latent error 55.
  • Know your modeFor Append grows a file; For Output wipes it first; For Input needs the file to exist.
  • The statement is not the methodOpen opens a text channel; Workbooks.Open opens a workbook.
  • Always Close → put Close #n in an On Error handler so a mid-write failure cannot leave the file locked.

The single habit that prevents most file bugs is the first line of every routine: n = FreeFile. Pick the number by hand and you have chosen the one thing VBA was ready to choose correctly for you.

How ExcelMaster helps

Writing a text file safely means taking the channel number from FreeFile instead of hardcoding #1, choosing For Append over For Output when history must survive, and guaranteeing a Close even when a write fails — three details around a statement that looks like it should just open a file.

ExcelMaster writes the file-handling routine that will not leak or wipe. Describe the job — "append each run to a log next to the workbook," or "export this range to a text file" — and it produces the FreeFile capture, the right mode, and the guaranteed Close, anchored to ThisWorkbook.Path. You describe the file you want; it writes the code that opens the channel correctly and always releases it.

Frequently asked questions

What does FreeFile do in VBA?

FreeFile returns the next file-channel number that is not currently in use, so you can open a file without guessing a number. Capture it in a variable before you open the file — n = FreeFile: Open path For Output As #n — because FreeFile keeps returning the same value until a file is actually open on that number. Using FreeFile instead of a hardcoded #1 prevents error 55 File already open when more than one file is open at once.

How do I open a text file in VBA?

Use the Open statement with a mode and a channel number: Open "C:\data.txt" For Input As #n, where n = FreeFile. Use For Output to create or overwrite, For Append to add to the end, and For Input to read. Always pair it with Close #n when you are done. Note this opens a text channel; to load a spreadsheet use Workbooks.Open instead.

Why does VBA give error 55 File already open?

Because the channel number you passed to Open is already in use — almost always because the code hardcodes #1 and a second Open reuses it before the first is closed. Replace every literal number with n = FreeFile captured into its own variable, and close each channel with Close #n as soon as you finish, so numbers are never double-booked.

Does For Output delete the existing file in VBA?

Yes. Opening an existing file For Output truncates it to empty before you write anything — its old contents are gone. If you want to keep the previous contents and add to them, open the file For Append instead. For Output is only for files you intend to rewrite from scratch on every run.

What happens if I do not close a file in VBA?

The file stays locked on its channel — you cannot re-open it, delete it with Kill, or open it in Excel — until the workbook or Excel quits. To avoid a leak when an error interrupts a write, put Close #n in an On Error cleanup section so it runs whether the write succeeds or fails.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-08-25.

Related guides: VBA Print # vs Write # · VBA Read Text File · VBA Open Workbook · VBA FileSystemObject · VBA On Error