A collection of file management and analysis tools, built with Go. Every tool is available both as a command and through a graphical interface.
- dupfind: Find duplicate files in a directory tree by comparing file hashes. Efficiently identifies identical files regardless of filename or location.
- dirstat: Analyze directory and subdirectories for comprehensive file statistics including sizes, types, and utilization percentages.
- rename: Rename files in a directory using pattern matching and sed-like replacements.
- organize: Sort files into per-category subdirectories by type, extension, modification date or size.
- size: Analyze how much space the files of a directory tree take up and report the largest ones.
- Multiple Output Formats: Support for text, JSON, XML, and HTML output formats
- File Output: Redirect output to files instead of stdout
- Flexible Hashing: Choose from MD5, SHA1, or SHA256 hash algorithms
- File/Directory Exclusions: Exclude files and directories from processing with pattern matching and file type filtering
- Structured Data: JSON/XML output provides machine-readable duplicate file information with metadata
- Rich HTML Reports: Generate professional HTML reports with styling, statistics, and interactive features
- Comprehensive Metadata: All structured outputs include execution context and branding information
- Graphical Interface: The same tools in a desktop window, with previews before anything is moved or renamed
See ROADMAP.md for the full list of planned and candidate features, including file content search and disk usage by owner.
Linux / macOS (amd64):
curl -fsSL https://raw.githubusercontent.com/amurru/filetools/main/install.sh | shWindows (PowerShell):
iex (irm https://raw.githubusercontent.com/amurru/filetools/main/install.ps1)The scripts download the latest release binary from GitHub and place it on
your PATH. Set INSTALL_DIR to choose a different location.
- Go 1.24.5 or later
git clone https://github.com/amurru/filetools.git
cd filetools
make build
make test # Run testsThe binary will be created as bin/filetools.
go install github.com/amurru/filetools@latestmake test # Run all tests
make clean # Clean build artifacts
make run # Build and run the applicationFind duplicate files in a directory tree with flexible output options.
Find duplicate files in a directory:
filetools dupfind /path/to/directoryIf no directory is specified, it uses the current directory:
filetools dupfindChoose from multiple output formats:
# Text output (default)
filetools dupfind /path/to/directory
# JSON output
filetools dupfind -o json /path/to/directory
filetools dupfind -j /path/to/directory
# XML output
filetools dupfind -o xml /path/to/directory
filetools dupfind -x /path/to/directory
# HTML output (generates a styled web page)
filetools dupfind -o html /path/to/directory
filetools dupfind -w /path/to/directoryRedirect output to a file instead of stdout:
# Save results to a file
filetools dupfind -f results.txt /path/to/directory
filetools dupfind -o json -f duplicates.json /path/to/directory
filetools dupfind -w -f report.html /path/to/directoryChoose the hash algorithm for file comparison:
# Use different hash algorithms (default: md5)
filetools dupfind -H sha256 /path/to/directory
filetools dupfind -H sha1 /path/to/directory
filetools dupfind -H md5 /path/to/directoryOnly consider files within a size range:
# Ignore files smaller than 1MB
filetools dupfind --min-size 1MB /path/to/directory
# Ignore files larger than 100MB
filetools dupfind --max-size 100MB /path/to/directory
# Combine both
filetools dupfind --min-size 1M --max-size 500M /path/to/directorySizes accept plain byte counts or a unit suffix: K, M, G, T and their
KB, MB, GB, TB variants.
Large files are fingerprinted on their first 64KB before they are read in full. Only files that share both a size and a fingerprint are hashed completely, which avoids reading large files that cannot be duplicates.
Combine multiple options:
# Generate JSON report with SHA256 hashes, save to file
filetools dupfind -H sha256 -o json -f report.json /path/to/directory
# Create HTML report with MD5 hashes
filetools dupfind -H md5 -w -f analysis.html /path/to/directoryText Output (default):
Generated by filetools dupfind v1.0.0 on 2025-10-27T14:30:45Z (hash: md5, output: text)
Duplicate files found:
- file1.txt (size: 1024 bytes, hash: a1b2c3d4...)
- /path/to/dir1/file1.txt
- /path/to/dir2/file1.txt
- file2.txt (size: 2048 bytes, hash: e5f6g7h8...)
- /path/to/dir3/file2.txt
- /path/to/dir4/file2.txt
JSON Output:
{
"metadata": {
"tool_name": "filetools",
"sub_command": "dupfind",
"flags": [
{
"name": "hash",
"value": "md5"
},
{
"name": "output",
"value": "json"
}
],
"version": "1.0.0",
"generated_at": "2025-10-27T14:30:45Z"
},
"groups": [
{
"hash": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"hash_type": "md5",
"size": 1024,
"files": ["/path/to/dir1/file1.txt", "/path/to/dir2/file1.txt"]
}
],
"found": true
}XML Output:
<?xml version="1.0" encoding="UTF-8"?>
<DuplicateResult>
<metadata>
<toolName>filetools</toolName>
<subCommand>dupfind</subCommand>
<flags>
<flag>
<name>hash</name>md5
</flag>
<flag>
<name>output</name>xml
</flag>
</flags>
<version>1.0.0</version>
<generatedAt>2025-10-27T14:30:45Z</generatedAt>
</metadata>
<groups>
<hash>a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6</hash>
<hashType>md5</hashType>
<size>1024</size>
<files>/path/to/dir1/file1.txt</files>
<files>/path/to/dir2/file1.txt</files>
</groups>
<found>true</found>
</DuplicateResult>HTML Output: Generates a complete HTML page with:
- Professional styling and layout
- Summary statistics
- Color-coded file badges (original/duplicate)
- Responsive design
- Interactive features: clickable hashes (copy to clipboard), collapsible duplicate groups
- Program branding footer
Exclude files and directories from processing while still reporting them in the output.
Exclude files matching patterns or file types:
# Exclude specific file patterns (globs)
filetools dupfind --exclude-file "*.log,*.tmp,cache/*" /path/to/directory
# Exclude by file type (matches extensions)
filetools dupfind --exclude-file "*.jpg,*.png,*.gif" /path/to/directory
# Combine with other options
filetools dirstat --exclude-file "*.log,*.tmp" -o json /path/to/directoryExclude entire directories matching patterns:
# Exclude common directories
filetools dupfind --exclude-dir "node_modules,.git,build" /path/to/directory
# Exclude by pattern
filetools dirstat --exclude-dir "temp*,cache*" /path/to/directoryUse both file and directory exclusions together:
filetools dupfind --exclude-file "*.log,*.tmp" --exclude-dir "node_modules,.git" /path/to/directoryExcluded items are listed in the "Exclusions" section of all output formats:
Text Output:
Excluded files and directories:
- node_modules (dir_pattern)
- cache/file.log (file_pattern)
- temp/image.jpg (file_type)
JSON/XML Output:
Excluded items are included in the exclusions array with path and reason fields.
HTML Output: Exclusions are displayed in a sortable table with professional styling.
Analyze directory and subdirectories for comprehensive file statistics.
Rename files in a directory using pattern matching and sed-like replacements.
Analyze a directory for file statistics:
filetools dirstat /path/to/directoryIf no directory is specified, it uses the current directory:
filetools dirstatChoose from multiple output formats:
# Text output (default)
filetools dirstat /path/to/directory
# JSON output
filetools dirstat -o json /path/to/directory
filetools dirstat -j /path/to/directory
# XML output
filetools dirstat -o xml /path/to/directory
filetools dirstat -x /path/to/directory
# HTML output (generates a styled web page)
filetools dirstat -o html /path/to/directory
filetools dirstat -w /path/to/directoryRedirect output to a file instead of stdout:
# Save results to a file
filetools dirstat -f stats.txt /path/to/directory
filetools dirstat -o json -f stats.json /path/to/directory
filetools dirstat -w -f report.html /path/to/directoryCombine multiple options:
# Generate JSON statistics, save to file
filetools dirstat -o json -f stats.json /path/to/directory
# Create HTML report
filetools dirstat -w -f analysis.html /path/to/directory
# Analyze with exclusions
filetools dirstat --exclude-file "*.log,*.tmp" --exclude-dir "node_modules,.git" -w -f clean-report.html /path/to/directoryText Output (default):
Generated by filetools dirstat v1.0.0 on 2025-10-27T14:30:45Z (output: text)
Directory Statistics
===================
Total Files: 150
Total Size: 25.3 MB
Largest File: large_video.mp4 (15.2 MB)
File Types
----------
Extension Count Size Percentage
------------ -------- --------- ----------
.mp4 5 18.5 MB 73.12%
.jpg 45 4.2 MB 16.60%
.txt 30 1.8 MB 7.11%
.pdf 12 780 KB 3.01%
(no ext) 58 45 KB 0.17%
Subdirectories
--------------
Path Files Size Percentage
----------------------- -------- --------- ----------
videos 5 18.5 MB 73.12%
images 45 4.2 MB 16.60%
documents 42 2.6 MB 10.28%
...
JSON Output:
{
"metadata": {
"tool_name": "filetools",
"sub_command": "dirstat",
"flags": [
{
"name": "output",
"value": "json"
}
],
"version": "1.0.0",
"generated_at": "2025-10-27T14:30:45Z"
},
"total_files": 150,
"total_size": 26528934,
"largest_file": {
"name": "large_video.mp4",
"size": 15920000,
"path": "videos/large_video.mp4"
},
"file_types": [
{
"extension": ".mp4",
"count": 5,
"total_size": 19398656,
"percentage": 73.12
}
],
"directories": [
{
"path": "videos",
"file_count": 5,
"total_size": 19398656,
"percentage": 73.12
}
]
}HTML Output: Generates a complete HTML page with:
- Professional styling and layout
- Summary statistics dashboard
- Sortable tables for file types and directories
- Visual percentage bars
- Responsive design
- Program branding footer
Sort files into per-category subdirectories.
Preview how the files of a directory would be organized:
filetools organize /path/to/directoryGroup the files by a different criteria:
# One directory per file extension
filetools organize --by extension /path/to/directory
# One directory per month of the modification date
filetools organize --by date /path/to/directory
# One directory per size range
filetools organize --by size /path/to/directoryMove the files into a separate destination directory:
filetools organize --dest /path/to/sorted --force /path/to/directory--by |
Example directory | Description |
|---|---|---|
type |
images/ |
Broad categories: images, video, audio, documents, archives, code, data, other |
extension |
png/ |
One directory per file extension |
date |
2024-03/ |
One directory per month of the modification date |
size |
1 MB - 10 MB/ |
One directory per size range |
By default the command only reports what it would do:
filetools organize /path/to/directoryTo actually move the files:
filetools organize --force /path/to/directoryExisting files at the target are never replaced unless --overwrite is given.
--by string: Group files by type, extension, date or size (default "type")--dest string: Destination directory (default: the scanned directory)--force: Move the files (disables dry-run)--overwrite: Replace files that already exist at the target--include-hidden: Also organize hidden files--category string: Only organize files belonging to this category
Analyze how much space the files of a directory tree take up.
filetools size /path/to/directoryReport more of the largest files:
filetools size --top 25 /path/to/directoryThe report contains the total file count, total size, directory count, the distribution of the files over size ranges and the largest files of the tree.
--top int: Number of largest files to report (default 10)
Check the version and build information:
filetools versionOutput:
version: 1.0.0
date: 2025-10-27T14:30:45Z
filetools/
βββ cmd/ # CLI commands
β βββ dirstat.go # Directory statistics command
β βββ dupfind.go # Duplicate file finder command
β βββ gui.go # Graphical interface command (build tag "gui")
β βββ gui_stub.go # Graphical interface placeholder (build tag "!gui")
β βββ organize.go # File organizer command
β βββ rename.go # Batch rename command
β βββ root.go # Root command and global flags
β βββ size.go # File size analyzer command
β βββ version.go # Version command
βββ internal/
β βββ exclusions/ # Exclusion pattern matching
β β βββ exclusions.go
β βββ gui/ # Graphical interface (build tag "gui")
β β βββ app.go # Window, navigation and event loop
β β βββ job.go # Background runner and progress reporting
β β βββ theme.go # Light and dark palettes
β β βββ widgets.go # Panels, forms, tables and charts
β β βββ page_*.go # One page per tool
β βββ output/ # Output formatting module
β β βββ formatter.go # Formatter interface
β β βββ json.go # JSON formatter
β β βββ xml.go # XML formatter
β β βββ html.go # HTML formatter
β β βββ text.go # Text formatter
β βββ progress/ # Progress reporting contract and reporter
β βββ report/ # Data model shared by every front end
β βββ scan/ # Analysis engines, shared by every front end
β βββ version/ # Build metadata injected via ldflags
βββ main.go # Application entry point
βββ go.mod # Go module definition
βββ Makefile # Build automation
βββ README.md # This file
The tool is built with a layered architecture. The dependency direction is strictly downwards, nothing in a lower layer imports a higher one.
- Front Ends:
cmdfor the command line andinternal/guifor the graphical interface. Both are thin adapters over the same engines. - Analysis Layer:
internal/scanholds the engines. They take an options struct, report their progress and return a report structure. They know nothing about the front end. - Data Model:
internal/reportholds the structures that flow from the engines to the formatters and to the interface. - Output Layer:
internal/outputrenders a report as text, JSON, XML or HTML.
The same tools are available in a desktop window, built with Gio. The interface shows a preview of what a tool would do before it touches the filesystem, and the renaming and organizing pages ask for a confirmation before they change anything.
The interface is guarded by the gui build tag, so the command line tool
stays pure Go and cross compiles to any target as before.
make build-gui # Builds bin/filetools-gui
./bin/filetools-gui guiOn Linux the build needs cgo and the windowing and graphics libraries of the platform:
sudo apt-get install -y \
gcc pkg-config \
libegl-dev libgles-dev \
libvulkan-dev \
libwayland-dev \
libx11-dev libx11-xcb-dev libxcursor-dev libxfixes-dev \
libxkbcommon-dev libxkbcommon-x11-devOn Windows no extra packages are needed. On macOS the build needs the Xcode
command line tools. The release artifacts are
named filetools-gui-windows-amd64.exe and filetools-gui-linux-amd64.
These flags work with all commands:
-o, --output string: Output format (text, json, xml, html) (default "text")-f, --file string: Output file (default: stdout)-j, --json: Shortcut for-o json-x, --xml: Shortcut for-o xml-w, --html: Shortcut for-o html--exclude-file string: Exclude files matching patterns (comma-separated globs or file types)--exclude-dir string: Exclude directories matching patterns (comma-separated globs)--no-progress: Disable progress indicators
-H, --hash string: Hash algorithm (md5, sha1, sha256) (default "md5")--min-size string: Only consider files of at least this size (e.g. 1MB, 512K)--max-size string: Only consider files of at most this size (e.g. 100MB)
The dirstat command uses only the global flags (no command-specific flags).
--by string: Group files by type, extension, date or size (default "type")--dest string: Destination directory (default: the scanned directory)--force: Move the files (disables dry-run)--overwrite: Replace files that already exist at the target--include-hidden: Also organize hidden files--category string: Only organize files belonging to this category
--top int: Number of largest files to report (default 10)
Rename files in a directory using pattern matching and sed-like replacements.
Rename files in a directory:
filetools rename --match "*.jpg" --sed "s/^/vacation_/" /photosIf no directory is specified, it uses the current directory:
filetools rename --match "*.txt" --sed "s/draft/final/g"Choose from multiple output formats:
# Text output (default)
filetools rename --match "*.jpg" --sed "s/old/new/" /path
# JSON output
filetools rename -o json --match "*.jpg" --sed "s/old/new/" /path
# XML output
filetools rename -o xml --match "*.jpg" --sed "s/old/new/" /path
# HTML output
filetools rename -o html --match "*.jpg" --sed "s/old/new/" /pathAdd prefix to all JPG files:
filetools rename --match "*.jpg" --sed "s/^/vacation_/" /photosRemove suffix from files:
filetools rename --match "*_old.jpg" --sed "s/_old//" /photosGeneral replacement:
filetools rename --match "*.txt" --sed "s/draft/final/g" /docsBy default, the command runs in dry-run mode for safety:
filetools rename --match "*.jpg" --sed "s/old/new/" /photos
# Shows what would be renamed without making changesTo actually perform the renames:
filetools rename --force --match "*.jpg" --sed "s/old/new/" /photos--match string: File pattern to match (glob, required)--sed string: Sed-style replacement expression (e.g., s/old/new/g, required)--dry-run: Preview changes without executing (default: true)--force: Perform actual renames and overwrite existing files
# View help
filetools --help
filetools dupfind --help
filetools dirstat --help
filetools organize --help
filetools size --help
# Different output combinations
filetools dupfind -j -f results.json /path
filetools dupfind -o xml -f report.xml /path
filetools dupfind -w /path > report.html
# Directory statistics
filetools dirstat -j -f stats.json /path
filetools dirstat -w -f analysis.html /path
# Organize files into category directories
filetools organize --by type --force /path
filetools organize --by extension -j -f plan.json /path
# Size analysis
filetools size --top 20 -j -f sizes.json /pathRun the test suite:
make testRun specific tests:
go test -run TestCalculateHash ./internal/scan/
go test ./internal/output/The graphical interface is tested by rendering it offscreen. The tests need an EGL implementation and are skipped when none is available:
go test -tags gui ./internal/gui/A screenshot of the interface can be written for review:
FILETOOLS_GUI_SCREENSHOT=/tmp/gui.png go test -tags gui -run Screenshot ./internal/gui/The project follows Go best practices:
- Uses
gofmtfor consistent formatting - Includes comprehensive unit tests
- Follows standard Go naming conventions
- Uses Cobra for CLI framework
- Modular architecture for maintainability
To add a new tool:
- Add the analysis engine in
internal/scan/with an options struct, aprogress.Indicatorparameter and areport.*Resultreturn value - Define the result struct in
internal/report/report.go - Add the formatter to
internal/output/and to theOutputFormatterinterface - Register the Cobra command in
cmd/ - Add the interface page in
internal/gui/page_<name>.go - Add tests in
internal/scan/
To add a new output format:
- Create a new formatter in
internal/output/ - Implement the
OutputFormatterinterface - Add the format to
NewFormatter()function - Add corresponding flag if needed
- Update tests and documentation
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Write tests for your changes
- Ensure all tests pass (
make test) - Update documentation if needed
- Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Follow the existing code style and architecture
- Add tests for new functionality
- Update README.md for new features
- Ensure backward compatibility
- Use meaningful commit messages
This project is licensed under the MIT License - see the LICENSE file for details.