壊れたSDカードから写真を復旧してみた

急にSDカードが破損したので頑張って写真を復旧した。

高尾駅でトランスイート四季島を撮って「さぁ写真をtwitterに上げよう」とカメラから取り出したSDカードを携帯につないだところ「フォーマットの必要があります」のエラーメッセージ。カメラに戻してみても「カードがフォーマットされてません」とエラーが出て起動せず……

これはSDカードが壊れたと思い、その後の予定全部潰して実家に帰宅。幸いLinux入れたASUS T100TAを持ってきてたので直ちにデータ救出開始。

救出前のデータ吸い出し

まずはddコマンドでSDカードのデータを吸い出し。

sudo dd if=/dev/sdb of=image.dd.orig bs=512 conv=noerror,sync

数十分待って30GBのイメージファイルの出来上がり。一応コピーとって操作開始。

復元作業

まずはmount -t vfatしてみるもエラー

sudo mount -t vfat image.dd.orig /mnt/sd
mount: /mnt/sd: wrong fs type, bad option, bad superblock on /dev/loop13, missing codepage or helper program, or other error.

次にfsckしてみるも、やっぱりエラー

sudo fsck.vfat image.dd.orig
fsck.fat 4.2 (2021-01-31)
Logical sector size is zero.

正直、想定内。

次に、予め帰りの電車で調べてたtestdiskをインストールして、同梱のphotorecで復元

photorec image.dd.orig

取り出し元デバイス(イメージファイル)とか出力先とかファイルシステムとか設定して実行。 ……終わらない。よく見たらreading sectorがある程度進んだあと戻ってる。

同じところを少なくとも4週してることを確認して処理を停止。幸いここ最近撮った写真は復元できてたので残りは諦めた。

ファイル名再設定

photorecはセクタを見てファイルを拾ってくる仕様らしく、ファイル名は復元されない。 贅沢言ってられないので、まずはexif情報をもとに撮影日ごとに仕分け

from PIL import Image
import re
import os.path
import shutil
def get_dirname(file):
    image = Image.open(file)
    if image._getexif():
        dir = re.sub('(\d{4}):(\d{2}):(\d{2}).*', r'\1\2\3',image._getexif()[36868])
        return dir
def get_filename(dir):
    file_count = sum(os.path.isfile(os.path.join(dir, name)) for name in os.listdir(dir))
    return 'REC_{:05d}.JPG'.format(file_count + 1)
def copy(file):
    dir = get_dirname(file)
    if dir is None:
        print(f'{file} does not have exif')
        return
    if not os.path.exists(dir):
        os.mkdir(dir)
    filename = get_filename(dir)
    shutil.copy(file, os.path.join(dir, filename))
    print(os.path.join(dir, filename))
list = os.listdir('.')
for file in list:
    if '.jpg' in file.lower():
        print(file)
        copy(file)

これだと撮影時刻ガン無視の並び順になるので、一旦仕分けしてから撮影時刻でソート

from PIL import Image
import re
import os
import shutil
import datetime
list = os.listdir('.')
file_list = []
for file in list:
    if '.JPG' in file:
        image = Image.open(file)
        file_list.append({
            'name': file,
            'date': datetime.datetime.strptime(image._getexif()[36868], '%Y:%m:%d %H:%M:%S')
        })
sorted_list = sorted(file_list, key = lambda o: o['date'])
index = 1
for file in sorted_list:
    file_path = os.path.join('sort', 'REC_{:05d}.JPG'.format(index))
    print(file_path)
    shutil.copy(file['name'], file_path)
    index = index + 1

ものすごく雑なスクリプトだけど、これでソートも完了(1秒以内に撮られた写真は順番が入れ替わるけど、そこはもう暇なときに手で対処)。今日撮った写真は復元できたっぽい。

壊れたSDカードは……フォーマットすれば使えるんだろうけど、FlashAirだから下手にフォーマットすると無線LAN機能が使えなくなるんだよなぁ……もう無線LANは使ってないし、普通のSDカードと交換するか……

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です