0

enter image description hereI have large database in sqlite file so I am trying to access it directly from my data.sqlite file but I am not able to access it . I had achieved that task in past using objective C

Steps Taken:

1:Drag data.sqlite file into project

2:Trying to access it via fmdb

Output: path=== /var/mobile/Containers/Data/Application/557B2961-52D8-4B14-BABC-BF4829852127/Documents/data.sqlite

let documentsDirectory = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString) as String 
pathToDatabase = documentsDirectory.appending("/(databaseFileName)")

func openDatabase() -> Bool {
 print("path=== \(pathToDatabase ?? "empty")")
      if database == nil {
           if FileManager.default.fileExists(atPath: pathToDatabase) {
                database = FMDatabase(path: pathToDatabase) 
//code is not entering in that if , it should be there becasuse I already included my sqlitefile    
 } 
        if database != nil {
            if database.open() {
                return true
            }
        }
        return false
    }
zkn
  • 79
  • 2
  • 11
  • Show how you set `pathToDatabase`. And have you confirmed that your `data.sqlite` is actually being copied to the app's bundle when the app is built? – rmaddy May 29 '19 at 18:14
  • let documentsDirectory = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString) as String pathToDatabase = documentsDirectory.appending("/\(databaseFileName)") – zkn May 29 '19 at 18:15
  • That needs to be in your question, not in a comment. – rmaddy May 29 '19 at 18:16
  • Please guide how can I confirm that data.sqlite file is actually being copied to apps bundle? – zkn May 29 '19 at 18:16
  • See https://stackoverflow.com/a/51054075/1226963 for how to check the Target Membership of a file. – rmaddy May 29 '19 at 18:20
  • @maddy Target membership of data.sqlite file looks fine. I included a pic please take a look – zkn May 29 '19 at 18:30
  • Looks good. But note that the file is in the app bundle, not the Documents folder. – rmaddy May 29 '19 at 18:58

3 Answers3

0

I have not used fmdb but I have used GRDB (https://github.com/groue/GRDB.swift) successfully in a recent project. Usually, those libraries will allow you to retrieve an error code or log output whenever there is an error and this may prove really useful in solving your issue.

In the meantime, here's a Swift function I'm using to convert a filename into a full Documents user path:

    private static func path(for filename: String) -> String {
        let fm = FileManager.default
        let documentsDirectory = fm.urls(for: .documentDirectory, in: .userDomainMask).first
        return documentsDirectory?.appendingPathComponent(filename).absoluteString ?? filename
    }

Note however, that files that are included as part of the build will typically not be in your Documents, it will be part of the bundle resources. In which case this piece of code may be more useful:

    let path = Bundle.main.path(forResource: "mydatabase", ofType: "sqlite")
ekscrypto
  • 3,718
  • 1
  • 24
  • 38
0

Try to copy the local database file to the app's documents library if it's not exist there.

import FMDB

class DBService {
    // MARK: Properties
    static let shared = DBService()
    var database: FMDatabase!

    private let fileManager = FileManager.default
    private var documentsDBPath: String
    private var resourcesDBPath: String

    private let databaseFileName = "data"
    private let databaseFileName = "sqlite"

    // MARK: Initializers
    private init() {
        documentsDBPath = try! fileManager
            .url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            .appendingPathComponent(databaseFileName)
            .appendingPathExtension(databaseFileExtension)
            .path

        resourcesDBPath = Bundle.main.path(forResource: databaseFileName,
                                           ofType: databaseFileExtension)!
    }

    // MARK: - Setup
    func isDatabaseOpen() -> Bool {
        if database == nil {
            initDatabase()
        }

        return database.open()
    }

    private func initDatabase() {
        if isFirstLaunch() {
            copyDatabase(from: resourcesDBPath, to: documentsDBPath)  
        }

        database = FMDatabase(path: documentsDBPath)
    }

    private func isFirstLaunch() -> Bool {
        return !fileManager.fileExists(atPath: documentsDBPath)
    }

    private func copyDatabase(from source: String, to destination: String) {
        do {
            try fileManager.copyItem(atPath: source, toPath: destination)
        } catch {
            debugPrint(error)
        }
    }
}
balazs630
  • 3,421
  • 29
  • 46
  • 2
    Copying may or may not be appropriate based on his use-case. A database with non-changing data would be wasting space, especially if large, if it is used in read-only mode. – ekscrypto May 29 '19 at 18:49
0

Your file is clearly not in documents directory, you should access it in main bundle

let dbUrl = Bundle.main.url(forResource: "data", withExtension: "sqlite")

If you need to copy the database in documents directory, use following instead

let fileManager = FileManager.default
let dbUrl = fileManager.urls(for: .documentDirectory, in: .userDomainMask).last!.appendingPathComponent("data.sqlite")
if !fileManager.fileExists(atPath: dbUrl.path) {
    let url = Bundle.main.url(forResource: "data", withExtension: "sqlite")!
    try? fileManager.copyItem(at: url, to: dbUrl)
}

Usage

let database = FMDatabase(url: dbUrl)
AamirR
  • 11,672
  • 4
  • 59
  • 73