103 lines
3.0 KiB
Python
103 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
File Extension Disk Usage Analyzer
|
|
|
|
Analyzes a directory and reports disk usage by file extension.
|
|
Useful for identifying large file types in project directories.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
|
|
|
|
def analyze_directory(directory: str, extension: str = None) -> dict:
|
|
"""
|
|
Analyze a directory and return file sizes grouped by extension.
|
|
|
|
Args:
|
|
directory: Path to directory to analyze
|
|
extension: Optional specific extension to filter (e.g., '.py')
|
|
|
|
Returns:
|
|
Dictionary mapping extensions to total size in bytes and file count
|
|
"""
|
|
stats = defaultdict(lambda: {"size": 0, "count": 0})
|
|
dir_path = Path(directory)
|
|
|
|
if not dir_path.exists():
|
|
raise FileNotFoundError(f"Directory not found: {directory}")
|
|
|
|
if not dir_path.is_dir():
|
|
raise NotADirectoryError(f"Not a directory: {directory}")
|
|
|
|
for root, dirs, files in os.walk(dir_path):
|
|
# Skip hidden directories and common ignore patterns
|
|
dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ('__pycache__', 'node_modules', '.git')]
|
|
|
|
for filename in files:
|
|
if filename.startswith('.'):
|
|
continue
|
|
|
|
filepath = Path(root) / filename
|
|
try:
|
|
size = filepath.stat().st_size
|
|
except OSError:
|
|
continue
|
|
|
|
file_ext = filepath.suffix.lower() or '(no extension)'
|
|
|
|
if extension and file_ext != extension.lower():
|
|
continue
|
|
|
|
stats[file_ext]["size"] += size
|
|
stats[file_ext]["count"] += 1
|
|
|
|
# Sort by total size descending
|
|
return dict(sorted(stats.items(), key=lambda x: x[1]["size"], reverse=True))
|
|
|
|
|
|
def format_size(size_bytes: int) -> str:
|
|
"""Format bytes to human readable string."""
|
|
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
|
|
if size_bytes < 1024.0:
|
|
return f"{size_bytes:.2f} {unit}"
|
|
size_bytes /= 1024.0
|
|
return f"{size_bytes:.2f} PB"
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage: file_ext_analyzer.py <directory> [extension]")
|
|
print("Example: file_ext_analyzer.py /path/to/project .py")
|
|
sys.exit(1)
|
|
|
|
directory = sys.argv[1]
|
|
extension = sys.argv[2] if len(sys.argv) > 2 else None
|
|
|
|
try:
|
|
stats = analyze_directory(directory, extension)
|
|
|
|
if not stats:
|
|
print("No files found.")
|
|
sys.exit(0)
|
|
|
|
print(f"\nDisk Usage Analysis: {directory}")
|
|
print("-" * 50)
|
|
|
|
for ext, data in stats.items():
|
|
print(f"{ext:15} {format_size(data['size']):>12} ({data['count']:>5} files)")
|
|
|
|
total_size = sum(d["size"] for d in stats.values())
|
|
total_files = sum(d["count"] for d in stats.values())
|
|
print("-" * 50)
|
|
print(f"{'TOTAL':15} {format_size(total_size):>12} ({total_files:>5} files)")
|
|
|
|
except (FileNotFoundError, NotADirectoryError) as e:
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |