Is there a way to force `apfsd` to defragment all the files on a disk?

As I understand, HFS+ and APFS volumes don't need to be defragmented, as files will automatically defragmented by the OS, but I'd like to leave a process running in the background that would do this to all files of the disk. Is there a way to check which files have more fragments or get a list of all files of the disk?


It is correct that on HFS+ volumes a technique named "On-the-fly" automatically defragments certain files when they're opened. However, it only applies for files that are less than 20 MB in size, are not busy, not read-only, have been unchanged for at least 60 seconds and has more than 8 extents (i.e. "fragments"). Typically those files will occupy a very small percentage of your hard drive.

In order to get statistics and list of fragmented files on HFS+ volumes, you'll want to use a tool like "hfsdebug" (free). It offers both listing of all fragmented files, as well as various statistics such as top lists of most fragmented files.

In order to get the list of all fragmented files that you seek, run the following command in Terminal.app after installing hfsdebug:

hfsdebug -f /

You can choose to see only the top 10 files like this:

hfsdebug -t 10 -f /

A newer tool named fileXray (79$) also exists that gives you much of the same features, and plenty more. As noted it is commercial software that requires you to purchase a license - note that it does not have a GUI, but has a textual interface similar to hfsdebug.

You can use fileXray to for example check if a file is fragmented or not:

fileXray filename

This will output a list of extents for the file "filename". If the file has multiple extents it is in theory fragmented. If the startBlock + blockCount of an extent lines up with the startBlock of the next extent, then in practice it doesn't matter much.

A simple way to do the actual defragmentation is to simply copy the file. Ensure that you have enough (non-fragmented) disk space in advance, and then copy the file to a new name on the same disk. The new file should be less fragmented (or not fragmented at all) - you can check that with the above mentioned command. After copying, you can remove the old file and rename the new file to match.

UPDATE: In the comments, you have expressed that you needed a free solution, and cannot use fileXray because it costs 75$. In that case you could use SleuthKit from HomeBrew instead - you'll find the ifind command from SleuthKit can list the number of extents as well. Another possibility is hfsinspect by Adam Knight, which can also list the extents.