Python获取一级子目录按最后访问时间倒序及磁盘清理需求
Hey there! Let's walk through building this disk cleanup function step by step—since you're new to Python, I'll keep things clear and add plenty of notes so you understand what's going on.
Step 1: Get Top-Level Subdirectories Efficiently
Instead of using os.listdir() (which only returns filenames), we'll use os.scandir(). It's faster because it grabs file metadata (like access times) right away, so we don't have to make extra calls to fetch that info later. We'll filter out files and symlinks to keep only actual directories.
Step 2: Sort by Last Access Time
Each entry from os.scandir() has a .stat() method that gives us access to st_atime—the timestamp of the last time the directory was accessed. We'll use Python's sorted() function to sort these directories: for disk cleanup, we usually delete the least recently accessed (oldest) first, so we'll sort in ascending order. If you want to delete newest first instead, just flip the reverse flag.
Step 3: Calculate Directory Size
To know how much space deleting a directory will free up, we need a helper function to recursively calculate the total size of all files and subdirectories inside it. We'll add error handling here for cases where we don't have permission to access parts of the directory.
Step 4: The Cleanup Logic
We'll loop through our sorted directories, delete them one by one, and keep track of how much space we've freed until we hit our target MB count. We'll handle common errors like permission issues or missing directories so the function doesn't crash unexpectedly.
Full Working Code
import os import shutil def get_dir_size(path): """Recursively calculate the total size of a directory in bytes""" total_size = 0 try: # Use scandir for efficiency here too for entry in os.scandir(path): if entry.is_file(follow_symlinks=False): # Add file size directly total_size += entry.stat(follow_symlinks=False).st_size elif entry.is_dir(follow_symlinks=False): # Recursively calculate subdirectory size total_size += get_dir_size(entry.path) except PermissionError: print(f"Warning: No permission to access {path} — skipping this directory.") return total_size def disk_cleanup(target_dir, mb_to_free): """ Clean up directories in target_dir to free up specified MB. Sorts top-level subdirectories by last access time (oldest first gets deleted). """ # Convert MB to bytes (since all file size functions use bytes) bytes_to_free = mb_to_free * 1024 * 1024 freed_bytes = 0 # Get all entries in the target directory try: entries = os.scandir(target_dir) except FileNotFoundError: print(f"Error: Target directory '{target_dir}' doesn't exist.") return except PermissionError: print(f"Error: You don't have permission to access '{target_dir}'.") return # Filter to keep only top-level directories (skip files and symlinks) subdirs = [entry for entry in entries if entry.is_dir(follow_symlinks=False)] # Sort directories by last access time: oldest first (delete least used first) # Change reverse=True if you want to delete newest first instead sorted_subdirs = sorted(subdirs, key=lambda x: x.stat().st_atime, reverse=False) print(f"Found {len(sorted_subdirs)} top-level directories.") print(f"Target: Free up {mb_to_free} MB ({bytes_to_free:,} bytes).") # Iterate through sorted directories and delete until we hit the target for dir_entry in sorted_subdirs: if freed_bytes >= bytes_to_free: break # We've freed enough space, stop here dir_path = dir_entry.path dir_size_bytes = get_dir_size(dir_path) dir_size_mb = dir_size_bytes / 1024 / 1024 # Print some info for transparency print(f"\nProcessing: {dir_path}") print(f"Size: {dir_size_mb:.2f} MB | Last accessed: {os.path.getatime(dir_path)}") try: # Delete the entire directory tree shutil.rmtree(dir_path) freed_bytes += dir_size_bytes print(f"Deleted! Total freed so far: {freed_bytes / 1024 / 1024:.2f} MB") except PermissionError: print(f"Warning: Can't delete {dir_path} — permission denied. Skipping.") except Exception as e: print(f"Error deleting {dir_path}: {str(e)}. Skipping.") # Final status update if freed_bytes >= bytes_to_free: print(f"\n✅ Success! Freed {freed_bytes / 1024 / 1024:.2f} MB, which meets your target of {mb_to_free} MB.") else: print(f"\n⚠️ Warning: Only freed {freed_bytes / 1024 / 1024:.2f} MB. Couldn't reach the target — no more directories to delete.") # Example usage (test with a dummy directory first!): # disk_cleanup("/path/to/your/test/directory", 500) # Free up 500 MB
Key Notes for You (As a Python Newbie)
os.scandir()vsos.listdir():scandiris more efficient because it caches metadata, which saves us from callingos.stat()on every entry separately.- Error Handling: We added catches for
PermissionErrorandFileNotFoundErrorso the function doesn't crash if it runs into issues—super important for scripts that modify files/directories. - Unit Conversion: All file size functions in Python use bytes, so we convert MB to bytes by multiplying by
1024 * 1024(since 1 MB = 1024 KB, 1 KB = 1024 bytes). - Testing: Always test with a dummy directory first! Create a folder with test subdirectories and files to verify the function works before using it on important data.
内容的提问来源于stack exchange,提问作者chross

