本文目录导读:

跨平台Python脚本(推荐)
#!/usr/bin/env python3
"""
批量清除文件元数据脚本
支持:图片、文档、视频等常见格式
"""
import os
import sys
from pathlib import Path
import argparse
def clear_metadata(file_path):
"""清除单个文件的元数据"""
try:
file_path = Path(file_path)
# 根据文件类型选择处理方法
suffix = file_path.suffix.lower()
if suffix in ['.jpg', '.jpeg', '.png', '.tiff', '.bmp', '.gif']:
# 图片文件 - 使用PIL
from PIL import Image
img = Image.open(file_path)
# 创建无元数据的新图片
data = list(img.getdata())
img_no_meta = Image.new(img.mode, img.size)
img_no_meta.putdata(data)
img_no_meta.save(file_path, quality='keep')
elif suffix in ['.mp4', '.avi', '.mov', '.mkv', '.flv']:
# 视频文件 - 使用ffmpeg
import subprocess
temp_path = file_path.with_suffix(f'.temp{suffix}')
subprocess.run([
'ffmpeg', '-i', str(file_path),
'-map_metadata', '-1',
'-c', 'copy',
str(temp_path)
], capture_output=True)
temp_path.replace(file_path)
elif suffix in ['.pdf']:
# PDF文件 - 使用pikepdf
import pikepdf
with pikepdf.open(file_path) as pdf:
pdf.metadata = None
pdf.save(file_path)
elif suffix in ['.docx', '.xlsx', '.pptx']:
# Office文档 - 使用python-docx/openpyxl
from docx import Document
doc = Document(file_path)
# 清除默认元数据
doc.core_properties.author = None
doc.core_properties.title = None
doc.core_properties.subject = None
doc.core_properties.keywords = None
doc.save(file_path)
else:
# 通用文件 - 使用exiftool(如果可用)
import shutil
if shutil.which('exiftool'):
import subprocess
subprocess.run(['exiftool', '-all=', str(file_path)], capture_output=True)
# 删除备份文件
backup = file_path.with_suffix(f'{file_path.suffix}_original')
if backup.exists():
backup.unlink()
return True
except Exception as e:
print(f"处理 {file_path} 时出错: {e}")
return False
def batch_clear_metadata(directory, recursive=False, file_types=None):
"""批量清除元数据"""
directory = Path(directory)
if not directory.exists():
print(f"目录不存在: {directory}")
return
# 支持的扩展名
supported_types = {
'.jpg', '.jpeg', '.png', '.tiff', '.bmp', '.gif',
'.mp4', '.avi', '.mov', '.mkv', '.flv',
'.pdf', '.docx', '.xlsx', '.pptx'
}
if file_types:
file_types = {f'.{t.strip(".").lower()}' for t in file_types.split(',')}
supported_types = supported_types.intersection(file_types)
# 遍历文件
pattern = '**/*' if recursive else '*'
success_count = 0
fail_count = 0
for file_path in directory.glob(pattern):
if file_path.is_file() and file_path.suffix.lower() in supported_types:
print(f"处理: {file_path}")
if clear_metadata(file_path):
success_count += 1
else:
fail_count += 1
print(f"\n处理完成!")
print(f"成功: {success_count}")
print(f"失败: {fail_count}")
def main():
parser = argparse.ArgumentParser(description='批量清除文件元数据')
parser.add_argument('directory', help='要处理的目录路径')
parser.add_argument('-r', '--recursive', action='store_true',
help='递归处理子目录')
parser.add_argument('-t', '--types',
help='指定文件类型(逗号分隔,如: jpg,png,pdf)')
args = parser.parse_args()
# 检查依赖
try:
from PIL import Image
except ImportError:
print("请安装PIL库: pip install Pillow")
sys.exit(1)
batch_clear_metadata(args.directory, args.recursive, args.types)
if __name__ == '__main__':
main()
Windows PowerShell脚本
# batch-clear-metadata.ps1
param(
[Parameter(Mandatory=$true)]
[string]$Path,
[switch]$Recurse,
[string]$FileTypes = "*"
)
function Clear-FileMetadata {
param([string]$FilePath)
try {
$shell = New-Object -ComObject Shell.Application
$folder = $shell.Namespace((Get-Item $FilePath).DirectoryName)
$file = $folder.ParseName((Get-Item $FilePath).Name)
# 清除常见元数据属性
$properties = @(
4, # 标题
5, # 主题
6, # 作者
7, # 标签
8, # 注释
9, # 创建日期
12, # 上次保存时间
14, # 页数
15, # 程序名称
16, # 创建时间
18, # 修改时间
20, # 持续时间
25, # 相机型号
26, # 相机厂商
27, # F-stop
28, # 曝光时间
29, # ISO速度
30, # 闪光灯模式
31, # 焦距
32, # 传感器大小
34, # 分辨率
36, # 压缩
38, # 音频格式
39, # 音频比特率
40, # 视频格式
41, # 视频高度
42, # 视频宽度
43, # 帧率
)
foreach ($prop in $properties) {
try {
$folder.GetDetailsOf($file, $prop) # 这只是读取
# 注意:COM方式不能直接清空,这里只是示例
} catch {}
}
Write-Host "已处理: $FilePath" -ForegroundColor Green
return $true
}
catch {
Write-Host "处理失败: $FilePath - $_" -ForegroundColor Red
return $false
}
}
function Invoke-BatchClear {
param(
[string]$Path,
[bool]$Recurse,
[string]$FileTypes
)
$success = 0
$failed = 0
$items = if ($Recurse) {
Get-ChildItem -Path $Path -Recurse -File
} else {
Get-ChildItem -Path $Path -File
}
foreach ($item in $items) {
if ($FileTypes -eq "*" -or $item.Extension -match $FileTypes.Replace("*", ".*")) {
if (Clear-FileMetadata -FilePath $item.FullName) {
$success++
} else {
$failed++
}
}
}
Write-Host "`n处理完成!" -ForegroundColor Yellow
Write-Host "成功: $success"
Write-Host "失败: $failed"
}
# 执行批量处理
Invoke-BatchClear -Path $Path -Recurse $Recurse.IsPresent -FileTypes $FileTypes
Linux/macOS Bash脚本
#!/bin/bash
# batch-clear-metadata.sh
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 显示使用说明
usage() {
echo "用法: $0 [-r] [-t file_types] <directory>"
echo "选项:"
echo " -r 递归处理子目录"
echo " -t types 指定文件类型(逗号分隔,如: jpg,png,pdf)"
echo " -h 显示帮助信息"
exit 1
}
# 检查依赖
check_dependencies() {
local deps=("exiftool" "ffmpeg")
local missing=()
for dep in "${deps[@]}"; do
if ! command -v $dep &> /dev/null; then
missing+=($dep)
fi
done
if [ ${#missing[@]} -ne 0 ]; then
echo -e "${RED}缺少依赖: ${missing[*]}${NC}"
echo "请安装:"
echo " exiftool: sudo apt install libimage-exiftool-perl (Ubuntu)"
echo " brew install exiftool (macOS)"
echo " ffmpeg: sudo apt install ffmpeg (Ubuntu)"
echo " brew install ffmpeg (macOS)"
exit 1
fi
}
# 清除单个文件元数据
clear_metadata() {
local file="$1"
local ext="${file##*.}"
ext=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
case "$ext" in
jpg|jpeg|png|tiff|bmp|gif)
# 图片文件
exiftool -all= "$file" 2>/dev/null
# 删除备份文件
rm -f "${file}_original"
;;
mp4|avi|mov|mkv|flv)
# 视频文件
local temp_file="${file}.temp.${ext}"
ffmpeg -i "$file" -map_metadata -1 -c copy "$temp_file" -y 2>/dev/null
if [ -f "$temp_file" ]; then
mv "$temp_file" "$file"
fi
;;
pdf)
# PDF文件 - 需要qpdf
if command -v qpdf &> /dev/null; then
local temp_file="${file}.temp.pdf"
qpdf --linearize --object-streams=disable "$file" "$temp_file" 2>/dev/null
if [ -f "$temp_file" ]; then
mv "$temp_file" "$file"
fi
else
echo -e "${YELLOW}qpdf未安装,跳过PDF处理${NC}"
return 1
fi
;;
docx|xlsx|pptx)
# Office文档 - 使用unzip和zip
local temp_dir=$(mktemp -d)
unzip -q "$file" -d "$temp_dir" 2>/dev/null
# 清除元数据XML
if [ -f "$temp_dir/docProps/core.xml" ]; then
cat > "$temp_dir/docProps/core.xml" << 'EOF'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<coreProperties xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties">
</coreProperties>
EOF
fi
# 重新打包
local temp_file="${file}.temp.docx"
cd "$temp_dir" && zip -q -r "$temp_file" . 2>/dev/null
cd - > /dev/null
if [ -f "$temp_file" ]; then
mv "$temp_file" "$file"
fi
rm -rf "$temp_dir"
;;
*)
# 其他文件 - 使用exiftool
exiftool -all= "$file" 2>/dev/null
rm -f "${file}_original"
;;
esac
return $?
}
# 批量处理
process_directory() {
local dir="$1"
local recursive="$2"
local types="$3"
local success=0
local failed=0
# 构建find参数
if [ "$recursive" = true ]; then
find_cmd="find \"$dir\" -type f"
else
find_cmd="find \"$dir\" -maxdepth 1 -type f"
fi
# 添加文件类型过滤
if [ -n "$types" ]; then
local ext_filter=""
IFS=',' read -ra EXTS <<< "$types"
for ext in "${EXTS[@]}"; do
ext=$(echo "$ext" | xargs) # trim
if [ -z "$ext_filter" ]; then
ext_filter="-name \"*.${ext}\""
else
ext_filter="$ext_filter -o -name \"*.${ext}\""
fi
done
if [ -n "$ext_filter" ]; then
find_cmd="$find_cmd \\( $ext_filter \\)"
fi
fi
# 执行处理
eval "$find_cmd" | while read -r file; do
echo -e "处理: $file"
if clear_metadata "$file"; then
echo -e "${GREEN}成功${NC}: $file"
((success++))
else
echo -e "${RED}失败${NC}: $file"
((failed++))
fi
done
echo -e "\n${YELLOW}处理完成!${NC}"
echo "成功: $success"
echo "失败: $failed"
}
# 主程序
main() {
local recursive=false
local types=""
# 解析参数
while getopts "rt:h" opt; do
case $opt in
r) recursive=true ;;
t) types="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
done
shift $((OPTIND-1))
if [ $# -lt 1 ]; then
usage
fi
directory="$1"
if [ ! -d "$directory" ]; then
echo -e "${RED}错误: 目录不存在: $directory${NC}"
exit 1
fi
# 检查依赖
check_dependencies
# 开始处理
echo -e "${YELLOW}开始批量清除元数据...${NC}"
echo "目录: $directory"
echo "递归: $recursive"
echo "类型: ${types:-所有}"
echo "----------------------------------------"
process_directory "$directory" "$recursive" "$types"
}
# 运行主程序
main "$@"
使用说明
Python脚本使用:
# 安装依赖 pip install Pillow pikepdf python-docx openpyxl # 基本使用 python clear_metadata.py /path/to/directory # 递归处理 python clear_metadata.py /path/to/directory -r # 指定文件类型 python clear_metadata.py /path/to/directory -t jpg,png,pdf
PowerShell脚本使用:
# 执行策略设置(如果需要) Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # 基本使用 .\batch-clear-metadata.ps1 -Path "C:\Users\YourName\Pictures" # 递归处理 .\batch-clear-metadata.ps1 -Path "C:\Users\YourName\Documents" -Recurse # 指定类型 .\batch-clear-metadata.ps1 -Path "C:\Users\YourName\Desktop" -FileTypes "*.jpg;*.png"
Bash脚本使用:
# 给予执行权限 chmod +x batch-clear-metadata.sh # 基本使用 ./batch-clear-metadata.sh /path/to/directory # 递归处理 ./batch-clear-metadata.sh -r /path/to/directory # 指定类型 ./batch-clear-metadata.sh -t jpg,png,pdf /path/to/directory # 显示帮助 ./batch-clear-metadata.sh -h
注意事项
- 备份重要文件:元数据清除不可逆,建议先备份
- 依赖安装:确保安装所需工具(exiftool、ffmpeg等)
- 权限问题:可能需要管理员权限访问某些文件
- 大文件处理:视频文件处理较慢,请耐心等待
选择适合你操作系统的脚本,根据需要调整参数即可。