【问题标题】:Move database file from bundle to documents folder - FMDB将数据库文件从捆绑包移动到文档文件夹 - FMDB
【发布时间】:2019-06-04 04:26:13
【问题描述】:

我正在使用FMdatabase。 我想使用准备好的数据库。

我想我应该将数据库文件从捆绑包移动到文档文件夹。

我的代码:

import FMDB
class DatabaseManager {

    private let dbFileName = "kashanmapDB_upgrade_3-4.db"
    private var database:FMDatabase!

    let TABLE_LOCATION_FA           = "LocationInfoFa";
    let TABLE_LOCATION_EN           = "LocationInfoEn";
    let TABLE_GREAT_PEOPLE_FA       = "GreatPeopleInfoFa";
    let TABLE_GREAT_PEOPLE_EN       = "GreatPeopleInfoEn";
    let TABLE_TAGS                  = "Tags";
    let TABLE_RELATION_TAG_LOCATION = "RelationTagLocation";
    let TABLE_NECESSARY_INFORMATION = "NecessaryInformation";
    let TABLE_SLIDER_FA             = "SliderFa";
    let TABLE_SLIDER_EN             = "SliderEn";
    let DATABASE_VERSION            = 4;
    static var LANGUAGE                    = 1 ; //1:Fa , 2:En
    var utilities                   = Utilities()

    init() {
        openDatabase()

        if(utilities.getData(key: "lang") == "2")
        {
            DatabaseManager.LANGUAGE = 2
        }

    }

    func copyDatabaseIfNeeded() {
        // Move database file from bundle to documents folder

        let fileManager = FileManager.default

        let documentsUrl = fileManager.urls(for: .documentDirectory,
                                            in: .userDomainMask)

        guard documentsUrl.count != 0 else {
            return // Could not find documents URL
        }

        //let finalDatabaseURL = documentsUrl.first!.appendingPathComponent("kashanmapDB_upgrade_3-4.db")
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
        let finalDatabaseURL = URL(fileURLWithPath: paths).appendingPathComponent(dbFileName)

        if !( (try? finalDatabaseURL.checkResourceIsReachable()) ?? false) {
            print("DB does not exist in documents folder")

            let documentsURL = Bundle.main.resourceURL?.appendingPathComponent("kashanmapDB_upgrade_3-4.db")

            do {
                try fileManager.copyItem(atPath: (documentsURL?.path)!, toPath: finalDatabaseURL.path)
            } catch let error as NSError {
                print("Couldn't copy file to final location! Error:\(error.description)")
            }

        } else {
            print("Database file found at path: \(finalDatabaseURL.path)")
        }

    }

    func openDatabase() {

        self.copyDatabaseIfNeeded()

        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
        let dbPath = URL(fileURLWithPath: paths).appendingPathComponent(dbFileName)

        let str_path = Bundle.main.resourceURL!.appendingPathComponent(dbFileName).path
        let database = FMDatabase(path: str_path)

        /* Open database read-only. */
        if (!(database.open(withFlags: 2))) {
            print("Could not open database at \(dbPath).")
        } else {
            print("opened database")
            self.database = database;
        }
    }

第一次(安装应用程序时)我收到此错误消息:

DB does not exist in documents folder

我总是收到这条消息:

Error Domain=FMDatabase Code=8 "attempt to write a readonly database" UserInfo={NSLocalizedDescription=attempt to write a readonly database}

【问题讨论】:

  • 您在哪一行代码中收到该错误消息?

标签: ios swift xcode


【解决方案1】:

嗯...查看您的代码:

func openDatabase() {

    self.copyDatabaseIfNeeded()

    let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
    let dbPath = URL(fileURLWithPath: paths).appendingPathComponent(dbFileName)

    let str_path = Bundle.main.resourceURL!.appendingPathComponent(dbFileName).path
    let database = FMDatabase(path: str_path)

    /* Open database read-only. */
    if (!(database.open(withFlags: 2))) {
        print("Could not open database at \(dbPath).")
    } else {
        print("opened database")
        self.database = database;
    }
}

您似乎将dbPath 设置为等于文档文件夹中文件的路径,但随后您尝试打开位于str_pathdatabase,它等于Bundle 路径。

也许只是改变:

let database = FMDatabase(path: str_path)

到:

let database = FMDatabase(path: dbPath)

【讨论】:

    【解决方案2】:

    复制数据库后,您正尝试从捆绑包中打开数据库。在 Documents 文件夹中打开一个。如果您在处理丢失数据库的 if 语句中定义捆绑 URL(如下所示),则不会意外抓取错误的数据库。

    顺便说一句,Apple 对存储在 Documents 文件夹中的内容越来越严格(请参阅 iOS Storage Best Practices)。您可能想改用 Application Support 文件夹。

    let fileURL = try FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("test.sqlite")
    
    let fileExists = (try? fileURL.checkResourceIsReachable()) ?? false
    if !fileExists {
        let bundleURL = Bundle.main.url(forResource: "test", withExtension: "sqlite")!
        try FileManager.default.copyItem(at: bundleURL, to: fileURL)
    }
    
    let db = FMDatabase(url: fileURL)
    guard db.open() else {
        print("unable to open")
        return
    }
    

    或者,通常更倾向于采用“请求宽恕而不是许可”的策略。即,与其在每次打开数据库之前检查是否存在,不如尝试打开它并处理找不到文件的错误场景(这只会发生一次,在您第一次尝试打开它时)。最重要的是,只需尝试打开数据库,如果失败,请从捆绑包中复制并重试。

    诀窍是提供SQLITE_OPEN_READWRITE 参数(如果您使用import SQLite3,则可以使用)而不是SQLITE_OPEN_CREATE,这样如果您第一次尝试打开它时没有找到它,它就不会创建一个空白数据库:

    let fileURL = try FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("test.sqlite")
    
    let db = FMDatabase(url: fileURL)
    
    if !db.open(withFlags: SQLITE_OPEN_READWRITE) {
        let bundleURL = Bundle.main.url(forResource: "test", withExtension: "sqlite")!
        try FileManager.default.copyItem(at: bundleURL, to: fileURL)
        guard db.open(withFlags: SQLITE_OPEN_READWRITE) else {
            print("unable to open")
            return
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-02
      相关资源
      最近更新 更多