Entra

View Full Version : Java e file di testo


Vegale
16-12-2002, 15:20
Dispongo di un file di testo contenenti frasi varie. Il mio progamma ne dovrebbe leggerne una a caso e stamparla. Vorrei conoscere il metodo più pratico per effettuare questa cosa, dato che mi sto scervellando! Per ora son riuscito a caprire come leggere un file di testo in maniera sequenziale, con la classe BufferedReader.
Inoltre, vorrei che il Math.random fosse fatto tenendo conto di tutti gli elementi del file, ma come faccio a sapere quanti elementi (per esempio, quante righe) ci sono nel suddetto file?
Domanda curiosa... :muro:

PGI
17-12-2002, 12:39
Se vuoi sapere il numero di linee contenute in un file di testo puoi usare un ciclo tipo questo su un oggetto LineNumberReader


while(!eof) {
if(lineReader.readLine()==null)
eof=true;
}


Al termine del ciclo il metodo "getLineNumber()" di LineNumberReader restituisce un "int" il cui valore è l'indice dell'ultima riga letta (cioè il numero totale di righe a partire dalla linea zero).

Lo stesso LineNumberReader ti permette poi di spostarti tra le linee di testo con il metodo "setLineNumber(int indice)": la chiamata successiva del metodo "readLine()" leggerà la linea all'indice scelto.

Potresti anche "infilare" le linee file di testo in un Vector all'inizio del programma per evitare un continuo accesso al disco fisso, ma questo dipende anche dal numero di "frasi" da leggere.

Ciao.

Vegale
17-12-2002, 23:12
Originally posted by "PGI"

Se vuoi sapere il numero di linee contenute in un file di testo puoi usare un ciclo tipo questo su un oggetto LineNumberReader


while(!eof) {
if(lineReader.readLine()==null)
eof=true;
}


Al termine del ciclo il metodo "getLineNumber()" di LineNumberReader restituisce un "int" il cui valore è l'indice dell'ultima riga letta (cioè il numero totale di righe a partire dalla linea zero).

Lo stesso LineNumberReader ti permette poi di spostarti tra le linee di testo con il metodo "setLineNumber(int indice)": la chiamata successiva del metodo "readLine()" leggerà la linea all'indice scelto.

Potresti anche "infilare" le linee file di testo in un Vector all'inizio del programma per evitare un continuo accesso al disco fisso, ma questo dipende anche dal numero di "frasi" da leggere.

Ciao.

Difatti, avevo pensato ad un Vector, ma mi pareva troppo impegnativo caricare tutte le frasi in memoria, che possono tra l'altro essere parecchie, per poi leggerne solo una.. Tra il Vector e quello che dici tu, quale può garantire migliori prestazioni?
La classe LineNumberReader l'ho conosciuta poco fa e mi pare interessante.. Vedrò cosa posso fare con i tui consigli.. :) Grazie per ora. Ciao

Vegale
18-12-2002, 19:04
Purtroppo il metodo setLineNumber a cui ti riferisci non funziona come si deve. Infatti, nella classe LineNumberReader, tra le info ho trovato questo:

* Note however, that <CODE>setLineNumber(int)</CODE> does not actually change the current
* position in the stream; it only changes the value that will be returned
* by <CODE>getLineNumber()</CODE>.

Non cambia la posizione nello stream, quindi non mi serve molto.. :(
E se facessi tanti readLine() finché non mi trovo alla riga che voglio? Fa schifo? :p

Vegale
18-12-2002, 19:23
Altro problema e poi basta.. :)
una volta fatto il ciclo per trovare il getLineNumber, mi trovo alla fine del file. Per ritornare in cima, devo riaprire il file o c'è un altor metodo? Troppi accessi al disco fisso? ;_;

PGI
18-12-2002, 21:08
Dopo l'ultimo (utilissimo :D ) consiglio che ti ho dato, stavolta ho prima provato e poi postato!

L'utilità dei metodi setLineNumber() e getLineNumber() generosamente forniti da Sun mi sfugge, visto che non fanno una mazza :D .

Puoi evitare di riaprire il file "marcando" il buffer con il metodo mark(int size) all'apertura del file e richiamare il metodo reset() quando vuoi tornare all'inizio.

Visto però che la classe LineNumberReader contiene due metodi (i famigerati setLineNumber() e getLineNumber()) praticamente vuoti, tanto vale crearsi un proprio LineNumberReader estendendo quello di Sun "sovrascrivendo quà e là" ;)

Per il metodo setLineNumber() anche a me l'unica soluzione sembra un ciclo (io ho provato un "for").

Ti scrivo una classe di esempio:


public class MyLineReader extends LineNumberReader{

public MyLineReader(Reader reader, int readAhead) throws IOException{
super(reader);
mark(readAhead);
}

public void setLineNumber(int lineNum) {
super.setLineNumber(lineNum);
try {
reset();
for(int i=0;i<lineNum;i++) {
readLine();
}
} catch (IOException ex) {
System.err.println("Error while setting line");
System.out.println(ex);
}
}
}


Per quanto riguarda la dimensione da passare al metodo mark(int) io l'ho ottenuta passando per un FileInputStream() così:

FileInputStream inFile=new FileInputStream(file);
InputStreamReader inReader=new InputStreamReader(inFile);
MyLineReader lineReader=new MyLineReader(inReader,inFile.available()*2);

In Java un char occupa due byte, ecco perchè la "dimensione" del buffer è ottenuta moltiplicando per 2 il valore (in byte) della dimensione del "FileInputStream".

A questo punto i metodi "reset()" e "setLineNumber(int)" fanno quello che dovrebbero fare ;) .

Usare un Vector (o un array) per immagazzinare i dati all'inizio del programma dovrebbe evitarti la scrittura di un tuo reader; tieni anche conto del fatto che anche se un Vector occupa un po' memoria, dal punto di vista delle prestazioni il sacrificio è più che accettabile, sia perchè un sistema medio possiede memoria a sufficienza per "stoccare" anche una serie molto lunga di stringhe (e meno che tu non voglia infilargli dentro l'enciclopedia britannica :D), sia perchè ne beneficia la facilità di lettura del codice.

Se hai bisogno sono qui (magari arrivo un po' tardi, ma arrivo :) )

Ciao.

cn73
19-12-2002, 09:25
public String getBuffer() throws Exception{
try
{
File fileInst = new File(nomeFile);
FileReader file = new FileReader(nomeFile);
char[] c = new char[(int)fileInst.length()];
file.read(c);
String buffer = String.copyValueOf(c);
file.close();


return buffer;
}
catch(Exception ex)
{
System.err.println("Exception raised by <getBuffer>: "+ex);
throw ex;
}
}


Questo metodi ti ritorna una stringa, sulla quale puoi operare con accesso diretto e non sequenziale, tramite i metodi substring() e similari...

Vegale
19-12-2002, 16:20
Grazie per le risposte :cool:
Hmm.. se dici che l'utilizzo di un vettore rimane comunque una scelta da considerare, posso provare con quello, benché sia riuscito alla fine a fare ciò che volevo fare leggendo dal file (con molta fatica!). Anche perché, una volta creato il vettore, posso utilizzare quello invece che riaprire nuovamente il file.

boh.. vediamo un po'.. mi rifarò risentire.. :)

Vegale
22-12-2002, 00:22
Ok.. il programma mi gira sotto, diciamo "dos", invece provando a creare una applet mi dà il seguente errore:
caricamento: impossibile definire istanze per Prova.class.
java.lang.InstantiationException: Prova

E pochi minuti prima girava sotto console! Mah..
Il problema è dato dal costruttore di oggetti, che mi serve per infilare le righe dentro il vettore, in modo da poterle rileggere successivamente.

Qualche idea?