2012-06-21 17 views
8

Nella mia applicazione, sto usando sqlite come back-end (per memorizzare i dati localmente). Sono in grado di inserire dati nel mio table.but quello che voglio fare è, voglio importare tutti i miei dati sqlite in Excel a livello di codice.E non voglio usare il server per questa app.se il foglio excel è generare utente dovrebbe essere in grado di spedire quel foglio. È possibile in iPhone: Please help me out.Esporta dati SQLite in Excel in iOS a livello di programmazione

seguito è il mio codice per inserire i dati nella tabella:

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

}

risposta

11

Per l'applicazione che ho che ha fatto questo, i dati SQLite era abbastanza grande. Pertanto, ho utilizzato un thread in background per esportare tutti i dati in un file CSV (valori separati da virgola), che Excel può importare e quindi aprire un compositore di posta con il file CSV come allegato. Se i dati sono piccolo, non potrebbe essere necessario utilizzare un thread in background:

- (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]; 
} 

Ecco 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]; 
    } 
} 

E poi, io ho una classe che incapsula tutti i miei dati SQLite. Questa classe è l'unica che effettua chiamate sqlite. In questa classe, ho un metodo per esportare i dati in un file CSV nella directory della cache della mia app. La variabile sqliteDb nel codice sopra è un'istanza di questa classe. Ecco il metodo per esportare i dati:

-(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]; 
} 

Il mio codice sta esportando un database di informazioni sulla posizione. Ovviamente, all'interno di exportCsv, sarà necessario sostituire le mie chiamate sqlite con quelle appropriate per il contenuto del database.

Inoltre, il codice memorizza i dati in un file temporaneo. Probabilmente vorrai decidere quando pulire i file temporanei.

Ovviamente, questo codice è stato scritto prima che ARC fosse disponibile. Regolare secondo necessità.

Problemi correlati