Techsenger DriveKit is a Java library for detecting local drives, classifying their types, providing stable IDs, and monitoring changes. It works on Windows, Linux, and macOS.
A drive is a volume that is available in the file system: a drive letter of Windows or a mounted file system of a Unix-like system. For every drive the library gives its root path, type, label, identifier, and the flag of encryption.
- Features
- Overview
- Quick Start
- Drive
- DriveDetector
- DriveMonitor
- Limitations
- Requirements
- Dependencies
- Code Building
- Running Demo
- License
- Contributing
- Support Us
Key features of DriveKit include:
- Listing of the drives of the local machine on Windows, Linux, and macOS.
- Classification of the drives: hard disk, solid state drive, removable drive, memory card, floppy, optical, network, LVM, RAID, virtual.
- A stable identifier of a drive that the operating system keeps across reboots.
- Detection of the encryption of a drive (dm-crypt on Linux).
- A monitor that reports the connected and removed drives, with three modes: manual, periodic, and smart refresh.
- Nested drives on Linux, where a volume is mounted into a directory of another one.
- No external processes and no parsing of the output of commands.
DriveKit detects the drives with DriveDetector and keeps track of them with DriveMonitor. Every drive has a root
path, a type, a label, an identifier, and the flag of encryption. The details are in the sections Drive,
DriveDetector, and DriveMonitor. How the drives and their types are found, and how accurate
it is, is in DriveDetector.
To get the drives currently available on the system, call DriveDetector.detect():
for (Drive drive : DriveDetector.detect()) {
System.out.println(drive.getRoot() + " " + drive.getType() + " "
+ drive.getLabel() + " " + drive.getId());
}By default, DriveMonitor uses MANUAL_REFRESH mode. It searches for drives when you call refresh() and notifies
listeners if the results differ from the previous search.
The listener runs in the same thread that calls refresh().
DriveListener listener = change -> {
change.getAdded().forEach(drive -> System.out.println("Connected: " + drive));
change.getRemoved().forEach(drive -> System.out.println("Removed: " + drive));
};
DriveMonitor.addListener(listener);
List<Drive> drives = DriveMonitor.getDrives(); // performs the initial search
// The listener is not called for the initial search.
// Later, when you want to check for changes:
DriveMonitor.refresh(); // notifies the listener if drives have changed
drives = DriveMonitor.getDrives(); // returns the latest resultsIf you don't want to call refresh() yourself, switch to SMART_REFRESH mode. The monitor checks the system state
periodically and searches for drives only when it detects a change.
The listener runs in the monitor's own thread. If you update a user interface, dispatch the update to the UI thread.
For example, in JavaFX, use Platform.runLater():
DriveListener listener = change ->
Platform.runLater(() -> table.getItems().setAll(change.getCurrent()));
DriveMonitor.addListener(listener);
DriveMonitor.setInterval(Duration.ofSeconds(5)); // optional; defaults to 3 seconds
DriveMonitor.setMode(MonitorMode.SMART_REFRESH); // starts monitoring immediatelyWhen you no longer need automatic monitoring, switch back to manual mode and remove the listener:
DriveMonitor.setMode(MonitorMode.MANUAL_REFRESH);
DriveMonitor.removeListener(listener);Drive is an immutable description of a volume:
| Method | Description |
|---|---|
getRoot() |
The root directory, such as E:\ or /media/user/DISK. |
getType() |
The type of the drive. |
getLabel() |
The label of the volume, or an empty string. On macOS it is the name of the directory of the volume in /Volumes, which differs from the name of the volume if another volume has taken it. |
getId() |
The identifier of the volume. |
isEncrypted() |
Whether the volume is known to be encrypted. |
Two drives are equal if their roots, types, identifiers, labels and encryption flags are equal. Clients tell a drive that has changed from a drive that has not by it.
| Type | Description |
|---|---|
HDD |
A hard disk with rotating plates. An external disk is also HDD or SSD, as the systems report it as an ordinary disk. |
SSD |
A solid state drive, including NVMe and built-in flash storage. |
REMOVABLE |
A removable drive that has no more specific type, such as a USB flash drive or a Zip drive. A memory card is also REMOVABLE. A floppy drive is FLOPPY, an optical drive is OPTICAL. |
FLOPPY |
A floppy disk drive. |
OPTICAL |
A CD, DVD, or Blu-ray drive. |
NETWORK |
A share of another machine mounted into the file system. |
LVM |
A logical volume of LVM (Linux). |
RAID |
A RAID array: several drives combined into one, also when it lies over other drives. |
VIRTUAL |
A drive that has no device of its own: a mounted disk image (ISO, VHD, DMG, loop) or a RAM disk. An image is virtual whatever it holds, so a mounted ISO image is VIRTUAL, not OPTICAL. |
UNKNOWN |
A drive whose type the system does not report, such as a disk behind a USB enclosure or in a virtual machine. |
The identifier is a string that the operating system keeps for the same volume across reboots and that differs for different volumes, so a drive found again can be told from a new one. Its prefix names the kind of the value, so values of different kinds never coincide:
| Prefix | Where | Value |
|---|---|---|
volguid: |
Windows | The GUID of the volume. |
net: |
Windows | The UNC path of a network drive. |
fsuuid: |
Linux | The UUID of the file system. |
partuuid: |
Linux, macOS | The UUID of the partition. |
src: |
Linux, macOS | The source of the mount, such as host:/export. |
path: |
all | The root path, if the system gives nothing else. It is not stable: a volume mounted elsewhere gets another one. |
The identifiers of the drives returned together are different: if several drives would have the same identifier, as a
volume mounted into several places has, the later ones get @ and the URI of their root added to it.
isEncrypted() is true if the whole volume is known to be encrypted. It is detected for dm-crypt on Linux (LUKS,
plain, and TrueCrypt modes), including the volumes of LVM and RAID that lie over it. The encryption that the other
systems do on their own, such as BitLocker and FileVault, is not detected, and isEncrypted() is false for such
drives.
DriveDetector.detect() searches the drives of the local machine and returns them, the root of the file system first.
Its API is static and it has no state: the drives are searched again on every call, and new instances are returned.
- Windows: the roots of the file system, that is the drive letters. The identifier is the GUID of the volume, or the UNC path for a network drive.
- Linux: the file systems that are mounted. The root is always listed. The other mounts are listed if they are made
from a device, or are network shares, or ZFS. The mounts of the system and of the programs are not listed:
/proc,/sys,/dev,/run(except/run/media), snap packages, containers. The layers over devices are followed: dm-crypt is passed through for the type and setsisEncrypted(), LVM and RAID give their own types. - macOS: the root and the volumes in
/Volumes.
The type of a drive is found from the signs that the operating system gives, so the accuracy depends on the type and on the system:
- Exact — the system tells the type directly.
- High — the type follows from the signs that the system sets reliably for ordinary hardware.
- — — the type is not detected, or the system does not have such drives.
If none of the signs is there, the type is UNKNOWN. The cells name the signs in the order they are checked.
| Type | Windows | Linux | macOS |
|---|---|---|---|
HDD |
High: seek penalty. | High: rotation rate that udev knows, then the flag of rotation, which is the weakest sign. | High: type of the medium in the registry of the kit. |
SSD |
Exact: NVMe and MMC (eMMC) buses. High: no seek penalty, support of trim, name of the product. | Exact: NVMe, and eMMC (the device of the card host that is not an SD card). High: rotation rate that udev knows, name of the model, flag of rotation. | High: type of the medium in the registry of the kit. |
REMOVABLE |
High: the drive that the system calls removable. Exact: SD bus. | High: the flag of removable media. Exact: SD card on a card host. | High: the medium that the system calls removable. |
FLOPPY |
High: removable drives A: and B:. |
Exact: fd*. |
— |
OPTICAL |
Exact: CD-ROM drive type, also in a USB drive. | Exact: sr*, also in a USB drive. |
High: file systems cd9660 and udf on a device that is not an image. |
NETWORK |
Exact: remote drive type. | Exact: nfs, nfs4, cifs, smb3, fuse.sshfs. |
Exact: nfs, smbfs, afpfs, webdav. |
LVM |
— | Exact: volumes of LVM. | — |
RAID |
High: RAID bus of the logical drives of a controller. | Exact: arrays of md. High: controllers whose drivers give arrays only (hpsa, aacraid, arcmsr, 3w-*). |
— |
VIRTUAL |
Exact: RAM disk, image mounted from a file (ISO, VHD, VHDX). | Exact: loop*, ram*, zram*. |
High: device of a disk image (DMG, ISO). |
The ratings come from the documented behavior of the system interfaces. The library has not been verified on all the hardware yet, and macOS has not been verified at all. The cases where the signs are hidden, such as disks behind USB bridges, are in Limitations.
DriveMonitor keeps the current drives of the machine and reports their changes. Its API is static, as the machine has
one set of drives. While a drive has not changed, the monitor gives the very same instance, and a new instance only
when it has changed.
A change is described by DriveChange: the added drives, the removed drives, and all the current drives. A drive whose
label or type has changed is both removed (as it was) and added (as it is now).
The mode tells how refresh() is called. refresh() searches the drives and notifies the listeners if they have
changed; a client may call it in any mode, and it always searches. refresh() is synchronous: when it returns, the
search is finished and getDrives() gives the drives that it found. In the periodic and smart modes the monitor calls
it on its own thread.
| Mode | Refreshed by | Cost | Accuracy |
|---|---|---|---|
MANUAL_REFRESH |
A client. This is the default. | None until it is called. | The state of the last refresh(). |
PERIODIC_REFRESH |
The monitor, every interval. | It reads the drives every interval, which may wake a sleeping device or load a network share. | The most accurate: every change is noticed within an interval. |
SMART_REFRESH |
The monitor, only when the state of the system has changed. | It checks the state every interval, which does not read the drives, and searches only on a change. | A drive that is connected or disconnected, or whose volume is replaced, is noticed within an interval. A change that the state does not show is noticed at the next refresh(), see the table below. |
setMode starts the periodic and smart modes with a refresh() right away. setInterval changes the interval of the
periodic and smart modes, three seconds by default, and getInterval returns it. getDrives() returns the drives that
the last refresh() has found, without a new search; if there was no search yet, it makes the first one.
The monitor of each system checks its own state in the smart mode, without reading the drives:
| System | State | Noticed | Not noticed until refresh() |
|---|---|---|---|
| Windows | The letters of the drives and the identifiers of their volumes. | A drive that is connected or disconnected, a card or a disc put into a reader that keeps its letter. | A new label of a drive. Another share behind the same letter of a network drive. |
| Linux | The lines of the mounts that are listed. | A mount, an unmount, a mount of another device to the same place. | A new label of a mounted file system. |
| macOS | The volumes in /Volumes and the numbers of their devices. |
A volume that is connected or disconnected, another device under the same name, a new name of a volume. | A change of the type of a drive that stays where it is. |
The listeners are added by addListener and are notified in all the modes. A listener is called by the refresh() that
has found the changes, in the thread that calls it: the thread of the monitor when the monitor calls refresh() in the
periodic and smart modes, and the thread of a client when the client calls it. That thread waits for the listener, so a
listener must not block, and a user interface is updated through its own thread.
- A hard disk is told from a solid state drive by the signs the system gives. Some bridges between a disk and the
machine, such as USB enclosures and the disks of virtual machines, hide the technology. On Windows and macOS the
type is then
UNKNOWN. On Linux the system takes a disk for a rotating one unless it is told otherwise, so a solid state drive behind such a bridge is anHDD, unless the name of its model containsSSD. - A drive is
REMOVABLEonly if the system calls it removable. A flash drive that reports itself as fixed is anHDDor anSSD(orUNKNOWN), as the system shows it as a disk too. Conversely, an external disk whose enclosure reports removable media isREMOVABLE. - A device on the MMC bus is always an
SSD. Nowadays it is almost always eMMC, the flash storage that is soldered into the machine, and the systems show it as an ordinary disk. The systems give the same bus and type to a removable MMC card, so it cannot be told from eMMC. Such cards are practically extinct, so a removable MMC card is also anSSD. An SD card is not affected: it isREMOVABLE. - A USB floppy drive is
REMOVABLE, as the system shows it as a removable disk. On Windows onlyA:andB:areFLOPPY. - A disc with a file system other than
cd9660andudfis not detected asOPTICALon macOS. - The arrays of Windows (dynamic disks, Storage Spaces) and of Linux controllers such as MegaRAID are seen as ordinary disks.
- On Windows a network share without a drive letter is not listed.
- On Linux only the mounted file systems are listed. Unmounted partitions and swap are not.
- On Linux the shares that are opened through the file manager (GVfs) are not listed.
- On Linux a ZFS dataset is listed with the type
UNKNOWN. - The encryption is detected on Linux only.
- Other systems than Windows, Linux, and macOS are not supported:
DriveDetectorandDriveMonitorfail to initialize with anUnsupportedOperationExceptionas the cause. - The library is young: the classification on Windows and macOS is based on the documented interfaces of the systems and has not been verified on all the hardware.
The library requires Java 21. The demo also requires JavaFX 21.
Minimal dependency:
<dependency>
<groupId>com.techsenger.drivekit</groupId>
<artifactId>drivekit-core</artifactId>
<version>${drivekit.version}</version>
</dependency>
To build the library use standard Git and Maven commands:
git clone https://github.com/techsenger/drivekit
cd drivekit
mvn clean install
To run the demo, execute the following commands in the project root:
cd drivekit-demo
mvn javafx:run
The window has a drop-down list with the mode of the monitor and the Refresh button. The table shows all the drives with their identifiers.
Techsenger DriveKit is licensed under the Apache License, Version 2.0.
We welcome all contributions. You can help by reporting bugs, suggesting improvements, or submitting pull requests with fixes and new features. If you have any questions, feel free to reach out — we’ll be happy to assist you.
You can support our open-source work through GitHub Sponsors. Your contribution helps us maintain projects, develop new features, and provide ongoing improvements. Multiple sponsorship tiers are available, each offering different levels of recognition and benefits.