本文目录导读:

跨平台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等)
- 权限问题:可能需要管理员权限访问某些文件
- 大文件处理:视频文件处理较慢,请耐心等待
选择适合你操作系统的脚本,根据需要调整参数即可。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播