Generate realistic test files, folders and fixtures — fast, and undoably.
Need 500 JSON files to point a parser at? A three-level directory tree to test a
file watcher? A 4 GB file to see what your uploader does with it? That is what
gofiles is for. It writes what you ask for, records what it wrote, and can
take it all back out again without touching anything else in the directory.
Zero dependencies — everything is the Go standard library.
go install github.com/NickName-AM/GoFiles@latest
Or from a clone:
git clone https://github.com/NickName-AM/GoFiles.git
cd GoFiles
go build -o gofiles .
Fill a directory with parseable JSON
gofiles gen -n 500 -size 4KB -content json -out ./testdata
Vary the sizes, to catch code that assumes they are uniform
gofiles gen -n 200 -size 1KB-5MB -content csv -out ./testdata
A big file, instantly
gofiles gen -n 1 -size 4GB -content zero -out ./testdata
Zero-filled files are allocated as holes, so this finishes immediately and uses
no disk until something writes into it. Pass -no-sparse to write every byte
for real.
A directory tree to walk
gofiles tree -depth 3 -dirs 4 -files 10 -out ./fixtures
4 + 16 + 64 directories, ten files in each.
Name files like the real thing
gofiles gen -n 30 -name 'app-{date}-{i:04}.log' -content log -size 64KB -out ./logs
# app-2026-08-05-0001.log ... app-2026-08-05-0030.log
Name files from a list you already have
gofiles gen -wordlist ./table-names.txt -content csv -size 10KB -out ./seed
Reproduce a run exactly
gofiles gen -n 50 -size 1KB-9KB -seed 42 -out ./a
gofiles gen -n 50 -size 1KB-9KB -seed 42 -out ./b # identical names and sizes
See the plan before committing to it
gofiles gen -n 5 -size 2KB -name 'log-{i:03}' -dry-run
Undo it
gofiles clean -out ./testdata
Every run drops a .gofiles.json in its output directory listing what it
created. gofiles clean reads that file and removes exactly those entries:
- Files you added yourself are never touched — they are not in the record.
- Files that changed since
gofileswrote them are kept and reported, on the assumption you meant to edit them.-forceremoves them anyway. - Directories are removed only once they are empty.
-dry-runshows what would go without removing anything.
$ gofiles clean -out ./testdata
[+] Removed 19 file(s) and 0 director(ies), 7.4 KiB reclaimed
[i] kept 1 file(s) modified since creation; pass -force to remove them anyway:
3BxdqScItK.csv
Pass -no-manifest to a run if you would rather it kept no record.
-content picks what goes inside each file. Every format fills the requested
size exactly, and the structured ones stay valid at any size.
| Format | Contents | Default extension |
|---|---|---|
random |
Random printable characters (the historical default) | txt |
lorem |
Wrapped lorem-ipsum prose | txt |
json |
An array of records — parses with any JSON reader | json |
csv |
A header plus rows, all with the same column count | csv |
log |
Timestamped logfmt lines | log |
binary |
Uniformly random bytes | bin |
zero |
NUL bytes, allocated sparsely | bin |
The extension follows the format unless you set -ext yourself.
Structured formats need a little room to be well-formed — a few hundred bytes — and say so plainly rather than emitting something that will not parse.
-name takes a template. Tokens:
| Token | Expands to |
|---|---|
{i} |
Position in the run, from 1 |
{i:04} |
The same, zero-padded to a width |
{rand} |
Random characters ({rand:12} for a width) |
{word} |
The next entry from -wordlist |
{date} |
2026-08-05 |
{time} |
150405 |
{datetime} |
20260805-150405 |
{ext} |
The extension in use |
{uuid} |
A random v4 UUID |
Write {{ and }} for literal braces. Without -name, files get random names
of -name-len characters.
Names never collide silently: files are created exclusively, random names are redrawn on a clash, and a pattern that cannot produce unique names fails with an explanation rather than overwriting.
-size accepts 512, 4KB, 10MiB, 1.5GB, and ranges like 1KB-5MB.
Decimal units are powers of 1000; the iB spellings are powers of 1024.
-seed fixes the random source. A given seed reproduces the same names, sizes
and contents, provided -workers is the same — the work is split across writers
up front, so the writer count is part of the recipe.
gofiles gen Create a batch of files
gofiles tree Create a nested directory fixture
gofiles clean Remove what a previous run created
gofiles version Print the version
gofiles help Show this help
Run gofiles <command> -h for a command's flags.
The pre-subcommand form still works and maps onto gen:
gofiles -n 100 -t 2 -e php # prints a deprecation notice, then runs
The old short flags remain as aliases: -n, -e, -t, -v, -fl, -dc, and
-dl (now a byte count handed to -size). New work should prefer gofiles gen
with the long names.
MIT — see LICENSE.