9

私のアプリケーションでは、sqlite をバックエンドとして使用しています (データをローカルに保存するため)。私は自分のテーブルにデータを挿入することができます.しかし、私がやりたいことは、すべてのsqliteデータをプログラムでExcelにインポートしたいということです.そして、私はこのアプリケーションにサーバーを使用したくありません.Excelシートが生成されたら、ユーザーはすべきですそのシートを郵送できること。これは iPhone で可能ですか: 助けてください。

以下は、テーブルにデータを挿入するための私のコードです:

-(IBAction)Login
{
sqlite3_stmt *stmt;
        char *errorMsg; 
        char *update1 = "insert into Login1 values (?,?,?,?);";
        int x = sqlite3_prepare_v2(database, update1, -1, &stmt, nil);

    if (x == SQLITE_OK) 
    { 
        sqlite3_bind_text(stmt, 1, NULL,-1, NULL);
        sqlite3_bind_text(stmt, 2, [USERID UTF8String],-1, NULL);
        sqlite3_bind_text(stmt, 3, [str1 UTF8String],-1, NULL);
        sqlite3_bind_text(stmt, 4, [str4 UTF8String],-1, NULL);


    } 

    if (sqlite3_step(stmt) != SQLITE_DONE)
        NSLog(@"Error: %@",errorMsg); 
    sqlite3_finalize(stmt);

}

4

1 に答える 1

12

これを行ったアプリの場合、SQLite データはかなり大きかった。そのため、バックグラウンド スレッドを使用して、すべてのデータを Excel でインポートできる CSV (カンマ区切り値) ファイルにエクスポートし、CSV ファイルを添付してメール コンポーザを開きました。データが小さい場合は、バックグラウンド スレッドを使用する必要がない場合があります。

- (IBAction) export: (id) sender
{    
    // in my full code, I start a UIActivityIndicator spinning and show a 
    //  message that the app is "Exporting ..."

    [self performSelectorInBackground: @selector(exportImpl) withObject: nil];
}

ここはexportImpl

- (void) exportImpl
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    NSArray* documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSSystemDomainMask, YES);
    NSString* documentsDir = [documentPaths objectAtIndex:0];
    NSString* csvPath = [documentsDir stringByAppendingPathComponent: @"export.csv"];

    // TODO: mutex lock?
    [sqliteDb exportCsv: csvPath];

    [pool release];

    // mail is graphical and must be run on UI thread
    [self performSelectorOnMainThread: @selector(mail:) withObject: csvPath waitUntilDone: NO];
}

- (void) mail: (NSString*) filePath
{
    // here I stop animating the UIActivityIndicator

    // http://howtomakeiphoneapps.com/home/2009/7/14/how-to-make-your-iphone-app-send-email-with-attachments.html
    BOOL success = NO;
    if ([MFMailComposeViewController canSendMail]) {
        // TODO: autorelease pool needed ?
        NSData* database = [NSData dataWithContentsOfFile: filePath];

        if (database != nil) {
            MFMailComposeViewController* picker = [[MFMailComposeViewController alloc] init];
            picker.mailComposeDelegate = self;
            [picker setSubject:[NSString stringWithFormat: @"%@ %@", [[UIDevice currentDevice] model], [filePath lastPathComponent]]];

            NSString* filename = [filePath lastPathComponent];
            [picker addAttachmentData: database mimeType:@"application/octet-stream" fileName: filename];
            NSString* emailBody = @"Attached is the SQLite data from my iOS device.";
            [picker setMessageBody:emailBody isHTML:YES];

            [self presentModalViewController:picker animated:YES];
            success = YES;
            [picker release];
        }
    }

    if (!success) {
        UIAlertView* warning = [[UIAlertView alloc] initWithTitle: @"Error"
                                                          message: @"Unable to send attachment!"
                                                         delegate: self
                                                cancelButtonTitle: @"Ok"
                                                otherButtonTitles: nil];
        [warning show];
        [warning release];
    }
}

そして、すべての SQLite データをカプセル化するクラスがあります。このクラスは、sqlite 呼び出しを行う唯一のクラスです。このクラスには、アプリのキャッシュディレクトリにある CSV ファイルにデータをエクスポートするメソッドがあります。sqliteDb上記のコードの変数は、このクラスのインスタンスです。データをエクスポートする方法は次のとおりです。

-(void) exportCsv: (NSString*) filename
{
    // We record this filename, because the app deletes it on exit
    self.tempFile = filename;

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    // Setup the database object
    sqlite3* database;

    // Open the database from the users filessytem
    if (sqlite3_open([self.databasePath UTF8String], &database) == SQLITE_OK)
    {
        [self createTempFile: filename];
        NSOutputStream* output = [[NSOutputStream alloc] initToFileAtPath: filename append: YES];
        [output open];
        if (![output hasSpaceAvailable]) {
            NSLog(@"No space available in %@", filename);
            // TODO: UIAlertView?
        } else {
            NSString* header = @"Source,Time,Latitude,Longitude,Accuracy\n";
            NSInteger result = [output write: [header UTF8String] maxLength: [header length]];
            if (result <= 0) {
                NSLog(@"exportCsv encountered error=%d from header write", result);
            }

            BOOL errorLogged = NO;
            NSString* sqlStatement = @"select timestamp,latitude,longitude,horizontalAccuracy from my_sqlite_table";

            // Setup the SQL Statement and compile it for faster access
            sqlite3_stmt* compiledStatement;
            if (sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK)
            {
                 // Loop through the results and write them to the CSV file
                 while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
                     // Read the data from the result row
                     NSInteger secondsSinceReferenceDate = (NSInteger)sqlite3_column_double(compiledStatement, 0);
                     float lat = (float)sqlite3_column_double(compiledStatement, 1);
                     float lon = (float)sqlite3_column_double(compiledStatement, 2);
                     float accuracy = (float)sqlite3_column_double(compiledStatement, 3);

                     if (lat != 0 && lon != 0) {
                         NSDate* timestamp = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: secondsSinceReferenceDate];
                         NSString* line = [[NSString alloc] initWithFormat: @"%@,%@,%f,%f,%d\n",
                                       table, [dateFormatter stringFromDate: timestamp], lat, lon, (NSInteger)accuracy];
                         result = [output write: [line UTF8String] maxLength: [line length]];
                         if (!errorLogged && (result <= 0)) {
                             NSLog(@"exportCsv write returned %d", result);
                             errorLogged = YES;
                         }
                         [line release];
                         [timestamp release];
                     }
                     // Release the compiled statement from memory
                     sqlite3_finalize(compiledStatement);
                 }
            }
        }
        [output close];
        [output release];
    }

    sqlite3_close(database);
    [pool release];
}

-(void) createTempFile: (NSString*) filename {
    NSFileManager* fileSystem = [NSFileManager defaultManager];
    [fileSystem removeItemAtPath: filename error: nil];

    NSMutableDictionary* attributes = [[NSMutableDictionary alloc] init];
    NSNumber* permission = [NSNumber numberWithLong: 0640];
    [attributes setObject: permission forKey: NSFilePosixPermissions];
    if (![fileSystem createFileAtPath: filename contents: nil attributes: attributes]) {
        NSLog(@"Unable to create temp file for exporting CSV.");
        // TODO: UIAlertView?
    }
    [attributes release];
}

私のコードは、位置情報のデータベースをエクスポートしています。明らかに、内部exportCsvでは、私の sqlite 呼び出しをデータベース コンテンツに適したものに置き換える必要があります。

また、コードはデータを一時ファイルに保存します。これらの一時ファイルをいつ消去するかを決定することをお勧めします。

明らかに、このコードは ARC が利用可能になる前に作成されました。必要に応じて調整します。

于 2012-06-21T20:47:36.673 に答える