2010-02-04 11 views
35

Cómo convertir NSData en . Tengo NSData y quiero convertirme en base64 ¿cómo puedo hacer esto?Conversión de NSData a base64

+0

Hola Mr-sk, ¿podría decirme cómo aceptar la respuesta? – mactalent

+0

Esto está muy cerca de esta pregunta: http://stackoverflow.com/questions/392464/any-base64-library-on-iphone-sdk –

+0

Entonces, ¿por qué tenemos que convertir NSData a la base 64 en general? – zumzum

Respuesta

46

EDITAR

A partir de OS X 10.9/iOS 7, esto está incorporado en los marcos.

Ver -[NSData base64EncodedDataWithOptions:]


Antes de iOS7/OS X 10.9:

Matt Gallagher escribió an article sobre este mismo tema. En la parte inferior, da un enlace a su código incrustado para iPhone.

En Mac puede usar la biblioteca OpenSSL, en el iPhone escribe su propia impl.

+2

Parece que hay un pequeño problema en el código Matts: en 'void * NewBase64Decode' línea 128,' j + = accumulateIndex - 1; 'debe estar rodeado por' if (accumulatedIndex> 0) {...} '. De lo contrario, si la secuencia codificada contiene caracteres no válidos (por ejemplo, '\ r \ n') al final, el último carácter del texto decodificado puede perderse. Esto causó problemas extraños en mi código al hacer una decodificación basada en línea de respuestas IMAP ... – DEAD10CC

+0

@Joker Esto me pasó a mí. ¡Gracias por la solución fácil, genio! – AndersTornkvist

+0

Resulta que ha habido una función para hacer esto desde iOS4, pero nunca se lanzó públicamente hasta iOS 7. Si imageData es una instancia de NSData, simplemente ... [imageData base64Encoding]; https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/NSData_Class/DeprecationAppendix/AppendixADeprecatedAPI.html –

4

No es fácil. Como en el caso de c u obj-c, no hay soporte integrado para esto. Esto es lo que hace Im (que básicamente está teniendo el CL lo haga por mí):

- (NSString *)_base64Encoding:(NSString *) str 
{ 
    NSTask *task = [[[NSTask alloc] init] autorelease]; 
    NSPipe *inPipe = [NSPipe pipe], *outPipe = [NSPipe pipe]; 
    NSFileHandle *inHandle = [inPipe fileHandleForWriting], *outHandle = [outPipe fileHandleForReading]; 
    NSData *outData = nil; 

    [task setLaunchPath:@"/usr/bin/openssl"]; 
    [task setArguments:[NSArray arrayWithObjects:@"base64", @"-e", nil]]; 
    [task setStandardInput:inPipe]; 
    [task setStandardOutput:outPipe]; 
    [task setStandardError:outPipe]; 

    [task launch]; 

    [inHandle writeData:[str dataUsingEncoding: NSASCIIStringEncoding]]; 
    [inHandle closeFile]; 

    [task waitUntilExit]; 

    outData = [outHandle readDataToEndOfFile]; 
    if (outData) 
    { 
     NSString *base64 = [[[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding] autorelease]; 
     if (base64) 
      return base64; 
    } 

    return nil; 
} 

y se utiliza de esta manera:

NSString *b64str = [strToConvert _base64Encoding:strToConvert]; 

Y esto no es mi código - lo encontré aquí : http://www.cocoadev.com/index.pl?BaseSixtyFour y funciona genial. Siempre puedes convertir esto en un método +().

Ah, y para obtener su NSData a un NSString para este método:

NSString *str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; 
+1

En mac no es necesario generar un proceso; puede usar libcrypto directamente. En el iPhone, ¿está presente/usr/bin/openssl? – Ken

+0

nice answer ... +1 –

6

Super fácil drop-in Google código de la biblioteca here.

Sólo tiene que utilizar +rfc4648Base64StringEncoding para obtener una instancia, a continuación, utilizar las funciones encode/decode.

Es una cosa hermosa. (No se olvide de agarrar el archivo de cabecera y la cabecera GTMDefines.h de la raíz, sin embargo.)

27
//from: http://cocoadev.com/BaseSixtyFour 
+ (NSString*)base64forData:(NSData*)theData { 

    const uint8_t* input = (const uint8_t*)[theData bytes]; 
    NSInteger length = [theData length]; 

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/="; 

    NSMutableData* data = [NSMutableData dataWithLength:((length + 2)/3) * 4]; 
    uint8_t* output = (uint8_t*)data.mutableBytes; 

    NSInteger i; 
    for (i=0; i < length; i += 3) { 
    NSInteger value = 0; 
     NSInteger j; 
    for (j = i; j < (i + 3); j++) { 
     value <<= 8; 

     if (j < length) { 
     value |= (0xFF & input[j]); 
     } 
    } 

    NSInteger theIndex = (i/3) * 4; 
    output[theIndex + 0] =     table[(value >> 18) & 0x3F]; 
    output[theIndex + 1] =     table[(value >> 12) & 0x3F]; 
    output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '='; 
    output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '='; 
    } 

    return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease]; 
} 
+0

¿Alguna versión rápida si la tiene? –

0

he modificado el código anterior para satisfacer mis necesidades, la construcción de un HTTP POST. Yo era capaz de saltarse el paso NSString, e incluir saltos de línea en el código BASE64, que al menos un servidor web encontrados más apetecible:

#define LINE_SIZE 76 

//originally from: http://www.cocoadev.com/index.pl?BaseSixtyFour 
// via joshrl on stockoverflow 

- (void) appendBase64Of: (NSData *)inData to:(NSMutableData *)outData { 
    const uint8_t* input = (const uint8_t*)[inData bytes]; 
    NSInteger length = [inData length]; 

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/="; 

    uint8_t buf[LINE_SIZE + 4 + 2]; 
    size_t n = 0; 

    NSInteger i; 
    for (i=0; i < length; i += 3) { 
     NSInteger value = 0; 
     NSInteger j; 
     for (j = i; j < (i + 3); j++) { 
      value <<= 8; 

      if (j < length) { 
       value |= (0xFF & input[j]); 
      } 
     } 

     buf[n + 0] =     table[(value >> 18) & 0x3F]; 
     buf[n + 1] =     table[(value >> 12) & 0x3F]; 
     buf[n + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '='; 
     buf[n + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '='; 
     n += 4; 
     if (n + 2 >= LINE_SIZE) { 
      buf[n++] = '\r'; 
      buf[n++] = '\n'; 
      [outData appendBytes:buf length:n]; 
      n = 0; 
     } 
    } 
    if (n > 0) { 
     buf[n++] = '\r'; 
     buf[n++] = '\n'; 
     [outData appendBytes:buf length:n]; 
    } 
    return; 
} 
20

Como una actualización, el SDK iOS7 tiene una categoría de NSData (NSDataBase64Encoding) con métodos

-[NSData base64EncodedStringWithOptions:] 
-[NSData initWithBase64EncodedString:options:] 
-[NSData initWithBase64EncodedData:options:] 
-[NSData base64EncodedDataWithOptions:] 

deben evitar tener que rodar su propia categoría método

+0

¡Guau, genial! Cada vez que se trata de base64, me pregunto por qué no está presente en las librerías estándar de tantos idiomas ... – DEAD10CC

+1

Están disponibles de nuevo en iOS 4, iOS 7 SDK acaba de hacerlos públicos – Crake

+0

Lo sentimos, hay funciones equivalentes métodos disponibles en iOS 4 (initWithBase64Encoding y base64Encoding) – Crake

2

iOS siempre ha incluido soporte incorporado para la codificación y decodificación base 64. Si mira resolv.h, debería ver las dos funciones b64_ntop y b64_pton. La biblioteca Square SocketRocket proporciona un ejemplo razonable de cómo utilizar estas funciones desde Object-c.

Estas funciones están muy bien probadas y son confiables, a diferencia de muchas de las implementaciones que puede encontrar en publicaciones aleatorias en Internet. No olvides vincular contra libresolv.dylib.

Si enlace contra el SDK de iOS 7, puede utilizar los métodos más nuevos initWithBase64Encoding: y base64EncodedDataWithOptions:. Estos existen en versiones anteriores, pero eran privados. Entonces, si enlaza con el SDK 6, puede encontrarse con un comportamiento indefinido. Este sería un ejemplo de cómo usar esto solo cuando se enlaza con el SDK 7:

#ifndef __IPHONE_7_0 
    // oh no! you are using something unsupported! 
    // Call and implementation that uses b64_pton here 
#else 
    data = [[NSData alloc] initWithBase64Encoding:string]; 
#endif