2012-06-21 4 views
8

В моем приложении я использую sqlite в качестве бэкэнд (для хранения данных локально). Я могу вставить данные в свою таблицу. Но я хочу, чтобы все мои данные sqlite импортировались в excel программно. И я не хочу использовать сервер для этого приложения. должен иметь возможность отправить этот лист. Возможно ли это в iPhone: Пожалуйста, помогите мне.Экспорт данных SQLite в Excel в iOS программно

Ниже мой код для вставки данных в таблицу:

-(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); 

}

ответ

11

Для приложения у меня есть, что сделал это, 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. При необходимости отрегулируйте.