database disk image is malformed 错误
sqlite是一个文本型数据库,其内部虽然做了异常处理,且官网上也说一般的异常不会引起数据库文件损坏,但是官方还是给出了有可能导致数据库文件损坏的情况。
以下内容来自官网:
SQLite 经过非常仔细的测试,以帮助确保它尽可能没有错误。对每个 SQLite 版本执行的众多测试包括模拟电源故障、I/O 错误和内存不足 (OOM) 错误的测试,并验证在任何这些事件期间不会发生数据库损坏。SQLite 还经过现场验证,约有 20 亿次活动部署,没有出现严重问题。
然而,没有一个软件是 100% 完美的。SQLite 中存在一些历史错误(现已修复),这些错误可能会导致数据库损坏。可能还有一些尚未被发现。由于 SQLite 的广泛测试和广泛使用,导致数据库损坏的错误往往非常隐蔽。应用程序遇到 SQLite bug 的可能性很小。为了说明这一点,下面列出了从 2009 年 4 月 1 日到 2013 年 4 月 15 日这四年期间在 SQLite 中发现的所有数据库损坏错误。这个帐户应该让读者直观地了解 SQLite 中的各种错误,这些错误设法通过测试过程并进入发布版本。
来源: How To Corrupt An SQLite Database File
修复方案一( 命令行手动修复)
-
以下是在linux环境下执行的,如果是windows需要把sqlite3修改为sqlite3.exe。
-
确保sqlite3在环境变量中,可以直接调用到,否则需要指明路径。
1.命令行打开sqlite3.exe并读取损坏的文件
sqlite3 CorruptDB
此时进入了sqlite命令行环境
2.导出sql语句到临时文件
sqlite>.output tmp.sql
sqlite>.dump
sqlite>.quit
3.修改tmp.sql文件
由于数据库文件损坏,所以sqlite自动将tmp.sql最后一行加上了一句Rollback
,因此我们需要手动修改tmp.sql
文件,将最后一行的Rollback
改为Commit;
。
这一步是最重要的!!!
4.读取tmp.sql并写入到新库中
sqlite3 NewDB
sqlite>.read tmp.sql
sqlite>.quit
大功告成!
修复方案二(python脚本自动修复)
- 一共有三个文件,一个python文件外加两个sql文件,原理是将方案一的所有操作集成为一个脚本执行。
三个文件内容如下
repair_tool.py
# -*- coding: utf-8 -*-
import os
class Repair(object):
def __init__(self):
# 前提是sqlite3已经添加到环境变量
self.__sqlite3_path = "sqlite3"
self.__path = os.path.dirname(os.path.abspath(__file__))
self.__dbDir = os.path.join(os.path.dirname(os.path.dirname(self.__path)), "data")
self.__tmpFilePath = os.path.join(self.__dbDir, "tmp.sql")
self.__dbPath = os.path.join(self.__dbDir, "data.db")
self.__newDbPath = os.path.join(self.__dbDir, "new_data.db")
self.__dumpSqlPath = os.path.join(self.__path, "dump.sql")
self.__readSqlPath = os.path.join(self.__path, "read.sql")
def doRepair(self):
# print("INFO: Starting repairing, please wait for a while.")
self.__dumpSql()
# print("INFO: DumpSql is successful.")
self.__modLastLine()
# print("INFO: Modify last line is successful.")
self.__readSql()
# print("INFO: ReadSql is successful.")
self.__delTmp()
# print("INFO: Delete TempFile is successful.")
self.__copyDB()
# print("INFO: Repairing is successful!")
def __dumpSql(self):
cmd = "cd " + self.__dbDir + "&&" + f'''{self.__sqlite3_path} {self.__dbPath}<{self.__dumpSqlPath}'''
os.system(cmd)
def __readSql(self):
with open(self.__newDbPath, "a"):
...
cmd = "cd " + self.__dbDir + "&&" + f'''{self.__sqlite3_path} {self.__newDbPath}<{self.__readSqlPath}'''
os.system(cmd)
def __delTmp(self):
os.remove(self.__tmpFilePath)
def __copyDB(self):
os.remove(self.__dbPath)
os.rename(self.__newDbPath, self.__dbPath)
def __modLastLine(self):
with open(self.__tmpFilePath, "rb+") as f:
file_size = os.path.getsize(self.__tmpFilePath)
offset = -8
while -1 * offset < file_size:
f.seek(offset, os.SEEK_END)
lines = f.readlines()
if len(lines) >= 2:
last_line_len = len(lines[-1])
f.seek(-last_line_len, os.SEEK_END)
f.truncate()
f.write(b"Commit;")
return
else:
offset *= 2
if __name__ == "__main__":
repair = Repair()
repair.doRepair()
dump.sql
.output tmp.sql
.dump
.quit
read.sql
.read tmp.sql
.quit
标签:.__,database,self,malformed,sql,sqlite3,path,os
From: https://www.cnblogs.com/liuyangQAQ/p/18037546