急に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カードと交換するか……