2010-03-27 13 views
6

Come faccio a rimuovere un numero di byte da un array di byte?Rimuovere i primi 16 byte?

+4

Un'altra domanda SO difettosa, ne abbiamo ricevute molte ultimamente. Distinto da una domanda a frase unica che non fa molto per spiegare il titolo. Di gran lunga l'approccio migliore è quello di non farlo.Molti metodi che accettano un array hanno un sovraccarico che richiede un offset e una lunghezza. C'è anche una classe dedicata per questo: ArraySegment . Se questo ti sarebbe di aiuto non è chiaro dalla tua domanda. Probabilmente no. –

risposta

24

EDIT: Come il commento di nobugz (e la risposta di Reed Copsey) menziona, se non effettivamente bisogno il risultato come un array di byte, si dovrebbe considerare di usare ArraySegment<T>:

ArraySegment<byte> segment = new ArraySegment<byte>(full, 16, full.Length - 16); 

In caso contrario, la copia sarà necessario: gli array hanno sempre una dimensione fissa, quindi non è possibile "rimuovere" i primi 16 byte dall'array esistente. Invece, dovrai creare un nuovo array più piccolo e copiare i dati rilevanti in esso.

suggerimento di Zach è nella giusta direzione per l'approccio non LINQ, ma può essere resa più semplice (questo presuppone che si conosce già la matrice originale è di almeno 16 byte di lunghezza):

byte[] newArray = new byte[oldArray.Length - 16]; 
Buffer.BlockCopy(oldArray, 16, newArray, 0, newArray.Length); 

o

byte[] newArray = new byte[oldArray.Length - 16]; 
Array.Copy(oldArray, 16, newArray, 0, newArray.Length); 

ho sospettoBuffer.BlockCopy sarà leggermente più veloce, ma non so per certo.

Si noti che entrambi potrebbero essere significativamente più efficienti rispetto all'approccio LINQ se gli array coinvolti sono grandi: l'approccio LINQ richiede che ogni byte venga restituito singolarmente da un iteratore e le copie potenzialmente intermedie da realizzare (nello stesso come l'aggiunta di articoli a un List<T> ha bisogno di aumentare periodicamente l'array di supporto). Ovviamente non ottimizzarlo, ma vale se si verifica se questo bit di codice è un collo di bottiglia delle prestazioni.

EDIT: Ho eseguito un benchmark molto "rapido e sporco" dei tre approcci. Non mi fido del benchmark per distinguere tra Buffer.BlockCopy e Array.Copy - erano piuttosto vicini - ma l'approccio LINQ era oltre 100 volte più lento.

Sul mio portatile, utilizzando array di byte di 10.000 elementi, sono stati necessari circa 10 secondi per eseguire 40.000 copie utilizzando LINQ; gli approcci di cui sopra hanno richiesto circa 80ms per fare lo stesso lavoro. Ho aumentato il numero di iterazioni a 4.000.000 e ci sono voluti solo circa 7 secondi. Ovviamente si applicano i normali avvertimenti sui micro-benchmark, ma questa è una differenza piuttosto significativa.

sicuramente utilizzare l'approccio di cui sopra, se questo è in un percorso di codice che è importante per le prestazioni :)

+0

+1, il buffering è decisamente più efficiente per i grandi array. –

+0

Qual è la differenza tra Buffer.BlockCopy e Array.Copy quando utilizzato con gli array di byte? – dtb

+0

@dtb: Non mi aspetto che ci siano differenze funzionali in questo caso. 'Buffer.BlockCopy' è un po 'più restrittivo - sospetto che sia implementato in un modo di livello inferiore, ma non conosco i dettagli. –

14

Si potrebbe fare questo:

using System.Linq 

// ... 

var newArray = oldArray.Skip(numBytes).ToArray(); 
0

Se non è possibile utilizzare LINQ, si poteva fare in questo modo:

byte[] myArray = // however you acquire the array 

byte[] newArray = new byte[myArray.Length - 16]; 

for (int i = 0; i < newArray.Length; i++) 
{ 
    newArray[i] = myArray[i + 16]; 
} 

// newArray is now myArray minus the first 16 bytes 

Avrete anche bisogno per gestire il caso in cui la matrice è lungo meno di 16 byte.

6

Vorrei anche ricordare - a seconda di come si prevede di utilizzare i risultati, spesso, un approccio alternativo è quello di utilizzare ArraySegment<T> per accedere alla porzione restante dell'array. Ciò impedisce la necessità di copiare l'array, che può essere più efficiente in alcuni scenari di utilizzo:

ArraySegment<byte> segment = new ArraySegment<byte>(originalArray, 16, originalArray.Length-16); 

// Use segment how you'd use your array... 
Problemi correlati