I did a bit of googling and found this lovely article with some C code to do exactly what you're asking on Windows. Here's that C code translated to ctypes
(written for readability):
import ctypes
import msvcrt
# https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
set_file_information = ctypes.windll.kernel32.SetFileInformationByHandle
class AllocationInfo(ctypes.Structure):
_fields_ = [('AllocationSize', ctypes.c_longlong)]
def allocate(file, length):
"""Tell the filesystem to preallocate `length` bytes on disk for the specified `file` without increasing the
file's length.
In other words, advise the filesystem that you intend to write at least `length` bytes to the file.
"""
allocation_info = AllocationInfo(length)
retval = set_file_information(ctypes.c_long(msvcrt.get_osfhandle(file.fileno())),
ctypes.c_long(5), # constant for FileAllocationInfo in the FILE_INFO_BY_HANDLE_CLASS enum
ctypes.pointer(allocation_info),
ctypes.sizeof(allocation_info)
)
if retval != 1:
raise OSError('SetFileInformationByHandle failed')
This will change the file's Size on disk: as shown in file explorer to the length you specify (plus a few kilobytes for metadata), but leave the Size: unchanged.
However, in the half hour I've spent googling, I've not found a way to do that on POSIX. fallocate()
actually does the exact opposite of what you're after: it sets the file's apparent length to the length you give it, but allocates it as a sparse extent on the disk, so writing to multiple files simultaneously will still result in fragmentation. Ironic, isn't it, that Windows has a file management feature that POSIX lacks?
I'd love nothing more than to be proven wrong, but I don't think it's possible.