2014-11-03 73 views
0

我試圖將文本數據存儲爲壓縮的斑點。從Sqlite通過FMDB存儲和檢索壓縮文本爲BLOB

[db executeUpdate:@"create table blobTable (a text, b blob)"]; 
    [db executeUpdate:@"insert into blobTable (a, b) values (?, compressMe('random text string'))", @"lord of the rings"]; 

然後我嘗試使用,以對它們進行查詢:

FMResultSet *rs = [db executeQuery:@"select uncompressMe(b) as k from blobTable where a = ?", @"lord of the rings"]; 

凡compressMe和uncompressMe被定義爲:

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:dbPath]; 

[queue inDatabase:^(FMDatabase *adb) { 
    [adb makeFunctionNamed:@"compressMe" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) { 
     if (sqlite3_value_type(aargv[0]) == SQLITE_TEXT) { 

      @autoreleasepool { 

       const char *c = (const char *)sqlite3_value_text(aargv[0]); 

       NSString *s = [NSString stringWithUTF8String:c]; 

       NSLog(@"string to compress: %@", s); 

       NSData *compressedBody = [self gzipDeflate:[s dataUsingEncoding:NSUTF8StringEncoding]]; 

       sqlite3_result_blob(context, (__bridge const void *)(compressedBody), [compressedBody length], nil); 
      } 
     } 
     else { 
      NSLog(@"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__); 
      sqlite3_result_null(context); 
     } 
    }]; 
}]; 


[queue inDatabase:^(FMDatabase *adb) { 
    [adb makeFunctionNamed:@"uncompressMe" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) { 
     if (sqlite3_value_type(aargv[0]) == SQLITE_BLOB) { 

      @autoreleasepool { 

       NSLog(@"inside uncompressMe"); 

       NSUInteger len = sqlite3_value_bytes(aargv[0]); 
       Byte *byteData = (Byte*)malloc(len); 
       memcpy(byteData, sqlite3_value_blob(aargv[0]), len); 

       NSData *data = [[NSData alloc] initWithBytes:byteData length:len]; 

       NSData *deflatedBody = [self gzipInflate:data]; 
       NSString *deflatedString = [[NSString alloc] initWithData:deflatedBody encoding:NSUTF8StringEncoding]; 
       sqlite3_result_text(context, (__bridge const void *)(deflatedString), -1, SQLITE_UTF8); 
      } 
     } 
     else { 
      NSLog(@"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__); 
      sqlite3_result_null(context); 
     } 
    }]; 
}]; 

爲了完整起見,拉鍊功能被定義爲例如:

- (NSData *)gzipInflate:(NSData*)data 
{ 
    if ([data length] == 0) return data; 

    unsigned full_length = [data length]; 
    unsigned half_length = [data length]/2; 

    NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length]; 
    BOOL done = NO; 
    int status; 

    z_stream strm; 
    strm.next_in = (Bytef *)[data bytes]; 
    strm.avail_in = [data length]; 
    strm.total_out = 0; 
    strm.zalloc = Z_NULL; 
    strm.zfree = Z_NULL; 

    if (inflateInit2(&strm, (15+32)) != Z_OK) return nil; 
    while (!done) 
    { 
     // Make sure we have enough room and reset the lengths. 
     if (strm.total_out >= [decompressed length]) 
      [decompressed increaseLengthBy: half_length]; 
     strm.next_out = [decompressed mutableBytes] + strm.total_out; 
     strm.avail_out = [decompressed length] - strm.total_out; 

     // Inflate another chunk. 
     status = inflate (&strm, Z_SYNC_FLUSH); 
     if (status == Z_STREAM_END) done = YES; 
     else if (status != Z_OK) break; 
    } 
    if (inflateEnd (&strm) != Z_OK) return nil; 

    // Set real length. 
    if (done) 
    { 
     [decompressed setLength: strm.total_out]; 
     return [NSData dataWithData: decompressed]; 
    } 
    else return nil; 
} 

- (NSData *)gzipDeflate:(NSData*)data 
{ 
    if ([data length] == 0) return data; 

    z_stream strm; 

    strm.zalloc = Z_NULL; 
    strm.zfree = Z_NULL; 
    strm.opaque = Z_NULL; 
    strm.total_out = 0; 
    strm.next_in=(Bytef *)[data bytes]; 
    strm.avail_in = [data length]; 

    // Compresssion Levels: 
    // Z_NO_COMPRESSION 
    // Z_BEST_SPEED 
    // Z_BEST_COMPRESSION 
    // Z_DEFAULT_COMPRESSION 

    if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil; 

    NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion 

    do { 

     if (strm.total_out >= [compressed length]) 
      [compressed increaseLengthBy: 16384]; 

     strm.next_out = [compressed mutableBytes] + strm.total_out; 
     strm.avail_out = [compressed length] - strm.total_out; 

     deflate(&strm, Z_FINISH); 

    } while (strm.avail_out == 0); 

    deflateEnd(&strm); 

    [compressed setLength: strm.total_out]; 
    return [NSData dataWithData:compressed]; 
} 

但是,uncompressMe函數似乎不成功。它在Inflate方法中失敗,總是返回一個零。任何想法我可能做錯了什麼?我已經檢查過,以確保blob列確實填充。

回答

0

我覺得問題是由下面的代碼:

  NSUInteger len = sqlite3_value_bytes(aargv[0]); 
      Byte *byteData = (Byte*)malloc(len); 
      memcpy(byteData, sqlite3_value_blob(aargv[0]), len); 

      NSData *data = [[NSData alloc] initWithBytes:byteData length:len]; 

試試這個從數據庫,而不是創建字節變量並將其複製加載NSData

const void *bytes = sqlite3_column_blob(statement, 3); 
NSData *data = [[NSData alloc] initWithBytes:bytes length:size]; 
+0

那不是我正在尋找的。我使用自定義函數,我也嘗試了'NSData * data = [[NSData alloc] initWithBytes:sqlite3_value_blob(aargv [0])length:len];'但得到了同樣的錯誤 – 2014-11-04 00:42:40