簡體   English   中英

通過 Objective-C 創建 SQLite3 數據庫文件

[英]Creating an SQLite3 database file through Objective-C

我正在嘗試在運行時通過 Objective-C 創建一個 SQLite3 數據庫文件。 我正在嘗試創建一個名為“tblStore”的表。 我希望將字段名稱稱為“strStoreNumber”和“strStoreReg”。 我是 iOS 和 SQLite 的新手,所以我很難找到執行此操作的語法。 除了創建表之外,我還希望創建的表不駐留在應用程序包中,而是駐留在/存儲在手機上的某個地方。 該表需要可讀/可寫。 我已經閱讀了“用戶沙箱”和“文檔目錄”。 我不確定我是否理解兩者之間的區別。 理想情況下,我的應用程序將使用一個按鈕從文本字段中獲取輸入。 將來自文本字段的輸入放入字符串后,將進行檢查以查看我的“tblStore”SQLite 表是否存在,如果不存在,則將創建該表。

回顧一下: 1. Obj-C/SQLite 創建一個名為“tblStore”的表的語法是什么,其中包含“strStoreNumber”和“strStoreReg”字段? 2. db 文件應該放在哪里? 我需要讀取和寫入 tblStore db 文件。 3. “用戶沙箱”和“文檔目錄”有什么區別?

這是我目前所擁有的:

-(IBAction)setInput:(id)sender
{
    NSString *strStoreNumber;
    NSString *strRegNumber;
    NSString *tableName = @"tblStore";
    NSString *dbStrStore = @"strStore";
    NSString *dbStrReg = @"strReg";


    strStoreNumber = StoreNumber.text;
    strRegNumber = RegNumber.text;

    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* documentsDirectory = [paths lastObject];
    NSString* databasePath = [documentsDirectory stringByAppendingPathComponent:@"tblStore.sqlite"];
//  NSString* databasePath = [[NSBundle mainBundle] pathForResource:@"tblStore" ofType:@"sqlite"];

    if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) 
    {
        NSLog(@"Opened sqlite database at %@", databasePath);

        char *err; 
        NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS '%@' ('%@' TEXT PRIMARY KEY, '%@' TEXT);", tableName, dbStrStore, dbStrReg];
        if (sqlite3_exec(database, [sql UTF8String], NULL, NULL, &err) != SQLITE_OK) 
        { 
            sqlite3_close(database);
            NSAssert(0, @"Table failed to create.");
        }
        //...stuff
    } 
    else 
    {
        NSLog(@"Failed to open database at %@ with error %s", databasePath, sqlite3_errmsg(database));
        sqlite3_close (database);
    }

    NSString *querystring;

    // create your statement
    querystring = [NSString stringWithFormat:@"SELECT strStore, strReg FROM tblStore WHERE strStore = %@ AND strReg = %@;", strStoreNumber, strRegNumber];  

    const char *sql = [querystring UTF8String];

    NSString *szStore = nil;
    NSString *szReg = nil;

    sqlite3_stmt *statement = nil;
    if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL)!=SQLITE_OK) //queryString = Statement
    {
        NSLog(@"sql problem occured with: %s", sql);
        NSLog(@"%s", sqlite3_errmsg(database));
    }
    else
    {
        // you could handle multiple rows here
        while (sqlite3_step(statement) == SQLITE_ROW) 
        {            
            szStore = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)];
            szReg = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)];
        }        
    }

    sqlite3_finalize(statement);

    lblStoreNumber.text = szStore;
    lblRegNumber.text = szReg;   
} 

當我運行我的應用程序時,我收到以下錯誤:

2012-05-10 14:58:38.169 CCoDBTry[355:f803] Opened sqlite database at /Users/Matt****/Library/Application Support/iPhone Simulator/5.1/Applications/5DB7A218-A0F6-   485F-B366-91FD2F9BC062/Documents/tblStore.sqlite
2012-05-10 14:58:38.307 CCoDBTry[355:f803] sql problem occured with: SELECT strStore, strReg FROM tblStore WHERE strStore = 8053 AND strReg = 4;
2012-05-10 14:58:38.308 CCoDBTry[355:f803] no such column: strStore

我感謝任何花時間解釋其中一些內容的人,因為我很新,並且未能成功完成我嘗試過的一些事情。 非常感謝你的幫忙!

// 創建數據庫

-(NSString *) filePath
{
 NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *documentDirectory=[paths objectAtIndex:0];
 return [documentDirectory stringByAppendingPathComponent:@"LoginDatabase.sql"];
}

// 打開數據庫

-(void)openDB
{
 if(sqlite3_open([[self filePath]UTF8String], &db) !=SQLITE_OK)
 {
   sqlite3_close(db);
   NSAssert(0, @"Database failed to Open");
 }
}

// 創建表

-(void) createTableNamed:(NSString*)tableName withField1:(NSString*) field1 withField2:(NSString*) field2

{
   char *err;
   NSString *sql=[NSString stringWithFormat:@" CREATE TABLE IF NOT EXISTS '%@'('%@' TEXT PRIMARY KEY,'%@' TEXT);",tableName,field1,field2];

   if(sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) !=SQLITE_OK)
   {
    sqlite3_close(db);
    NSAssert(0, @"Table failed to create");
   }
}

// 插入記錄

-(void)insertrecordIntoTable:(NSString*) tableName withField1:(NSString*) field1 field1Value:(NSString*)field1Vaue andField2:(NSString*)field2 field2Value:(NSString*)field2Value
{

  NSString *sqlStr=[NSString stringWithFormat:@"INSERT INTO '%@'('%@','%@')VALUES(?,?)",tableName,field1,field2];
 const char *sql=[sqlStr UTF8String];

 sqlite3_stmt *statement1;

 if(sqlite3_prepare_v2(db, sql, -1, &statement1, nil)==SQLITE_OK)
 {
  sqlite3_bind_text(statement1, 1, [field1Vaue UTF8String], -1, nil);
  sqlite3_bind_text(statement1, 2, [field2Value UTF8String], -1, nil);
 }
 if(sqlite3_step(statement1) !=SQLITE_DONE)
    NSAssert(0, @"Error upadating table");
 sqlite3_finalize(statement1);
}

// 從表中獲取數據

-(void)getAllRowsFromTableNamed:(NSString *)tableName
{
  NSString *field1Str,*field2Str;

  NSString *qsql=[NSString stringWithFormat:@"SELECT * FROM %@",tableName];
  sqlite3_stmt *statement;
  if(sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, nil)==SQLITE_OK)
  {
   while(sqlite3_step(statement) ==SQLITE_ROW)
   {
     char *field1=(char *) sqlite3_column_text(statement, 0);
     char *field2=(char *) sqlite3_column_text(statement, 1);

     field1Str=[[NSString alloc]initWithUTF8String:field1];
     field2Str=[[NSString alloc] initWithUTF8String:field2];

     NSString *str=[NSString stringWithFormat:@"%@ - %@",field1Str,field2Str];
     NSLog(@"%@",str);
   }
}

}

在 viewDidLoad 中調用方法

- (void)viewDidLoad
{

  [self openDB];
  [self createTableNamed:@"Login" withField1:@"USERNAME" withField2:@"PASSWORD"];
  [self insertrecordIntoTable:@"Login" withField1:@"USERNAME" field1Value:username andField2:@"PASSWORD" field2Value:password];

}

其中用戶名和密碼是 NSString 值;

如果您不知道自己在做什么,sqlite 會很痛苦。 我在使用 sqlite c 函數時也遇到了一些問題,但后來我決定使用 sqlite 包裝器。

FMDBBWDB是用於目標 c 的良好且易於使用的 sqlite 包裝器。 我建議你使用其中之一。

請注意,BWDB 位於 lynda.com 教程( 教程)中,如果您在網上找不到它...請發表評論,我會將其上傳到某個地方。

編輯:你可以在你的應用程序中寫東西的唯一地方是你的文檔目錄......所以......簡單地說......如果數據庫不在你的文檔目錄中......是只讀的......也是......當你讀/寫你的數據庫..操作系統復制文檔目錄中的數據庫..並在那里完成所有的讀寫,所以你可以在你的應用程序包中有一個數據庫,但你不能編輯那個......所以你最終會得到 2 db。我自己也遇到了同樣的問題。我在更新應用程序時通過合並 2 db 來修復它

編輯 2:我上傳了 BWDB 最終項目(你在那里有你的包裝器和項目,看看它是如何工作的)

您可以使用以下代碼獲取在 Documents 文件夾中創建的數據庫。 只需在文檔文件夾中傳遞一個路徑,如果需要,該函數將在給定路徑的文檔文件夾中復制 sqlite 數據庫。 然后您可以使用此路徑來創建和查詢數據庫表。

+ (NSString*) createDatabaseIfRequiredAtPath:(NSString*)databasePath {

    if (databasePath == nil)
       return nil;


   NSString *path = [NSString stringWithFormat:@"%@/%@", databasePath, kMainDBName];
   NSFileManager *fileManager = [NSFileManager defaultManager];
   NSError *error = nil;

   if ([fileManager fileExistsAtPath:path] == NO) 
   {
    // The writable database does not exist, so copy the default to the appropriate location.
      NSString *defaultDBPath = [[NSBundle mainBundle] pathForResource:kMainDBName
                                                              ofType:nil];
      BOOL success = [fileManager copyItemAtPath:defaultDBPath 
                                       toPath:path
                                        error:&error];
      if (!success)
      {
        NSCAssert1(0, @"Failed to create writable database file with message '%@'.", [  error localizedDescription]);
        return nil;
    }
}

return path;

你可以打開終端和 cd 到 /Users/Matt* * /Library/Application Support/iPhone Simulator/5.1/Applications/5DB7A218-A0F6-485F-B366-91FD2F9BC062/Documents/

然后 sqlite3 tblStore.sqlite

然后使用 .schema tblStore 應該顯示您的表架構,您可以查看它是否正確構建。

您的數據庫需要位於文檔目錄中才能進行寫訪問。 如果您的數據庫只是要被讀取,則永遠不會寫入它可能在您的應用程序包中。 完成此操作的一種方法是創建 database.sqlite 文件並將其添加到包中,然后在啟動時將其復制到文檔目錄(如果該目錄尚不存在)。

與使用 CoreData 相比,您是否有特定的原因想要直接使用 SQLLite? CoreData 使用 SQLLite 數據庫,但它本身是一個更高級別的 API,特別是對於表視圖等,您可以獲得很多功能和模板方法,這些功能和模板方法已經在 Xcode 中設置好了。 定義數據模型是微不足道的,你會得到大量的樣板代碼,而且都是經過優化的。

http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started

CoreData 有時被描述為具有陡峭的學習曲線。 我不同意。 如果您正在考慮在您的應用程序中自己編寫 SQL,那么使用 CoreData 不會有任何問題。

術語“沙箱”是您的應用程序具有讀/寫訪問權限的設備文件系統部分的抽象術語。 “Documents”目錄是應用程序沙箱中的特定目錄。 您的沙箱中還有其他文件,而不僅僅是文檔目錄,但大多數將數據保存到 iOS 文件系統的應用程序都是在文檔目錄中進行的。

也許你忘記了表插入。 創建了數據庫和表,但它的表是空的。 您試圖從空的表中讀取記錄。

我試過上面的方法對我不起作用,主要是因為給出的例子通常會指向 DB 文件,但並沒有真正創建它。

在使用命令 shell 觀察 sqlite3 的工作方式后,這是我解決問題的方法:

  1. (出於測試目的),要使用 Linux shell 創建文件,請執行以下操作:

sqlite3 Heider.db

這創建了一個新的數據庫文件名 (Heider.db),還啟動了 DB 命令提示符以創建 SQL 查詢,...在執行任何查詢之前,只需輸入以下內容,無需執行任何操作即可:

。出口

在 Linux shell 中檢查創建的文件,執行以下操作:

ls -ltra

您應該看到創建了一個大小為 0 字節的“Heider.db”文件,這意味着 sqllite3 工具正在創建一個沒有內容的空白文件。

現在,要檢查這是否有效,請返回到 sqlite:

sqlite3 Heider.db

這一次,使用以下命令創建一個新表:

創建表測試(id int not null 主鍵);

插入一些東西:

插入 test(id) 值 (123);

請注意,查詢執行得很好,沒有任何錯誤。

現在,退出並檢查:

.exit ls -ltra

該文件中應該有一些數據,這證實了 Linux 中的工具至少可以工作......

現在,離開 Linux/Shell 回到 XCODE/Development(或您正在使用的任何工具)......這讓我們的生活變得如此簡單,因為我們需要做的就是使用代碼“以某種方式”手動創建一個文件,然后讓sqlite使用它。

因此,您需要執行以下操作:

// 檢查文件名是否已經存在:

DBFileName = @"MyNewFile.db";  

if (![[NSFileManager defaultManager] fileExistsAtPath: DBFileName])
{

    NSLog([NSString stringWithFormat:@"Database does not exists, creating: %@", DBFileName]);
    [[NSFileManager defaultManager] createFileAtPath:DBFileName contents:NULL attributes:NULL];  
}

// Use SQLite to access the new file to do whatever you want:

int DBOpen = sqlite3_open([_DBFileName UTF8String], &_SqlLite);

if (DBOpen == SQLITE_OK) 
{

    NSLog([NSString stringWithFormat: @"Client: SQLite DB Opended Successfully, creating test table..."]); 

// Heider: Notice I am using "self" here because I am having this as a
wrapper class (see at the bottom of this post the whole function), you don't have to do the same, as you can use your own
SQLITE3 object directly instead...

 [self ExecQuery:@"create table Test(id int not null primary key);"];
 [self ExecQuery:@"insert into Test(id) values (123);"];

}

我在上面使用的 SELF ExecQuery 也在下面,以防您需要它:

-(BOOL)ExecQuery:(NSString *)Query { BOOL 成功 = NO;

 if (sqlite3_prepare_v2(_SqlDB, [Query UTF8String], -1, &_SqlQuery, NULL) == SQLITE_OK) { if (sqlite3_step(_SqlQuery) == SQLITE_DONE) { NSLog([NSString stringWithFormat: @"Client: SQL Query Successful: %@", Query]); } else { NSLog([NSString stringWithFormat: @"Client-Error Executing SQL Query: %@", Query]); } } else { Log(3, [NSString stringWithFormat: @"Client-Error Preparing SQL Query: %@", Query]); } sqlite3_finalize(_SqlQuery); return Successful;

}

這個過程是創建一個你喜歡的空白文件,然后將 sqlite3 指向它,然后以舊的方式執行你的 SQL......應該很簡單。

祝你好運,我希望這會有所幫助。

H

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM