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 numbernis a handle every laterPrint #nandClose #nrefers to — take it fromFreeFile, never hardcode#1. Two hardcoded#1files raiseerror 55,For Outputtruncates an existing file to empty, and a channel you neverClosestays 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 —
FreeFilehands you a channel number; catch it in a variable - Why hardcoding
#1raiseserror 55the 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
Openstatement is notWorkbooks.Open - Why a channel you never
Closelocks the file until Excel quits - The
On Errorcleanup 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 fileFor Outputdeletes 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 raiseserror 53 File not found, so guard withDirfirst.
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 number →
n = FreeFileonce, then use#neverywhere. A literal#1is a latenterror 55. - Know your mode →
For Appendgrows a file;For Outputwipes it first;For Inputneeds the file to exist. - The statement is not the method →
Openopens a text channel;Workbooks.Openopens a workbook. - Always Close → put
Close #nin anOn Errorhandler 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
