2015-04-30 11 views
5

Come parte del mio corso Java, ho scritto uno scrittore e lettore "zip" - come funziona l'algoritmo di Huffman.Estendere il lettore, come restituire la mia "lettura"?

La mia classe estende Reader e ha un oggetto Reader r. Nel mio metodo principale, ho queste linee:

input = new BufferedReader(new HuffmanReader(new FileReader("output.hff"))); 
String str = input.readLine(); 

deve restituire la stringa decompresso ho scritto al file, dopo la decompressione, naturalmente. Ma restituisce la prima riga del file!

La mia funzione di lettura:

public int read(char[] cbuf, int off, int len) throws IOException { 
    //... 
    r.read(buffer,0,8192) 
    //does the decompress process 
    String fnlStr = ... //The final result 
    cbuf = fnlStr.toCharArray(); 
    //close streams 
    return cbuf.length; 
} 

finestra Risorse di debug mostra questo:

HuffmanReader.read(char[], int, int) line: 23 
BufferedReader.fill() line: not available 
BufferedReader.readLine(boolean) line: not available  
BufferedReader.readLine() line: not available 
Run.main(String[]) line: 23 

Si chiama la mia funzione di lettura due volte. Come posso impedire a bufferReader di chiamare di nuovo la funzione di lettura?

+0

1. Considera 'off' e' len' nella funzione 'read()'? 2. Hai bisogno di BufferedReader (non puoi testare senza di esso)? – xerx593

+1

L'unico punto in cui si legge da 'input' è in' input.readLine() ', che, naturalmente, legge solo una riga. Sono un po 'sorpreso dal fatto che la tua funzione 'read' funzioni del tutto, perché in realtà non scrivi sul buffer che è passato, ma assegni un nuovo buffer a' cbuf'. – dddsnn

+0

Inoltre non si usa il conteggio restituito da 'r.read().' Questo codice non può funzionare. – EJP

risposta

2

Non si restituiscono i dati letti dal metodo come si farebbe di solito. Invece, quando si chiama read, il chiamante ti dà l'array cbuf, che è essenzialmente l'indirizzo di un blocco di memoria, e ti dice di scrivere lenchar s in esso.

Quando si esegue cbuf = fnlStr.toCharArray(), si sta solo sostituendo la copia locale di quell'indirizzo con un altro indirizzo, ma in realtà non si sta modificando la memoria a cui si supponeva dovesse scrivere. È necessario eseguire iterazioni sull'array assegnato in un ciclo for e scrivere su di esso oppure utilizzare System.arraycopy se è stato creato un altro buffer contenente il risultato.

ad esempio il metodo read seguente sarà sempre leggere "Test\n":

public int read(char[] cbuf, int off, int len) throws IOException { 
    char[] result = "Test\n".toCharArray(); 
    int numRead = Math.min(len, result.length); 
    System.arraycopy(result, 0, cbuf, off, numRead); 
    return numRead; 
} 

Sostituzione del "Test\n" letterale con la stringa decompresso dovrebbe iniziare. Ovviamente, dovrai comunque gestire quanto della tua fonte hai già consumato.


E da BufferedReader chiamare read due volte: non si deve la cura quanto spesso si chiama. È sufficiente ottenere i dati dalla fonte sottostante, scriverlo su cbuf e restituire il numero di char s che hai scritto. Se non è rimasto nulla da leggere, restituire -1 per segnalare la fine del flusso (nel qual caso BufferedReader smetterà di chiamare read).


Per inciso, Reader si intende leggere i flussi di caratteri, mentre InputStream is for binary data (è praticamente la stessa cosa, solo con byte[] invece di char[] e senza l'utilizzo di un set di caratteri). Dato che i file compressi sono binari, potresti voler cambiare il tuo FileReader in un FileInputStream.

Potrei immaginare bug strani se, per qualche motivo, il set di caratteri con cui si codifica non è lo stesso con cui decodificare. O meno drammaticamente, potresti usare più spazio di quanto pensi, se un'unità di codice a 16 bit in UTF-16 necessita di 3 unità di codice a 8 bit in UTF-8.

+0

Grazie mille! Questo era il mio problema Funziona bene! Conosco il problema con il Reader, è un limite che abbiamo avuto per questo esercizio. Grazie. –

1

Stai leggendo solo la prima riga. Modificare la prima parte a qualcosa di simile:

input = new BufferedReader(new HuffmanReader(new FileReader("output.hff"))); 
Arraylist<String> list = new ArrayList<String>(); 
String line; 

while ((line = reader.readLine()) != null) { 
    list.add(line); 
} 

E anche, per fissare che il metodo viene chiamato due volte, fare un valore booleano e impostarla su true dopo aver fatto le tue cose nel metodo. Quindi, all'inizio di quel metodo, controlla se quel booleano è vero. Se lo è, ritorna dal metodo in modo che non esegua le cose dopo di nuovo.

+0

Oppure chiama il metodo una volta ;-) – EJP

+0

@ ImBatman64 Ciao, ho provato prima la cosa booleana e non ha funzionato, perché non so come scrivere il mio risultato nel buffer. Quando arriva la volta successiva, torna a String string una stringa con alcuni spazi. Non posso cambiare la parte principale - fa parte dell'esercizio. BufferedReader sta tentando di leggere di nuovo, anche se dovrebbe leggere solo una riga. –

+0

@RoeiJacobovich Dove stai chiamando esattamente il metodo? – ImBatman64

Problemi correlati