2016-04-12 11 views
6

Mi sto occupando di un'applicazione che ha bisogno di leggere casualmente un'intera riga di testo da una serie di file di testo potenzialmente grandi (~ 3 + GB).Come posso indicizzare in modo efficiente un file?

Le linee possono essere di lunghezza diversa.

Per ridurre GC e creare stringhe inutili, sto usando la soluzione forniti a: Is there a better way to determine the number of lines in a large txt file(1-2 GB)? per rilevare ogni nuova riga e memorizza nel una mappa in una passata producendo così un indice di lineNo => position cioè:

// maps each line to it's corresponding fileStream.position in the file  
List<int> _lineNumberToFileStreamPositionMapping = new List<int>(); 
  1. passare attraverso l'intero file
  2. quando rileva un incremento new linelineCount e aggiungere il fileStream.Position al _lineNumberToFileStreamPositionMapping

Abbiamo quindi utilizzare un'API simile a:

public void ReadLine(int lineNumber) 
{ 
    var getStreamPosition = _lineNumberToFileStreamPositionMapping[lineNumber]; 
    //... set the stream position, read the byte array, convert to string etc. 
} 

Questa soluzione sta attualmente fornendo una buona prestazione ma ci sono due cose che non mi piacciono:

  1. Dal momento che non conosco la numero totale di righe nel file, non posso preallocare un array quindi devo usare un List<int> che ha la potenziale inefficienza del ridimensionamento a raddoppiare di quello che effettivamente ho bisogno;
  2. Utilizzo memoria, ad esempio per un file di testo di ~ 1 GB con ~ 5 milioni di righe di testo l'indice occupa ~ 150 MB Vorrei davvero diminuire il più possibile.

Tutte le idee sono molto apprezzate.

+0

Perché l'indice 150 gb? 5 milioni di ints sono meno di 20 MB di storage grezzo, quindi dove ottieni questo valore? – DavidG

+0

Questo è ciò che mi mostra il profiler, ma di nuovo non ho scavato più a fondo. A parte questo, 20mb sarebbe lo scenario ideale, ma in realtà potrebbe essere il doppio rispetto alla logica di ridimensionamento della 'Lista' – MaYaN

+0

Forse dovresti usare un semplice vecchio array allora. Non sono sicuro che un 'Elenco' fornisca effettivamente qualcosa di utile qui. Una volta costruito l'elenco, convertirlo in array e lanciare la lista. – DavidG

risposta

3
  1. Usa List.Capacity per aumentare manualmente la capacità, ad esempio ogni 1000 linee o giù di lì.

  2. Se si desidera scambiare le prestazioni per la memoria, è possibile farlo: anziché memorizzare le posizioni di ogni riga, memorizzare solo le posizioni di ogni centesimo (o qualcosa) linea. Quindi quando, per esempio, è richiesta la linea 253, andare alla posizione della linea 200 e contare 53 linee avanti.

+1

aaaah ... molto bello! Mi piace molto provarlo. tnx! – MaYaN

Problemi correlati