今すぐ修復
- ファイルをドロップ
- 修復はローカルで実行
- 結果をダウンロード
History ファイルは標準的な SQLite データベースです(16 バイトのマジックナンバー SQLite format 3\0)。そのため、ツールがこのファイルに対して database disk image is malformed と報告したり、クラッシュ後に Chrome が履歴を失ったりする場合、それはどの SQLite ファイルにも起こりうるのと同じ種類の障害です。つまり、1 つのページやポインタが壊れただけであって、データが丸ごと失われたわけではありません。上に History ファイルをドロップすると、スキャナーがブラウザ内でそれを開き、ページを直接たどり、スキーマを再構築し、まだデコードできるすべての行を、開くことのできる新しいデータベースへ再挿入します — ファイルがあなたのマシンから外に出ることは決してありません。
Chrome の History は拡張子のない SQLite データベース
あなたの履歴は独自形式で保存されているわけではありません — それは Chrome のプロフィールディレクトリに置かれた SQLite データベースです。Windows では %LOCALAPPDATA%\Google\Chrome\User Data\Default\History、macOS では ~/Library/Application Support/Google/Chrome/Default/History、Linux では ~/.config/google-chrome/Default/History にあります(Chromium は ~/.config/chromium/…、Edge は …/Microsoft/Edge/…、Brave は …/BraveSoftware/Brave-Browser/… を使います)。ファイル名は拡張子なしの History です。だからこそ、これを任意の SQLite ツールで開けることに多くの人は気づきません — コピーの名前を History.db に変更すれば、DB Browser for SQLite がそのまま読み込みます。
その中には、あなたの閲覧記録を構成するテーブルが入っています。urls は訪問したページごとに 1 行を保持します — その列は id、url、title、visit_count、typed_count、last_visit_time、hidden です。visits はタイムラインです。各行には urls.id へ戻る外部キー url、visit_time、直前の訪問を指す from_visit(これにより「戻る/進む」の連鎖が再構築されます)、そして下位バイトが中心的な種類を表すビットマスク transition(LINK = 0、TYPED = 1、AUTO_BOOKMARK = 2、RELOAD = 8)があります。それらの隣には、keyword_search_terms、downloads と downloads_url_chains、segments/segment_usage(新しいタブのショートカットを支えます)、そして version と last_compatible_version の行を持つ小さな meta テーブル(どのスキーマを見ているかを Chrome に伝えます)があります。
履歴をエクスポートする人が必ずつまずく細部が 1 つあります。タイムスタンプは Unix 時間ではありません。last_visit_time と visit_time は 1601-01-01 00:00:00 UTC からのマイクロ秒(Chrome/WebKit のエポック)として保存されています。これを通常の日付として読むには、1,000,000 で割り、11,644,473,600 秒を引きます。復元はこの生の整数をディスク上にある値のまま正確に保持するので、日付は再構築後も失われません — あとから自分で変換するだけです。
History ファイルはどのように malformed になるのか: ページとポインタ
SQLite データベースは、固定サイズのページが並んだ平坦な配列です — Chrome は既定の 4096 バイトを使います。ページ 1 にはヘッダーとスキーマが入ります。urls や visits を含むすべてのテーブルはB ツリーで、その内部ページは、実際の行を保持するリーフページへと下向きに指しています。Chrome は History データベースを WAL(write-ahead logging、先行書き込みログ)モードで動かすため、その隣には通常 History-wal と History-shm という名前の兄弟ファイルが見えます。古いビルドや一部のプロフィールでは、代わりに History-journal というロールバックジャーナルが残ります。
この兄弟ファイルの仕組みこそ、まさに破損が忍び込む場所です。マシンの電源が落ちたり、ディスクがいっぱいになったり、チェックポイントの途中で Chrome が強制終了されたりすると、WAL のフレームがメインファイルへ途中までしか書き戻されないことがあります — たった 1 つの内部ページに、矛盾したセルポインタや、ファイルサイズと食い違うページ数が入り込みます。SQLite はそのポインタをたどり、有効な B ツリーページではない何かに行き当たって停止します。Error: database disk image is malformed (11) — 結果コード SQLITE_CORRUPT です。PRAGMA integrity_check を実行すると具体的な内容が見えます。たとえば *** in database main ***、Page 214: btreeInitPage() returns error code 11、row 1803 missing from index urls_url_index、あるいは wrong # of entries in index visits_url_index といった行です。
肝心なのはここです。エンジンは最初の不整合で停止しますが、そこに到達しなかったページはたいてい完璧で、行は手つかずのままリーフページに収まっています。これは、動画で moov インデックスが欠けているときや、ZIP の中央ディレクトリが壊れているときと同じ話です — 壊れたのは地図であって、データではありません。だからこそ、ファイルを普通に開いても何も取り戻せない場面で、ページ単位の再構築はこれほど多くを復元できるのです。
復元で取り戻せるもの
malformed になった History ファイルはその場で直すのではありません — まだデコードできるものをすべて読み出し、まっさらな新しいデータベースへ書き込みます。これは SQLite 自身の .recover コマンドの動きとまったく同じです。スキャナーはすべてのページをローカルで読み、残っている定義からスキーマを再構築し、各テーブルの B ツリーをたどってそのリーフページにある自己記述型のレコードをデコードします。ポインタの連鎖ではもう到達できなくなった行は、ページの生スキャン(raw page sweep)で見つけ出します。そしてデコードはできるものの既知のどのテーブルにも一致しないものは、捨てずに lost_and_found テーブルへ書き込みます。
実際にはこれで履歴の中身が取り戻せます。urls テーブル(アドレス、ページタイトル、visit_count、last_visit_time)、transition の種類と from_visit の連鎖を伴う visits タイムライン、そして — ページが無事であれば — keyword_search_terms、downloads、segments のデータです。History-wal の兄弟ファイルがまだ手元にあれば、メインファイルをドロップしたあとオプションのスロットに追加してください。そのコミット済みフレームがスキャン前に重ね合わされるので、再構築は最後のチェックポイントではなく最後にコミットされたトランザクションを反映します — 多くの場合、直近の数時間分の閲覧です。出力は、開くことのできる新しい SQLite ファイルで、ダウンロードできます。名前を History に戻し、Chrome を閉じた状態でプロフィールフォルダーに置けば履歴が復活します。あるいは任意の SQLite ビューアーでそのまま照会するだけでもかまいません。
本当に限界となるところ
復元は物理的に存在するものを返します。上書きされたものを作り出すことはできません。ファイルの末尾で切り詰められた行や、削除後にページが再利用された行は失われています — どんなツールもそれらを取り戻せません。Chrome 特有の最大の損失は時間です。Chrome は malformed とみなした History ファイルを開くと、しばしばその場でそれを削除して空の新しいファイルを作るため、破損した元のファイルがその場で上書きされます。もしすでにそれが起きているなら、すぐに Chrome を閉じ、バックアップか古い History/History-wal のコピーから復元してください — それを置き換えた空のファイルには、見つけ出すものが何も入っていません。
より小さな注意点を 2 つ、はっきり述べておきます。復元された値はディスク上の格納クラス(storage class)のまま返るため、列に宣言されたアフィニティが再適用されないことがあります — タイムスタンプは依然として正しいマイクロ秒の整数なので、自分で変換するだけです。そして、破損したデータベースから復元したデータは常に疑わしいものです。SQLite 自身のドキュメントがそう述べており、生スキャンはフリーリストのページも読むため、以前に削除した URL がときおり再浮上することがあります。復元レポートは、何が出てきたか、そして何が生スキャンで引き出されたかをテーブルごとに示します。以上のどれにもサーバーは不要です。History ファイル — あなたが訪れたすべての場所の地図です — はあなたのディスクから読み込まれ、あなたのタブ内で再構築されます。Network タブを見れば、0 バイトしか外に出ていないことを確認できます。
修復できるものとできないもの
修復できる
- 損傷したページや B ツリーのポインタが原因で Chrome/Chromium の History ファイルに出る「database disk image is malformed (11)」
- 残存するリーフページから取り出す urls テーブル — アドレス、ページタイトル、visit_count、typed_count、last_visit_time
- visits タイムライン: visit_time、transition の種類、from_visit による戻る/進むの連鎖
- ページが無事な場合の keyword_search_terms、downloads、segments のデータ
- 提供された History-wal 兄弟ファイルからの、チェックポイント未処理の閲覧(スキャン前に重ね合わせ)
- 破損したヘッダーフィールド(誤ったページサイズやページ数)で、その背後のページは無事なもの
修復できない
- Chrome がすでに削除して空の新しいファイルに置き換えた履歴 — 古い行はその場で上書きされています
- ファイルの末尾で物理的に切り詰められた行や、削除後に再利用されたページ上の行 — それらのバイトはもう存在しません
- 正確さの保証 — 復元データは常に疑わしく、削除された URL がフリーリストのページから再浮上することがあるので、検証してください
- 列の正確なアフィニティ: 値はディスク上の格納クラスのまま返ります(タイムスタンプは正しいままなので、自分で再変換するだけです)
- 0 バイトの History ファイル — それは SQLite の再構築より前に、まずストレージデバイスのデータ復旧の問題です
修復が失敗した場合、その理由(データの欠落か構造の破損か)をお伝えします。失敗した修復に料金が請求されることはありません。