fdatasync
Flushes a stream's buffered data to physical storage without syncing file metadata.
fdatasync(resource $stream): bool- Added in PHP 8.1.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$stream | resource | An open file pointer from fopen() or fsockopen(), not yet closed by fclose(). |
Return value
boolReturns true on success or false on failure.
Errors
Returns false on failure; a value that is not a valid open stream raises a TypeError.
Changelog
- PHP 8.1.0Function introduced.
There are two layers of buffering between fwrite() and the platter. fflush() pushes PHP's userland buffer into the kernel; fdatasync() then tells the kernel to push its page cache onto the physical device. It includes the fflush() step, so you do not need to call both.
The difference from fsync() is what it skips: fdatasync() syncs the file's contents but not metadata that is not required to read them back — the modification timestamp, for example. When a write only changes bytes inside an already-allocated region, that saves a second seek to the inode and is measurably faster in write-heavy loops.
When to reach for it
- Append-only logs and write-ahead journals where each record must survive a power loss but the mtime does not matter.
- Overwriting fixed-size records in place — a database page file, a slot-based cache.
- Any hot loop where
fsync()proved too slow but you still need durability.
What trips people up
Metadata includes the file size. If your write extended the file, the new length is metadata, and skipping it can leave a crash-recovered file that is correct but truncated. When a write grows the file and you need the growth to survive, use fsync().
On Windows there is no distinction: fdatasync() is aliased to fsync(). And neither function syncs the parent directory, so a brand-new filename can still vanish after a crash even though its contents were synced.
Example
When to use it
- Commit each entry of a write-ahead log before acknowledging the transaction to the caller.
- Persist an in-place update to a fixed-size record file without paying for a metadata sync.
- Flush a high-volume audit stream at checkpoints where durability matters but timestamps do not.
Frequently asked questions
What is the difference between fsync and fdatasync?
fsync() syncs both the file's data and all of its metadata; fdatasync() skips metadata that is not needed to read the data back, such as the modification time. Use fsync() when the write changed the file size.
Do I need to call fflush before fdatasync?
No. fdatasync() implicitly flushes PHP's userland buffer before asking the kernel to sync, so calling fflush() first is redundant.
Does fdatasync work on Windows?
Yes, but it is aliased to fsync() there, so it also syncs metadata. The performance advantage over fsync() only exists on POSIX systems.
More examples
In-place record update
The initial write grows the file, so fsync() records the new size. The later overwrite keeps the size identical, which is exactly the case fdatasync() is built for.
<?php
$fh = fopen('records.dat', 'w+');
fwrite($fh, str_pad('rec-A', 16) . str_pad('rec-B', 16));
fsync($fh); // size change needs fsync
fseek($fh, 16); // overwrite slot 2 in place
fwrite($fh, str_pad('rec-C', 16));
var_dump(fdatasync($fh)); // no size change: fdatasync is enough
rewind($fh);
echo trim(fread($fh, 32)), "\n";
fclose($fh);
unlink('records.dat');Comparing the cost of syncing per write
Every iteration waits for the storage device, so the elapsed time is dominated by device latency rather than PHP. This is why syncing per write is reserved for data that must not be lost.
<?php
$fh = fopen('bench.log', 'w');
$t = microtime(true);
for ($i = 0; $i < 20; $i++) {
fwrite($fh, "line $i\n");
fdatasync($fh);
}
printf("20 synced writes: %.4f s\n", microtime(true) - $t);
echo 'lines: ', count(file('bench.log')), "\n";
fclose($fh);
unlink('bench.log');fdatasync includes the flush
Reading the file back through a separate call returns the content, showing that fdatasync() already pushed PHP's buffer to the kernel before syncing. Calling fflush() first would be redundant.
<?php
$fh = fopen('demo.txt', 'w');
fwrite($fh, "buffered in userland\n");
// no explicit fflush() needed
var_dump(fdatasync($fh));
echo file_get_contents('demo.txt');
fclose($fh);
unlink('demo.txt');
Discussion