Экспортировать данные SQLite в Excel в iOS программно

в моем приложении,я с помощью SQLite в качестве бэкенда(для хранения данных locially). Я могу вставлять данные в свою таблицу.но то,что я хочу сделать, это импортировать все мои данные 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);

}

1 ответов


для приложения, которое я сделал это, данные SQLite были довольно большими. Поэтому я использовал фоновый поток для экспорта всех данных в файл CSV (значение, разделенное запятыми), который Excel может импортировать, а затем открыл почтовый композитор с файлом 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 был доступен. Отрегулируйте по мере необходимости.