A Java library for monitoring disk events on macOS using the DiskArbitration framework.
- π Monitor USB device mount/unmount events
- π Track all disk appearance/disappearance events
- π― Powerful filtering system (USB-only, external-only, size-based, etc.)
- π Comprehensive disk metadata (vendor, model, size, filesystem type, etc.)
- β‘ Lightweight JNA-based implementation
dependencies {
implementation 'com.selesse:jdiskarbitration:1.0.0'
}// Use DiskEventAdapter to only implement the events you care about
DiskEventManager manager = DiskEventManager.builder()
.listener(new DiskEventAdapter() {
@Override
public void onDiskMounted(DiskInfo diskInfo) {
System.out.println("Disk mounted: " + diskInfo.volumeInfo().name() +
" at " + diskInfo.volumeInfo().path());
}
@Override
public void onDiskUnmounted(DiskInfo diskInfo) {
System.out.println("Disk unmounted: " + diskInfo.bsdName());
}
})
.build();
manager.start();
// Resources are automatically cleaned up on JVM shutdown
// Or manually: manager.stop();Note: The manager automatically registers a shutdown hook to clean up resources when the JVM exits. You don't need to manually add shutdown hooks unless you want custom cleanup behavior.
DiskEventManager manager = DiskEventManager.builder()
.externalOnly() // Only external devices
.usbOnly() // Only USB protocol
.minSize(1024 * 1024) // At least 1MB
.listener(myListener)
.build();
manager.start();The builder provides powerful filtering capabilities:
DiskEventManager.builder()
// Convenience filters
.externalOnly() // External devices only
.usbOnly() // USB protocol only
.removableOnly() // Removable media only
.ejectableOnly() // Ejectable disks only
.writableOnly() // Writable disks only
// Size filters (with readable units)
.minSize(1, FileSize.GIGABYTE) // Minimum 1GB
.maxSize(128, FileSize.GIGABYTE) // Maximum 128GB
// Size filters (raw bytes also supported)
.minSize(1024 * 1024 * 1024) // Minimum 1GB
.maxSize(128L * 1024 * 1024 * 1024) // Maximum 128GB
// Property filters
.protocol("USB") // Specific protocol
.volumeKind("exfat") // Specific filesystem
// Custom filters
.filter(info -> info.volumeInfo().name() != null)
.filter(info -> !info.volumeInfo().name().startsWith("Time Machine"))
.listener(myListener)
.build();The DiskInfo record and its nested types provide disk metadata.
bsdName()- BSD device name (e.g., "disk2s1")
path()- Mount path (e.g., "/Volumes/USB Drive")name()- Volume name (e.g., "USB Drive")kind()- Filesystem type (e.g., "exfat", "msdos", "apfs")uuid()- Volume UUIDmountable()- Whether volume is mountable (Boolean, may be null)network()- Whether volume is on network (Boolean, may be null)type()- Volume type
protocol()- Protocol (e.g., "USB", "SATA", "Virtual Interface")model()- Device modelvendor()- Device vendor/manufacturerrevision()- Firmware revisionunit()- Device unit numberisInternal()- Whether device is internalguid()- Device GUIDpath()- Device pathtdmLocked()- Whether Target Disk Mode is locked (Boolean, may be null)
mediaSize()- Size in bytesmediaBlockSize()- Block sizeisRemovable()- Whether media is removableisEjectable()- Whether disk can be ejectedisWritable()- Whether disk is writableisWholeDisk()- Whether this is whole disk vs partitionisLeaf()- Whether this is a leaf nodemediaType()- Media typemediaContent()- Media content identifiermediaUUID()- Media UUIDbsdMajor()- BSD major numberbsdMinor()- BSD minor numberbsdName()- BSD namebsdUnit()- BSD unit numbericon()- Icon bundle identifier (e.g., "com.apple.finder")kind()- Media kindname()- Media namepath()- Media pathencrypted()- Whether media is encrypted (Boolean, may be null)encryptionDetail()- Encryption detail code (Integer, e.g., 256 for AES-256)
name()- Bus name (e.g., "USB")path()- Bus path
isExternal()- Returns!deviceInfo().isInternal()isUSB()- Returns true if device protocol is "USB"getFormattedSize()- Human-readable size (e.g., "16.37 GB")
DiskEventManager manager = DiskEventManager.builder()
.usbOnly()
.removableOnly()
.minSize(1, FileSize.MEGABYTE) // At least 1MB
.listener(new DiskEventAdapter() {
@Override
public void onDiskMounted(DiskInfo info) {
System.out.printf("USB drive mounted: %s (%s) at %s%n",
info.volumeInfo().name(),
info.getFormattedSize(),
info.volumeInfo().path());
}
})
.build();
manager.start();DiskEventManager manager = DiskEventManager.builder()
.externalOnly()
.filter(info -> !info.mediaInfo().isRemovable()) // Not removable (hard drives)
.minSize(100, FileSize.GIGABYTE) // At least 100GB
.listener(myListener)
.build();DiskEventManager manager = DiskEventManager.builder()
.filter(info -> {
// Only exFAT or FAT32 filesystems
String kind = info.volumeInfo().kind();
return "exfat".equalsIgnoreCase(kind) ||
"msdos".equalsIgnoreCase(kind);
})
.filter(info -> {
// Not Time Machine backups
String name = info.volumeInfo().name();
return name == null || !name.contains("Time Machine");
})
.listener(myListener)
.build();