How to create a file of an exact size
Every system has a command for it, and all three are below. They give you a file of exactly the right number of bytes - and for a lot of testing that is all you need. Every command on this page was run before it was published, on the system it belongs to.
The short answer
Windows: fsutil file createnew name 10485760. Linux:
dd if=/dev/zero of=name bs=1M count=10. macOS: mkfile 10m name.
Sizes are in bytes, and 10 MB counted the way your file manager counts is 10485760 of them.
Windows
fsutil, and a PowerShell version that needs nothing extra
fsutil ships with Windows. It takes the size in bytes, so work the
number out first - 10 MB is 10485760, 100 MB is 104857600, 1 GB is 1073741824.
fsutil file createnew test10mb.bin 10485760
Measured on Windows 11: it works from an ordinary prompt and does not need an elevated one, and the file comes out at exactly 10485760 bytes.
PowerShell can do the same without calling out to another program, and it understands units:
$file = New-Object System.IO.FileStream "test10mb.bin", Create, ReadWrite
$file.SetLength(10MB)
$file.Close()
10MB in PowerShell means 10485760 bytes, the same 1024 based counting Explorer uses,
so the two commands above produce the same size.
Linux
dd, truncate and fallocate, and the difference that catches people
dd is the one everybody knows. It really writes the bytes:
dd if=/dev/zero of=test10mb.bin bs=1M count=10
truncate is instant, and that is the catch. Measured on Alpine Linux, the file reports
10485760 bytes and occupies zero blocks - it is a sparse file.
Anything that reads it gets ten megabytes of zeros, but the disk never gave up the space:
truncate -s 10M test10mb.bin
That is fine for testing an upload limit and misleading for testing a disk quota.
fallocate is the one to reach for when the space has to be real:
fallocate -l 10M test10mb.bin
And when the content has to be incompressible, so an archiver cannot squeeze it back down:
head -c 10485760 /dev/urandom > test10mb.bin
macOS
mkfile, which is not sparse, and the two you already know
macOS ships mkfile. Measured on macOS 26.6.2: 10485760 bytes and 20480 blocks, so the
space is really allocated rather than promised:
mkfile 10m test10mb.bin
dd and truncate are both there too and behave as they do on Linux:
dd if=/dev/zero of=test10mb.bin bs=1m count=10
truncate -s 10M test10mb.bin
Where this stops working
A file of the right size is not a file of the right kind
All of the above give you a block of zeros. That is enough when the thing under test only looks at the size - an upload limit, a quota, a transfer. It stops being enough the moment anything opens the file.
Measured, and it is worth doing yourself: make a 2 MB file with fsutil, call it
photo.png, and hand it to an image library. Pillow answers
cannot identify image file. It is not a PNG. It never was - only the name said so.
That matters more than it sounds, because of which way the test then fails. Your upload endpoint rejects the file, your test goes green, and you conclude the size limit works. It did not reject it for the size. It rejected it because the bytes were not an image, and the rule you meant to test was never reached.
- a parser rejects it before any size rule is looked at
- a thumbnail step fails and the error you read is about the thumbnail
- an antivirus or content check refuses it for a third reason
- a viewer shows nothing, and nobody can tell whether that is the bug
The other way
A real file of that format, at exactly the size you asked for
This is what Testing Files Generator does. The file is a genuine one of its format - it opens in the software that owns it - and it is the exact number of bytes you asked for, to the byte:
tfg generate --format png --size 10mb --out ./fixtures
Ask for a size a format cannot reach and you get an error naming the floor and the reason for it, never a file of the wrong size. The formats page lists every format with the smallest file it can produce.
And a limit is three test cases rather than one, so the tool builds all three:
tfg generate --format pdf --boundary 10mb --out ./edges
That gives you 10485759, 10485760 and 10485761 bytes, and a manifest saying which of them your system should accept and which it should reject. The use cases page goes through that and four other jobs it is built for.
Free and open source, GPL-3.0. Nothing to sign up for. The binaries are not signed yet, so your system will warn you the first time - the release notes say what to expect.
So which should you use?
-
Use the system command
When nothing opens the file. Testing a size limit on an endpoint that checks the size first, a transfer, a quota, a disk full condition. It is one line and it is already installed.
-
Use a real generator
When anything parses, renders, imports or extracts the file - and when you need the same fixtures again tomorrow, on another machine, byte for byte.
Both are on this page because both are right some of the time. The mistake worth avoiding is using the first where the second is needed and reading the green test as proof.