2009-09-14 2 views
19

Quindi, ecco l'affare: sto cercando di aprire un file (da byte), convertirlo in una stringa in modo da poter fare confusione con alcuni metadati nell'intestazione, convertirlo di nuovo a byte e salvarlo. Il problema che sto incontrando in questo momento è con questo codice. Quando confronto la stringa che è stata convertita avanti e indietro (ma non altrimenti modificata) nella matrice di byte originale, non è uguale. Come posso fare questo lavoro?Conversione di array di byte in stringa e viceversa in C#

public static byte[] StringToByteArray(string str) 
{ 
    UTF8Encoding encoding = new UTF8Encoding(); 
    return encoding.GetBytes(str); 
} 

public string ByteArrayToString(byte[] input) 
{ 
    UTF8Encoding enc = new UTF8Encoding(); 
    string str = enc.GetString(input); 
    return str; 
} 

Ecco come li sto confrontando.

byte[] fileData = GetBinaryData(filesindir[0], Convert.ToInt32(fi.Length)); 
string fileDataString = ByteArrayToString(fileData); 
byte[] recapturedBytes = StringToByteArray(fileDataString); 
Response.Write((fileData == recapturedBytes)); 

Sono sicuro che è UTF-8, utilizzando:

StreamReader sr = new StreamReader(filesindir[0]); 
Response.Write(sr.CurrentEncoding); 

che restituisce "System.Text.UTF8Encoding".

+6

sei sicuro che sia UTF-8 con cui iniziare? –

+0

Non sono sicuro. Come potrei dire se lo è o no? –

+0

Cosa vuoi dire, è ineguale? La tua stringa non ha eguali? non ottieni lo stesso risultato di stringa? – Khan

risposta

16

Provare le funzioni statiche nella classe Encoding che fornisce istanze delle varie codifiche. Non è necessario istanziare lo Encoding solo per la conversione in/da un array di byte. Come stai confrontando le stringhe nel codice?

Modifica

si sta confrontando gli array, non stringhe. Sono disuguali perché si riferiscono a due diversi array; usando l'operatore == si confronteranno solo i loro riferimenti, non i loro valori. Dovrai ispezionare ogni elemento dell'array per determinare se sono equivalenti.

public bool CompareByteArrays(byte[] lValue, byte[] rValue) 
{ 
    if(lValue == rValue) return true; // referentially equal 
    if(lValue == null || rValue == null) return false; // one is null, the other is not 
    if(lValue.Length != rValue.Length) return false; // different lengths 

    for(int i = 0; i < lValue.Length; i++) 
    { 
     if(lValue[i] != rValue[i]) return false; 
    } 

    return true; 
} 
+0

Ho modificato la domanda per mostrare come ... il codice non viene visualizzato nel commento! –

+0

Ho provato questo, restituiscono che non sono della stessa lunghezza. Deve essere da qualche altra parte. –

+3

Dai un'occhiata alla documentazione per la codifica UTF8. Esiste un'opzione per specificare se specificare o meno il preambolo. Se stai scoprendo che il tuo array di byte generato è più lungo dell'originale, è probabile che questo sia il tuo problema. Ancora una volta, è necessario assicurarsi che UTF8 sia, di fatto, la giusta codifica. Per quanto riguarda il modo in cui puoi dirlo, dovresti chiedere a chiunque ti fornisca i dati. –

3

Il tuo problema sembra essere il modo in cui si sta confrontando l'array di byte:

Response.Write((fileData == recapturedBytes)); 

questo sarà sempre return false in quanto si sta confrontando l'indirizzo della matrice di byte, non il valori che contiene Confrontare i dati della stringa o utilizzare un metodo per confrontare gli array di byte. Si potrebbe anche fare questo, invece:

Response.Write(Convert.ToBase64String(fileData) == Convert.ToBase64String(recapturedBytes)); 
5

A causa del fatto che le stringhe .NET utilizzano stringhe Unicode, non è più possibile fare questo la gente come ha fatto in C. Nella maggior parte dei casi, non si dovrebbe nemmeno tentativo a andare avanti e indietro dalla stringa < -> matrice di byte a meno che il contenuto non sia effettivamente testo.

devo chiarire questo punto: In .NET, se i dati non è byte[]testo, quindi non tentare di convertirlo in un string tranne che per la speciale Base64 codifica per i dati binari su un testo canale. Questo è un malinteso diffuso tra le persone che lavorano in .NET.

+4

Stringa <-> byte [] le conversioni dovrebbero generalmente essere eseguite attraverso una delle classi System.Text.Encoding, non la classe BitConverter. BitConverter.ToString converte un array di byte in una rappresentazione di stringa esadecimale dei numeri, ma ** non ** converte un array di byte in una stringa. –

+1

Heh, avrei dovuto rimuovere quella linea una volta saputo che non era il punto del mio post. –

7

Quando si dispone di byte prime (8-bit caratteri forse-non-stampabili) e si desidera manipolarli come una stringa NET e li trasformano di nuovo in byte, è possibile farlo utilizzando

Encoding.GetEncoding(1252) 

invece di UTF8Encoding. Quella codifica funziona per prendere qualsiasi valore a 8 bit e convertirlo in un char .NET a 16 bit, e viceversa, senza perdere alcuna informazione.

Nel caso specifico descritto sopra, con un file binario, non sarà possibile "confondere i metadati nell'intestazione" e fare in modo che le cose funzionino correttamente, a meno che la lunghezza dei dati non sia cambiata. Ad esempio, se l'intestazione contiene

{any}{any}ABC{any}{any} 

e si desidera cambiare ABC a DEF, che dovrebbe funzionare come vuoi. Ma se vuoi cambiare ABC in WXYZ, dovrai scrivere sopra il byte che segue "C" o dovrai (in sostanza) spostare tutto di un byte più a destra. In un tipico file binario, ciò farà molto casino.

Se i byte dopo "ABC" sono spazi o caratteri nulli, c'è una migliore possibilità che la scrittura di dati di sostituzione più grandi non causi problemi - ma non è ancora possibile sostituire ABC con WXYZ nella stringa .NET, rendendolo più lungo - Dovresti sostituire ABC {whatever_follows_it} con WXYZ. Detto questo, potresti scoprire che è più semplice lasciare i dati come byte e scrivere i dati di sostituzione un byte alla volta.

+0

Se uno ha una matrice di byte e desidera sostituire tutte le occorrenze di una particolare sequenza con un'altra sequenza di una lunghezza diversa (ad esempio, sostituisce tutte le occorrenze di {0x7D, 0x5E} con {0x7E}), converte in stringa, usando 'String .Replace', e quindi riconvertire un approccio ragionevole? La codifica summenzionata sostituirà ogni valore di byte 0-255 con il suo corrispondente codice con lo stesso numero [il fatto che la codifica sia senza perdita non implicherebbe di per sé che]? – supercat

+0

@supercat: sì, quell'approccio (purché si usi la codifica 1252) funzionerebbe. Ma non saresti ancora in grado di farlo con la maggior parte dei formati di file binari per le ragioni menzionate nel mio messaggio. –

+0

Se si utilizzano formati sensibili alla posizione, è ovvio che è necessario assicurarsi che le cose che non dovrebbero spostarsi, no. Anche allora, ci sarebbero casi in cui 'String.Replace' sembrerebbe utile se le stringhe" originale "e" sostituzione "hanno la stessa lunghezza. – supercat