如何编写自动生成文件夹快照脚本

wen 实用脚本 2

本文目录导读:

如何编写自动生成文件夹快照脚本

  1. Python版本(最全面、跨平台)
  2. Shell脚本版本(Linux/macOS)
  3. PowerShell版本(Windows)
  4. 使用方法
  5. 功能特点

我来提供一个跨平台的文件夹快照生成脚本,包含多个实用版本。

Python版本(最全面、跨平台)

#!/usr/bin/env python3
"""
文件夹快照生成器
功能:生成文件夹结构、文件大小、修改时间等信息
"""
import os
import json
import hashlib
from datetime import datetime
from pathlib import Path
def get_file_info(file_path, base_path):
    """获取文件详细信息"""
    try:
        stat = file_path.stat()
        rel_path = str(file_path.relative_to(base_path))
        # 计算文件哈希(可选,用于检测文件变化)
        # sha256_hash = hashlib.sha256()
        # with open(file_path, "rb") as f:
        #     for byte_block in iter(lambda: f.read(4096), b""):
        #         sha256_hash.update(byte_block)
        # file_hash = sha256_hash.hexdigest()
        return {
            "path": rel_path,
            "type": "file",
            "size": stat.st_size,
            "size_human": format_size(stat.st_size),
            "modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
            "created": datetime.fromtimestamp(stat.st_ctime).isoformat(),
            "permissions": oct(stat.st_mode)[-3:]
            # "hash": file_hash  # 启用哈希计算
        }
    except (OSError, IOError) as e:
        return {
            "path": str(file_path),
            "type": "file",
            "error": str(e)
        }
def get_dir_info(dir_path, base_path):
    """获取目录信息"""
    try:
        rel_path = str(dir_path.relative_to(base_path))
        stat = dir_path.stat()
        return {
            "path": rel_path,
            "type": "directory",
            "modified": datetime.fromtimestamp(stat.st_mtime).isoformat(),
            "created": datetime.fromtimestamp(stat.st_ctime).isoformat(),
            "permissions": oct(stat.st_mode)[-3:]
        }
    except (OSError, IOError) as e:
        return {
            "path": str(dir_path),
            "type": "directory",
            "error": str(e)
        }
def format_size(size_bytes):
    """格式化文件大小"""
    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 generate_snapshot(directory, output_format='json', exclude_patterns=None):
    """生成文件夹快照"""
    base_path = Path(directory).resolve()
    if not base_path.exists():
        print(f"错误: 路径 {directory} 不存在")
        return None
    snapshot = {
        "snapshot_info": {
            "generated_at": datetime.now().isoformat(),
            "base_path": str(base_path),
            "total_items": 0,
            "total_size": 0,
            "total_files": 0,
            "total_dirs": 0
        },
        "items": []
    }
    # 默认排除模式
    if exclude_patterns is None:
        exclude_patterns = ['.git', '__pycache__', '.DS_Store', 'node_modules']
    try:
        for root, dirs, files in os.walk(base_path):
            # 排除指定目录
            dirs[:] = [d for d in dirs if d not in exclude_patterns]
            root_path = Path(root)
            # 添加目录信息(跳过根目录)
            if root_path != base_path:
                dir_info = get_dir_info(root_path, base_path)
                snapshot['items'].append(dir_info)
                snapshot['snapshot_info']['total_dirs'] += 1
            # 添加文件信息
            for file in files:
                if file in exclude_patterns:
                    continue
                file_path = root_path / file
                file_info = get_file_info(file_path, base_path)
                if 'error' not in file_info:
                    snapshot['snapshot_info']['total_size'] += file_info['size']
                    snapshot['snapshot_info']['total_files'] += 1
                snapshot['items'].append(file_info)
        snapshot['snapshot_info']['total_items'] = len(snapshot['items'])
        # 格式化总大小
        snapshot['snapshot_info']['total_size_human'] = format_size(
            snapshot['snapshot_info']['total_size']
        )
        return snapshot
    except Exception as e:
        print(f"生成快照时出错: {e}")
        return None
def save_snapshot(snapshot, output_file, output_format='json'):
    """保存快照到文件"""
    if output_format == 'json':
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(snapshot, f, ensure_ascii=False, indent=2)
        print(f"快照已保存到: {output_file}")
    elif output_format == 'txt':
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(f"文件夹快照报告\n")
            f.write(f"{'='*60}\n\n")
            f.write(f"生成时间: {snapshot['snapshot_info']['generated_at']}\n")
            f.write(f"路径: {snapshot['snapshot_info']['base_path']}\n")
            f.write(f"总计: {snapshot['snapshot_info']['total_items']} 个项目\n")
            f.write(f"文件: {snapshot['snapshot_info']['total_files']} 个\n")
            f.write(f"目录: {snapshot['snapshot_info']['total_dirs']} 个\n")
            f.write(f"总大小: {snapshot['snapshot_info']['total_size_human']}\n\n")
            f.write(f"{'='*60}\n\n")
            for item in snapshot['items']:
                if item['type'] == 'file':
                    f.write(f"[文件] {item['path']} ({item['size_human']})\n")
                else:
                    f.write(f"[目录] {item['path']}\n")
    print(f"快照统计: 共 {snapshot['snapshot_info']['total_items']} 个项目")
    print(f"         {snapshot['snapshot_info']['total_files']} 个文件")
    print(f"         {snapshot['snapshot_info']['total_dirs']} 个目录")
    print(f"         总大小: {snapshot['snapshot_info']['total_size_human']}")
def main():
    import argparse
    parser = argparse.ArgumentParser(description='文件夹快照生成器')
    parser.add_argument('directory', help='要扫描的目录路径')
    parser.add_argument('-o', '--output', default='snapshot.json',
                       help='输出文件路径 (默认: snapshot.json)')
    parser.add_argument('-f', '--format', choices=['json', 'txt'], 
                       default='json', help='输出格式 (默认: json)')
    parser.add_argument('-e', '--exclude', nargs='*', 
                       default=['.git', '__pycache__', '.DS_Store', 'node_modules'],
                       help='排除的文件/目录名')
    args = parser.parse_args()
    print(f"正在扫描文件夹: {args.directory}")
    snapshot = generate_snapshot(args.directory, args.format, args.exclude)
    if snapshot:
        save_snapshot(snapshot, args.output, args.format)
if __name__ == "__main__":
    main()

Shell脚本版本(Linux/macOS)

#!/bin/bash
# 文件夹快照生成器 - Shell版本
# 默认配置
OUTPUT_FILE="snapshot_$(date +%Y%m%d_%H%M%S).txt"
TARGET_DIR="${1:-.}"
EXCLUDE_PATTERNS=(".git" "__pycache__" ".DS_Store" "node_modules")
print_header() {
    echo "========================================"
    echo "文件夹快照报告"
    echo "========================================"
    echo "生成时间: $(date '+%Y-%m-%d %H:%M:%S')"
    echo "扫描路径: $(cd "$TARGET_DIR" && pwd)"
    echo "========================================"
    echo
}
print_tree() {
    local dir="$1"
    local prefix="$2"
    # 获取文件和目录列表
    local items=()
    while IFS= read -r -d '' item; do
        items+=("$item")
    done < <(find "$dir" -maxdepth 1 -mindepth 1 -print0 | sort -z)
    local count=${#items[@]}
    local index=0
    for item in "${items[@]}"; do
        local name=$(basename "$item")
        # 检查是否需要排除
        local exclude=false
        for pattern in "${EXCLUDE_PATTERNS[@]}"; do
            if [[ "$name" == "$pattern" ]]; then
                exclude=true
                break
            fi
        done
        [[ $exclude == true ]] && continue
        ((index++))
        if [ $index -eq $count ]; then
            echo "${prefix}└── $name"
            new_prefix="${prefix}    "
        else
            echo "${prefix}├── $name"
            new_prefix="${prefix}│   "
        fi
        if [ -d "$item" ]; then
            print_tree "$item" "$new_prefix"
        fi
    done
}
generate_snapshot() {
    {
        print_header
        # 文件树
        echo "文件树结构:"
        echo "----------------------------------------"
        print_tree "$TARGET_DIR" ""
        echo
        # 文件统计
        echo "文件统计:"
        echo "----------------------------------------"
        echo "总文件数: $(find "$TARGET_DIR" -type f | wc -l)"
        echo "总目录数: $(find "$TARGET_DIR" -type d | wc -l)"
        # 计算总大小(排除隐藏目录和macOS的.DS_Store)
        local total_size=$(du -sh --exclude='.git' "$TARGET_DIR" 2>/dev/null | cut -f1)
        echo "总大小: $total_size"
        echo
        # 按类型统计
        echo "文件类型统计:"
        echo "----------------------------------------"
        find "$TARGET_DIR" -type f | while read -r file; do
            ext="${file##*.}"
            echo "$ext"
        done | sort | uniq -c | sort -rn | head -20
        echo
        # 大文件列表
        echo "最大的10个文件:"
        echo "----------------------------------------"
        find "$TARGET_DIR" -type f -exec ls -lh {} \; 2>/dev/null | \
            sort -k5 -rh | head -10
        echo
        # 最新修改的文件
        echo "最近修改的10个文件:"
        echo "----------------------------------------"
        find "$TARGET_DIR" -type f -exec ls -lt {} \; 2>/dev/null | \
            head -10
    } > "$OUTPUT_FILE"
    echo "快照已生成: $OUTPUT_FILE"
    cat "$OUTPUT_FILE"
}
# 主程序
if [ ! -d "$TARGET_DIR" ]; then
    echo "错误: 目录 $TARGET_DIR 不存在"
    exit 1
fi
generate_snapshot

PowerShell版本(Windows)

# Windows文件夹快照生成器 - PowerShell版本
param(
    [string]$TargetPath = (Get-Location).Path,
    [string]$OutputFile = "snapshot_$((Get-Date).ToString('yyyyMMdd_HHmmss')).txt",
    [string[]]$ExcludePatterns = @('.git', '__pycache__', '.DS_Store', 'node_modules', '.vs')
)
function Format-FileSize {
    param([long]$bytes)
    $sizes = @('B', 'KB', 'MB', 'GB', 'TB')
    $index = 0
    while ($bytes -ge 1024 -and $index -lt $sizes.Length - 1) {
        $bytes /= 1024
        $index++
    }
    return "{0:N2} {1}" -f $bytes, $sizes[$index]
}
function Write-Snapshot {
    param(
        [string]$Path,
        [string]$Indent = ""
    )
    $items = Get-ChildItem -Path $Path -Force | Where-Object {
        $_.Name -notin $ExcludePatterns
    } | Sort-Object -Property PSIsContainer, Name
    $count = ($items | Measure-Object).Count
    $index = 0
    foreach ($item in $items) {
        $index++
        $prefix = if ($index -eq $count) { "└── " } else { "├── " }
        $newIndent = if ($index -eq $count) { "    " } else { "│   " }
        if ($item.PSIsContainer) {
            Write-Output "$Indent$prefix[$($item.Name)]"
            Write-Snapshot -Path $item.FullName -Indent "$Indent$newIndent"
        } else {
            $size = Format-FileSize -bytes $item.Length
            $modified = $item.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
            Write-Output "$Indent$prefix$($item.Name) ($size, $modified)"
        }
    }
}
# 主程序
if (-not (Test-Path -Path $TargetPath)) {
    Write-Error "错误: 目录 $TargetPath 不存在"
    exit 1
}
# 生成快照内容
$content = @"
========================================
文件夹快照报告
========================================
生成时间: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
扫描路径: $((Resolve-Path $TargetPath).Path)
========================================
文件结构:
----------------------------------------
"@
# 准备写入文件
$content | Out-File -FilePath $OutputFile -Encoding UTF8
# 递归生成文件树
$treeOutput = Write-Snapshot -Path $TargetPath -Indent ""
$treeOutput | Out-File -FilePath $OutputFile -Encoding UTF8 -Append
# 统计信息
$stats = @"
文件统计:
----------------------------------------
总文件数: $(Get-ChildItem -Path $TargetPath -Recurse -File | Where-Object { $_.Name -notin $ExcludePatterns } | Measure-Object | Select-Object -ExpandProperty Count)
总目录数: $(Get-ChildItem -Path $TargetPath -Recurse -Directory | Where-Object { $_.Name -notin $ExcludePatterns } | Measure-Object | Select-Object -ExpandProperty Count)
总大小: $(Format-FileSize -bytes ((Get-ChildItem -Path $TargetPath -Recurse -File | Where-Object { $_.Name -notin $ExcludePatterns } | Measure-Object -Property Length -Sum).Sum))
最近修改的文件:
----------------------------------------
"@
$stats | Out-File -FilePath $OutputFile -Encoding UTF8 -Append
# 列出最近修改的文件
Get-ChildItem -Path $TargetPath -Recurse -File | 
    Where-Object { $_.Name -notin $ExcludePatterns } |
    Sort-Object -Property LastWriteTime -Descending |
    Select-Object -First 10 -Property Name, LastWriteTime, Length |
    ForEach-Object {
        $size = Format-FileSize -bytes $_.Length
        "$($_.Name) - $($_.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss')) - $size"
    } | Out-File -FilePath $OutputFile -Encoding UTF8 -Append
Write-Host "快照已生成: $OutputFile"

使用方法

Python版本

# 基本用法
python snapshot.py /path/to/folder
# 指定输出格式和文件
python snapshot.py /path/to/folder -o report.txt -f txt
# 自定义排除项
python snapshot.py /path/to/folder -e .git .svn temp_cache

Shell版本

# 设置执行权限
chmod +x snapshot.sh
# 基本用法
./snapshot.sh /path/to/folder
# 使用当前目录
./snapshot.sh

PowerShell版本

# 基本用法
.\snapshot.ps1 -TargetPath "C:\YourFolder"
# 使用当前目录
.\snapshot.ps1

功能特点

  1. 递归扫描:完整展示文件夹结构
  2. 文件统计:数量、大小、类型分布
  3. 时间信息:创建时间、修改时间
  4. 大文件检测:找出占用空间大的文件
  5. 排除机制:忽略不需要的目录和文件
  6. 多种格式:支持JSON和TXT格式输出
  7. 跨平台:支持Windows、Linux、macOS

选择适合您操作系统的版本,根据需求调整配置即可。

抱歉,评论功能暂时关闭!