Python技术问询:如何将文件复制到已有文件的目录且不覆盖?
Got it, let's break down how to solve your problem—aggregating files from heterogeneous source directories into a single target folder, without overwriting any existing files. You mentioned you can already set up the target directory and copy initial files, but need to handle subsequent copies without conflicts. Here are practical, cross-platform solutions:
1. Command-Line Tools (Quick & No Code)
These are great for one-off tasks or scripting in shell/batch files.
Linux/macOS
Use rsync (more robust than cp for recursive operations):
rsync -av --ignore-existing /path/to/source/ /path/to/destination/
-a: Archive mode (preserves permissions, timestamps, and recurses through directories)-v: Verbose output (so you can see what's being copied/skipped)--ignore-existing: Skips any files that already exist in the target directory
If you prefer cp for simpler cases:
cp -rn /path/to/source/* /path/to/destination/
-r: Recursively copy directories-n: No-clobber (won't overwrite existing files)
Windows
Use robocopy (built into modern Windows versions):
robocopy C:\path\to\source C:\path\to\destination /E /XC /XN /XO
/E: Copies all subdirectories, including empty ones/XC: Excludes files that already exist in the target and have identical content/XN: Excludes files that are newer in the target/XO: Excludes files that are older in the target
Together, these flags ensure only files that don't exist in the destination get copied.
2. Python Script (Automated & Customizable)
If you need more control (like handling duplicate filenames or flattening directory structures), a Python script is perfect.
Option A: Preserve Source Directory Structure
This copies files while keeping their original folder hierarchy in the target:
import os import shutil def copy_without_overwrite(src, dest): # Recursively walk through the source directory for root, _, files in os.walk(src): # Calculate the corresponding subdirectory in the target relative_path = os.path.relpath(root, src) target_dir = os.path.join(dest, relative_path) # Create the target subdirectory if it doesn't exist (no error if it does) os.makedirs(target_dir, exist_ok=True) for filename in files: src_file = os.path.join(root, filename) target_file = os.path.join(target_dir, filename) # Only copy if the file doesn't exist in the target if not os.path.exists(target_file): shutil.copy2(src_file, target_file) print(f"Copied: {src_file} → {target_file}") else: print(f"Skipped (exists): {target_file}") # Example usage copy_without_overwrite("/home/user/source_files", "/home/user/aggregated_files")
shutil.copy2: Preserves file metadata (timestamps, permissions) unlikeshutil.copyos.makedirs(exist_ok=True): Safely creates directories without throwing errors if they already exist
Option B: Flatten All Files Into One Folder (Handle Duplicates)
If you want all files in the target folder (ignoring source subdirectories) and automatically rename duplicates:
import os import shutil def flatten_copy_without_overwrite(src, dest): # Ensure target directory exists os.makedirs(dest, exist_ok=True) for root, _, files in os.walk(src): for filename in files: src_file = os.path.join(root, filename) target_file = os.path.join(dest, filename) # Rename duplicates (e.g., "file.txt" → "file_1.txt", "file_2.txt") counter = 1 while os.path.exists(target_file): name, ext = os.path.splitext(filename) target_file = os.path.join(dest, f"{name}_{counter}{ext}") counter += 1 shutil.copy2(src_file, target_file) print(f"Copied: {src_file} → {target_file}") # Example usage flatten_copy_without_overwrite("C:\\Users\\User\\Source", "C:\\Users\\User\\Aggregated")
Key Notes
- Permissions: Make sure you have read access to source files and write access to the target directory
- Symbolic Links: If you need to handle symlinks, add checks with
os.path.islink()and useshutil.copyfile()oros.symlink()depending on your needs - Large Files: For very large datasets,
rsyncis more efficient than Python scripts since it checks file differences before copying
Let me know if you need tweaks for specific edge cases!
内容的提问来源于stack exchange,提问作者Legion

