Linux bzip2recover命令

工具说明:bzip2recover是一个专门用于从损坏的.bz2压缩文件中尝试恢复数据的工具。当bzip2文件因传输错误、存储损坏或其他原因无法正常解压时,可以尝试使用此工具恢复部分或全部数据。
工作原理:bzip2recover利用bzip2压缩文件的块结构特性,扫描损坏的文件,查找完整的压缩块,并将每个完整的压缩块保存为单独的文件。然后可以尝试解压这些恢复的块来获取数据。
主要功能
  • 扫描损坏的.bz2文件
  • 查找完整的压缩块
  • 将完整块保存为单独文件
  • 尝试恢复部分或全部数据
  • 处理传输中断的文件
  • 处理存储损坏的文件
使用场景
  • 下载中断的压缩文件
  • 磁盘损坏导致的文件损坏
  • 网络传输错误
  • 存储介质故障
  • 不完整备份文件
  • 意外中断的压缩过程

命令语法

语法格式
bzip2recover [损坏的.bz2文件]

命令参数

参数 说明
-h, --help 显示帮助信息
-V, --version 显示版本信息
文件名 损坏的.bz2文件(必需参数)

使用示例

1. 基本恢复操作 常用
示例
# 尝试恢复损坏的.bz2文件
bzip2recover damaged_file.bz2

# 执行后会产生类似以下输出:
# bzip2recover 1.0.8: extracts blocks from damaged .bz2 files.
# bzip2recover: searching for block boundaries ...
# bzip2recover: splitting into blocks
# 0:  [0 .. 1048574]  1048575 bytes
# 1:  [1048575 .. 2097150]  1048576 bytes
# 2:  [2097151 .. 3145726]  1048576 bytes
# 3:  [3145727 .. 4194302]  1048576 bytes
# 4:  [4194303 .. 4403200]  209798 bytes
# bzip2recover: 5 blocks found.

# 生成的文件:
# rec00001damaged_file.bz2
# rec00002damaged_file.bz2
# rec00003damaged_file.bz2
# rec00004damaged_file.bz2
# rec00005damaged_file.bz2

# 尝试解压恢复的文件
for f in rec*.bz2; do
    echo "尝试解压: $f"
    bunzip2 -t "$f" 2>/dev/null && echo "  ✓ 文件完整" || echo "  ✗ 文件损坏"
done
2. 恢复并解压数据
# 恢复损坏的文件
bzip2recover corrupted_data.bz2

# 遍历所有恢复的块文件
for recovered_file in rec*corrupted_data.bz2; do
    echo "处理: $recovered_file"

    # 尝试解压
    if bunzip2 -t "$recovered_file" 2>/dev/null; then
        echo "  ✓ 块文件完整,正在解压..."

        # 解压到单独文件
        output_file="${recovered_file%.bz2}.txt"
        bunzip2 -c "$recovered_file" > "recovered_${output_file}"

        # 检查解压文件大小
        file_size=$(stat -c%s "recovered_${output_file}" 2>/dev/null || echo 0)
        if [ "$file_size" -gt 0 ]; then
            echo "  ✓ 解压成功: recovered_${output_file} (${file_size} 字节)"
        else
            echo "  ✗ 解压失败"
        fi
    else
        echo "  ✗ 块文件损坏,跳过"
    fi
done

echo "恢复完成"
3. 处理不完整下载文件
# 检查文件是否损坏
echo "检查文件完整性..."
if bunzip2 -t partial_download.bz2 2>/dev/null; then
    echo "文件完整,无需恢复"
    bunzip2 partial_download.bz2
else
    echo "文件损坏,尝试恢复..."

    # 运行恢复工具
    bzip2recover partial_download.bz2

    # 统计恢复的块
    block_count=$(ls -1 rec*partial_download.bz2 2>/dev/null | wc -l)
    echo "找到 $block_count 个完整块"

    if [ "$block_count" -gt 0 ]; then
        # 合并恢复的数据
        echo "合并恢复的数据..."
        for block in rec*partial_download.bz2; do
            bunzip2 -c "$block" 2>/dev/null >> recovered_data.txt
        done

        # 检查恢复结果
        recovered_size=$(stat -c%s recovered_data.txt 2>/dev/null || echo 0)
        echo "恢复数据大小: $recovered_size 字节"
    else
        echo "未能找到任何完整块"
    fi
fi

# 清理临时文件
rm -f rec*.bz2 2>/dev/null
4. 批量恢复多个损坏文件
#!/bin/bash
# 批量恢复损坏的.bz2文件

RECOVERY_DIR="recovered_files"
mkdir -p "$RECOVERY_DIR"

echo "=== 开始批量恢复.bz2文件 ==="

# 查找当前目录下所有.bz2文件
for bz2_file in *.bz2; do
    [ -f "$bz2_file" ] || continue

    echo "处理文件: $bz2_file"

    # 测试文件完整性
    if bunzip2 -t "$bz2_file" 2>/dev/null; then
        echo "  ✓ 文件完整,跳过恢复"
        continue
    fi

    echo "  ✗ 文件损坏,尝试恢复..."

    # 运行恢复工具
    bzip2recover "$bz2_file" 2>/dev/null

    # 检查恢复结果
    recovered_count=$(ls -1 rec*"$bz2_file" 2>/dev/null | wc -l)

    if [ "$recovered_count" -gt 0 ]; then
        echo "  ✓ 找到 $recovered_count 个完整块"

        # 为每个文件创建单独目录
        file_basename=$(basename "$bz2_file" .bz2)
        file_recovery_dir="$RECOVERY_DIR/$file_basename"
        mkdir -p "$file_recovery_dir"

        # 移动恢复的块文件
        mv rec*"$bz2_file" "$file_recovery_dir/" 2>/dev/null

        # 尝试解压每个块
        success_count=0
        for block in "$file_recovery_dir"/rec*.bz2; do
            [ -f "$block" ] || continue

            block_name=$(basename "$block" .bz2)
            if bunzip2 -t "$block" 2>/dev/null; then
                bunzip2 -c "$block" > "$file_recovery_dir/${block_name}.txt" 2>/dev/null
                if [ $? -eq 0 ]; then
                    success_count=$((success_count + 1))
                fi
            fi
        done

        echo "  ✓ 成功解压 $success_count/$recovered_count 个块"
    else
        echo "  ✗ 未能找到任何完整块"
    fi

    echo ""
done

echo "=== 批量恢复完成 ==="
echo "恢复文件保存在: $RECOVERY_DIR"
5. 恢复损坏的tar.bz2文件
#!/bin/bash
# 恢复损坏的.tar.bz2文件

CORRUPTED_TARBALL="backup.tar.bz2"
RECOVERY_DIR="recovered_tar"
EXTRACT_DIR="extracted_content"

mkdir -p "$RECOVERY_DIR" "$EXTRACT_DIR"

echo "恢复损坏的tar.bz2文件: $CORRUPTED_TARBALL"

# 步骤1: 尝试直接解压
echo "步骤1: 尝试直接解压..."
if tar -tjf "$CORRUPTED_TARBALL" 2>/dev/null; then
    echo "tar文件完整,直接解压..."
    tar -xjf "$CORRUPTED_TARBALL" -C "$EXTRACT_DIR"
    exit 0
else
    echo "tar文件损坏,需要恢复..."
fi

# 步骤2: 恢复压缩文件
echo -e "\n步骤2: 恢复压缩文件..."
bzip2recover "$CORRUPTED_TARBALL"

# 步骤3: 处理恢复的块
echo -e "\n步骤3: 处理恢复的块..."
block_count=0
for block in rec*.bz2; do
    [ -f "$block" ] || continue

    block_count=$((block_count + 1))
    echo "处理块 $block_count: $block"

    # 尝试解压块
    bunzip2 -c "$block" > "$RECOVERY_DIR/block_$block_count.tar" 2>/dev/null

    # 检查解压的tar文件
    if tar -tf "$RECOVERY_DIR/block_$block_count.tar" 2>/dev/null; then
        echo "  ✓ tar块有效,提取内容..."

        # 提取内容到单独目录
        mkdir -p "$EXTRACT_DIR/block_$block_count"
        tar -xf "$RECOVERY_DIR/block_$block_count.tar" -C "$EXTRACT_DIR/block_$block_count" 2>/dev/null

        # 记录恢复的文件
        find "$EXTRACT_DIR/block_$block_count" -type f | wc -l | \
            xargs echo "  恢复文件数:"
    else
        echo "  ✗ tar块损坏"
        rm -f "$RECOVERY_DIR/block_$block_count.tar"
    fi
done

# 步骤4: 合并恢复的数据
echo -e "\n步骤4: 合并恢复的数据..."
if [ "$block_count" -gt 0 ]; then
    echo "总共找到 $block_count 个块"
    echo "恢复的内容保存在: $EXTRACT_DIR"

    # 列出所有恢复的文件
    echo -e "\n恢复的文件列表:"
    find "$EXTRACT_DIR" -type f | head -20
else
    echo "未能恢复任何数据"
fi

echo -e "\n=== 恢复过程完成 ==="
6. 高级恢复脚本(带日志和报告)
#!/bin/bash
# 高级文件恢复脚本

set -e

# 配置
CORRUPTED_FILE="$1"
LOG_FILE="recovery_$(date +%Y%m%d_%H%M%S).log"
REPORT_FILE="recovery_report_$(date +%Y%m%d_%H%M%S).txt"
RECOVERY_BASE="recovery_$(date +%Y%m%d_%H%M%S)"

# 创建目录
mkdir -p "$RECOVERY_BASE/blocks" "$RECOVERY_BASE/extracted"

# 初始化日志
echo "=== bzip2文件恢复日志 ===" > "$LOG_FILE"
echo "开始时间: $(date)" >> "$LOG_FILE"
echo "损坏文件: $CORRUPTED_FILE" >> "$LOG_FILE"
echo "恢复目录: $RECOVERY_BASE" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"

# 函数:记录日志
log() {
    echo "[$(date +%H:%M:%S)] $1" | tee -a "$LOG_FILE"
}

# 函数:检查文件
check_file() {
    if [ ! -f "$CORRUPTED_FILE" ]; then
        log "错误: 文件不存在 - $CORRUPTED_FILE"
        exit 1
    fi

    if [[ ! "$CORRUPTED_FILE" =~ \.bz2$ ]]; then
        log "警告: 文件扩展名不是.bz2"
    fi

    file_size=$(stat -c%s "$CORRUPTED_FILE" 2>/dev/null || echo 0)
    log "文件大小: $(numfmt --to=iec $file_size)"
}

# 函数:测试文件完整性
test_integrity() {
    log "测试文件完整性..."
    if bunzip2 -t "$CORRUPTED_FILE" 2>/dev/null; then
        log "✓ 文件完整,无需恢复"
        return 0
    else
        log "✗ 文件损坏,需要恢复"
        return 1
    fi
}

# 主恢复函数
recover_file() {
    log "开始恢复过程..."

    # 运行bzip2recover
    log "执行: bzip2recover \"$CORRUPTED_FILE\""
    bzip2recover_output=$(bzip2recover "$CORRUPTED_FILE" 2>&1)
    echo "$bzip2recover_output" >> "$LOG_FILE"

    # 统计恢复的块
    recovered_blocks=$(ls -1 rec*.bz2 2>/dev/null | wc -l)
    log "找到 $recovered_blocks 个完整块"

    if [ "$recovered_blocks" -eq 0 ]; then
        log "⚠ 未能找到任何完整块"
        return 1
    fi

    # 处理每个块
    success_count=0
    for block in rec*.bz2; do
        block_name=$(basename "$block")
        log "处理块: $block_name"

        # 移动块文件
        mv "$block" "$RECOVERY_BASE/blocks/"

        # 测试块完整性
        if bunzip2 -t "$RECOVERY_BASE/blocks/$block_name" 2>/dev/null; then
            # 解压块
            output_name="${block_name%.bz2}.out"
            if bunzip2 -c "$RECOVERY_BASE/blocks/$block_name" > "$RECOVERY_BASE/extracted/$output_name" 2>/dev/null; then
                output_size=$(stat -c%s "$RECOVERY_BASE/extracted/$output_name" 2>/dev/null || echo 0)

                if [ "$output_size" -gt 0 ]; then
                    log "  ✓ 块恢复成功: $output_name ($(numfmt --to=iec $output_size))"
                    success_count=$((success_count + 1))
                else
                    log "  ✗ 块解压后大小为0"
                fi
            else
                log "  ✗ 块解压失败"
            fi
        else
            log "  ✗ 块本身损坏"
        fi
    done

    log "成功恢复 $success_count/$recovered_blocks 个块"
    return $success_count
}

# 生成报告
generate_report() {
    echo "=== 文件恢复报告 ===" > "$REPORT_FILE"
    echo "生成时间: $(date)" >> "$REPORT_FILE"
    echo "原始文件: $CORRUPTED_FILE" >> "$REPORT_FILE"
    echo "原始大小: $(numfmt --to=iec $(stat -c%s "$CORRUPTED_FILE"))" >> "$REPORT_FILE"
    echo "" >> "$REPORT_FILE"

    # 统计信息
    total_blocks=$(ls -1 "$RECOVERY_BASE/blocks/"*.bz2 2>/dev/null | wc -l)
    successful_extracts=$(ls -1 "$RECOVERY_BASE/extracted/"*.out 2>/dev/null | wc -l)

    echo "恢复统计:" >> "$REPORT_FILE"
    echo "  找到的完整块: $total_blocks" >> "$REPORT_FILE"
    echo "  成功解压块: $successful_extracts" >> "$REPORT_FILE"
    echo "" >> "$REPORT_FILE"

    # 恢复的文件列表
    echo "恢复的文件:" >> "$REPORT_FILE"
    for file in "$RECOVERY_BASE/extracted/"*.out; do
        [ -f "$file" ] || continue
        file_size=$(stat -c%s "$file")
        echo "  $(basename "$file"): $(numfmt --to=iec $file_size)" >> "$REPORT_FILE"
    done

    # 总恢复大小
    total_recovered=$(find "$RECOVERY_BASE/extracted" -type f -exec stat -c%s {} \; 2>/dev/null | awk '{sum+=$1} END {print sum}')
    echo "" >> "$REPORT_FILE"
    echo "总恢复数据: $(numfmt --to=iec $total_recovered)" >> "$REPORT_FILE"

    # 恢复率
    original_size=$(stat -c%s "$CORRUPTED_FILE")
    if [ "$original_size" -gt 0 ]; then
        recovery_rate=$(echo "scale=2; $total_recovered * 100 / $original_size" | bc)
        echo "恢复率: ${recovery_rate}%" >> "$REPORT_FILE"
    fi
}

# 主程序
main() {
    if [ -z "$CORRUPTED_FILE" ]; then
        echo "用法: $0 <损坏的.bz2文件>"
        exit 1
    fi

    log "=== 开始恢复过程 ==="
    check_file

    if test_integrity; then
        log "文件完整,无需恢复"
        exit 0
    fi

    if recover_file; then
        generate_report
        log "恢复完成,报告已生成: $REPORT_FILE"
        log "恢复数据保存在: $RECOVERY_BASE"

        echo -e "\n=== 恢复摘要 ==="
        echo "日志文件: $LOG_FILE"
        echo "报告文件: $REPORT_FILE"
        echo "恢复目录: $RECOVERY_BASE"
    else
        log "恢复失败"
        exit 1
    fi
}

# 执行主程序
main 2>&1 | tee -a "$LOG_FILE"

恢复流程详解

bzip2recover恢复过程
  1. 扫描文件:bzip2recover扫描损坏的.bz2文件,查找完整的压缩块
  2. 识别块边界:利用bzip2的块头标识(0x314159265359)识别块开始位置
  3. 分割文件:将每个完整的块保存为单独的文件(rec*.bz2格式)
  4. 块验证:对每个恢复的块进行完整性检查
  5. 数据提取:尝试解压完整的块获取原始数据
  6. 数据合并:将所有成功恢复的数据合并为完整文件
恢复成功率因素
损坏类型 恢复成功率 说明 建议操作
文件尾部损坏 只损坏最后一个块,前面块完整 使用bzip2recover,丢弃最后一个块
文件头部损坏 第一个块损坏,后面块可能完整 使用bzip2recover,跳过第一个块
中间部分损坏 损坏块周围的块可能完整 使用bzip2recover,恢复完整块
多点随机损坏 文件多处损坏,完整块很少 尝试恢复,但期望较低
完全损坏 极低 文件结构完全破坏 可能需要其他恢复工具
不完整下载 下载中断,文件不完整但结构完整 使用bzip2recover恢复已完成部分

恢复技巧和最佳实践

恢复前检查
  • 先使用bunzip2 -t测试文件完整性
  • 备份原始损坏文件
  • 检查磁盘空间是否充足
  • 记录文件原始大小和时间戳
  • 在副本上操作,保留原始文件
恢复过程建议
  • 使用日志记录恢复过程
  • 逐个测试恢复的块文件
  • 合并恢复的数据前先验证
  • 保留中间文件供调试
  • 对重要文件多次尝试恢复
手动恢复技巧
# 技巧1:使用dd跳过损坏部分
# 如果知道损坏位置,可以跳过损坏部分
dd if=damaged.bz2 of=partial.bz2 bs=1 skip=1000
bzip2recover partial.bz2

# 技巧2:尝试不同的块大小
# 修改bzip2recover源代码中的块大小定义
# 默认查找900KB块,可以尝试其他大小

# 技巧3:使用hex编辑器手动修复
# 1. 用hex编辑器打开损坏的.bz2文件
# 2. 查找BZIP2文件头: 42 5A 68 (BZh)
# 3. 查找块尾标识
# 4. 删除损坏部分,保存为新的.bz2文件
# 5. 尝试解压

# 技巧4:尝试部分解压
bunzip2 -c damaged.bz2 2>/dev/null | head -c 1000000 > partial_recovery.txt

# 技巧5:使用其他恢复工具
# 如PhotoRec、TestDisk等通用恢复工具

注意事项

重要注意事项:
  • 非保证恢复:bzip2recover不能保证100%恢复数据,成功率取决于损坏程度
  • 备份原始文件:恢复前务必备份原始损坏文件
  • 磁盘空间:恢复过程可能产生多个临时文件,需要足够磁盘空间
  • 时间消耗:大文件的恢复可能需要较长时间
  • 数据不完整:恢复的数据可能不完整,需要人工检查
  • 块顺序:恢复的块文件可能不是原始顺序,需要手动整理
  • 加密文件:bzip2recover无法恢复加密的.bz2文件
  • 版本兼容:确保bzip2recover版本与创建压缩文件的bzip2版本兼容

常见问题

A: 不能保证100%恢复。成功率取决于:
  • 损坏类型:尾部损坏容易恢复,多点损坏难恢复
  • 损坏程度:损坏越严重,恢复率越低
  • 文件结构:bzip2的块结构是否还能识别
  • 块大小:使用较小块大小(-1到-3)的文件更容易恢复
示例:
# 测试文件损坏程度
file_size=$(stat -c%s damaged.bz2)
echo "文件大小: $file_size 字节"

# 尝试恢复
bzip2recover damaged.bz2
block_count=$(ls rec*.bz2 2>/dev/null | wc -l)
echo "找到 $block_count 个完整块"

# 计算恢复率
if [ "$block_count" -gt 0 ]; then
    # 假设每个块平均800KB
    estimated_recovery=$((block_count * 800 * 1024))
    recovery_rate=$(echo "scale=2; $estimated_recovery * 100 / $file_size" | bc)
    echo "估计恢复率: ${recovery_rate}%"
fi

A: rec*.bz2文件是bzip2recover从损坏文件中提取的完整压缩块:
  • 命名规则:recNNNNN原文件名.bz2(如rec00001data.bz2)
  • 内容:每个文件包含一个完整的bzip2压缩块
  • 大小:通常为100KB-900KB,取决于原始压缩级别
  • 顺序:数字NNNNN表示块在原始文件中的顺序
  • 独立性:每个块可以独立解压
处理方法:
# 列出所有恢复的块
ls -lh rec*.bz2

# 查看块信息
for block in rec*.bz2; do
    echo "块: $block"
    bzip2 -lv "$block" 2>/dev/null | head -1
done

# 解压所有块
for block in rec*.bz2; do
    output_name="${block%.bz2}.txt"
    bunzip2 -c "$block" > "$output_name" 2>/dev/null && \
        echo "解压: $block -> $output_name"
done

# 合并所有解压的数据
cat rec*.txt > recovered_data.txt 2>/dev/null

A: 通过以下方法判断恢复是否成功:
  • 检查输出:查看bzip2recover的输出信息,确认找到的块数量
  • 检查文件:查看是否生成了rec*.bz2文件
  • 测试块:使用bunzip2 -t测试每个恢复的块
  • 解压测试:尝试解压块文件查看内容
  • 内容验证:检查解压后的数据是否可用
判断脚本:
#!/bin/bash
check_recovery() {
    echo "=== 恢复结果评估 ==="

    # 检查是否有恢复的块
    if [ ! -f rec*.bz2 ]; then
        echo "状态: 失败 - 未找到任何完整块"
        return 1
    fi

    block_count=$(ls -1 rec*.bz2 2>/dev/null | wc -l)
    echo "找到块数: $block_count"

    # 测试每个块
    valid_blocks=0
    for block in rec*.bz2; do
        if bunzip2 -t "$block" 2>/dev/null; then
            valid_blocks=$((valid_blocks + 1))
        fi
    done

    echo "有效块数: $valid_blocks"

    if [ "$valid_blocks" -eq 0 ]; then
        echo "状态: 失败 - 没有有效块"
        return 1
    elif [ "$valid_blocks" -eq "$block_count" ]; then
        echo "状态: 优秀 - 所有块都有效"
        return 0
    else
        echo "状态: 部分成功 - $valid_blocks/$block_count 个块有效"
        return 2
    fi
}

# 运行恢复
bzip2recover damaged.bz2

# 检查结果
check_recovery
result=$?

case $result in
    0) echo "恢复非常成功" ;;
    1) echo "恢复失败" ;;
    2) echo "部分恢复成功" ;;
esac

相关命令

bzip2

压缩文件为.bz2格式:

bzip2 file.txt
bzip2 -9 file.txt
bzip2 -k file.txt
bunzip2

解压.bz2文件:

bunzip2 file.bz2
bunzip2 -t file.bz2
bunzip2 -c file.bz2
bzcat

查看.bz2文件内容:

bzcat file.bz2
bzcat file.bz2 | head -20
bzcat file.bz2 | wc -l
其他恢复工具

其他文件恢复工具:

# 通用文件恢复
photorec
testdisk

# ZIP文件恢复
zip -F damaged.zip --out repaired.zip

# RAR文件恢复
rar r damaged.rar