Come faccio a creare una stringa Java dal contenuto di un file?


1513

Sto usando il linguaggio di seguito da qualche tempo. E sembra essere il più diffuso, almeno sui siti che ho visitato.

Esiste un modo migliore / diverso per leggere un file in una stringa in Java?

private String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    try {
        while((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    } finally {
        reader.close();
    }
}

7
Qualcuno può spiegarmi in modo molto semplice cosa c'è con il NIO? Ogni volta che lo leggo, mi perdo nell'ennesima menzione del canale :(
OscarRyz,

7
ricorda che non è garantito che il separatore di riga nel file non sia necessario uguale al separatore di riga del sistema.
Henrik Paul,

138
Potresti per favore inserire finalmente un tentativo adeguato che chiuda il lettore? Qualcuno potrebbe effettivamente utilizzare questo esempio e introdurre un bug nel suo codice.
Hans-Peter Störr,

6
Il codice sopra ha un bug nell'aggiungere un nuovo carattere extra nell'ultima riga. Dovrebbe essere simile al seguente if (line = reader.readLine ())! = Null) {stringBuilder.append (line); } while (line = reader.readLine ())! = null) {stringBuilder.append (ls); stringBuilder.append (line); }
Deep

27
Java 7 introduce byte[] Files.readAllBytes(file);A coloro che suggeriscono la soluzione scanner "a una riga": non è necessario chiuderla?
Val

Risposte:


1536

Leggi tutto il testo da un file

Java 11 ha aggiunto il metodo readString () per leggere piccoli file come a String, preservando i terminatori di riga:

String content = Files.readString(path, StandardCharsets.US_ASCII);

Per le versioni tra Java 7 e 11, ecco un linguaggio compatto, robusto, racchiuso in un metodo di utilità:

static String readFile(String path, Charset encoding) 
  throws IOException 
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

Leggi righe di testo da un file

Java 7 ha aggiunto un metodo pratico per leggere un file come righe di testo, rappresentato come a List<String>. Questo approccio è "lossy" perché i separatori di riga vengono eliminati dalla fine di ogni riga.

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

Java 8 ha aggiunto il Files.lines()metodo per produrre a Stream<String>. Ancora una volta, questo metodo è in perdita perché i separatori di riga vengono eliminati. Se IOExceptiondurante la lettura del file viene rilevato un , viene racchiuso in un UncheckedIOException, poiché Streamnon accetta lambdas che generano eccezioni verificate.

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

Questo Streamha bisogno di una close()chiamata; questo è scarsamente documentato sull'API e sospetto che molte persone non si accorgano nemmeno che Streamha un close()metodo. Assicurarsi di utilizzare un blocco ARM come mostrato.

Se si sta lavorando con una fonte diversa da un file, è possibile utilizzare il lines()metodo BufferedReader, invece.

Utilizzo della memoria

Il primo metodo, che preserva le interruzioni di riga, può richiedere temporaneamente memoria più volte la dimensione del file, perché per un breve periodo il contenuto del file non elaborato (un array di byte) e i caratteri decodificati (ognuno dei quali è 16 bit anche se codificato come 8 bit nel file) risiedono in memoria contemporaneamente. È più sicuro applicare a file che si ritiene siano piccoli rispetto alla memoria disponibile.

Il secondo metodo, leggere le righe, di solito è più efficiente in termini di memoria, poiché il buffer di byte di input per la decodifica non deve contenere l'intero file. Tuttavia, non è ancora adatto a file di dimensioni molto grandi rispetto alla memoria disponibile.

Per leggere file di grandi dimensioni, è necessario un design diverso per il programma, uno che legge una porzione di testo da un flusso, lo elabora e passa al successivo, riutilizzando lo stesso blocco di memoria di dimensioni fisse. Qui, "grande" dipende dalle specifiche del computer. Al giorno d'oggi, questa soglia potrebbe essere di molti gigabyte di RAM. Il terzo metodo, usando a Stream<String>è un modo per farlo, se i tuoi "record" di input sono linee individuali. (L'uso del readLine()metodo di BufferedReaderè l'equivalente procedurale di questo approccio.)

Codifica dei caratteri

Una cosa che manca nell'esempio nel post originale è la codifica dei caratteri. Ci sono alcuni casi speciali in cui l'impostazione predefinita della piattaforma è ciò che desideri, ma sono rari e dovresti essere in grado di giustificare la tua scelta.

La StandardCharsetsclasse definisce alcune costanti per le codifiche richieste per tutti i runtime Java:

String content = readFile("test.txt", StandardCharsets.UTF_8);

L'impostazione predefinita piattaforma è disponibile presso la Charsetclasse di sé:

String content = readFile("test.txt", Charset.defaultCharset());

Nota: questa risposta sostituisce ampiamente la mia versione di Java 6. L'utilità di Java 7 semplifica in modo sicuro il codice e la vecchia risposta, che utilizzava un buffer di byte mappato, impediva l'eliminazione del file letto fino a quando il buffer mappato non veniva raccolto. È possibile visualizzare la versione precedente tramite il collegamento "modificato" su questa risposta.


3
Tecnicamente parlando, è O (n) nel tempo e nello spazio. Qualitativamente, a causa del requisito di immutabilità di Strings, è piuttosto difficile da ricordare; temporaneamente ci sono due copie dei dati del char in memoria, oltre allo spazio per i byte codificati. Supponendo una codifica a byte singolo, richiederà (temporaneamente) 5 byte di memoria per ogni carattere nel file. Poiché la domanda richiede specificamente una stringa, è quello che mostro, ma se puoi lavorare con CharBuffer restituito dalla "decodifica", il requisito di memoria è molto inferiore. Per quanto riguarda il tempo, non credo che troverai qualcosa di più veloce nelle librerie Java di base.
Erickson,

5
Possibile errore di battitura? NIO ha una classe Charset (non CharSet) chiamata java.nio.charset.Charset. È questo ciò che CharSet avrebbe dovuto essere?
Jonathan Wright,

31
Nota: dopo aver esercitato un po 'quel codice, ho scoperto che non è possibile eliminare in modo affidabile il file subito dopo averlo letto con questo metodo, che in alcuni casi potrebbe essere un problema, ma non mio. Potrebbe essere in relazione con questo problema: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 ? Alla fine sono andato con la proposta di Jon Skeet che non soffre di questo errore. Comunque, volevo solo dare le informazioni, per altre persone, per ogni evenienza ...
Sébastien Nussbaumer,

5
@ Sébastien Nussbaumer: ho anche incontrato questo problema. Incredibile che il bug sia stato contrassegnato "Non risolverà". Ciò significa essenzialmente che FileChannel#mapè, in generale, inutilizzabile.
Joonas Pulakka,

4
@ Sébastien Nussbaumer: il bug è stato cancellato dal database dei bug Oracle / Sun: "Questo bug non è disponibile." Google ha memorizzato nella cache il sito webcache.googleusercontent.com/search?q=cache:bugs.sun.com/…
bobndrew

351

Se sei disposto a utilizzare una libreria esterna, controlla Apache Commons IO (200KB JAR). Contiene un org.apache.commons.io.FileUtils.readFileToString()metodo che consente di leggere un intero Filein un Stringcon una riga di codice.

Esempio:

import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}

Non trovo questo metodo nell'URL fornito.
OscarRyz

2
È nella classe org.apache.commons.io.FileUtils
Cyrille Ka,

2
Sto usando anche FileUtils, ma mi chiedo cosa sia meglio tra FileUtils o la risposta nio accettata?
Guillaume,

4
@Guillaume: la domanda più grande è se ti senti a tuo agio con una biblioteca di terze parti. Se hai Commons IO o Guava nel tuo progetto, allora usalo (solo per semplicità del codice; altrimenti probabilmente non ci sarà una differenza evidente).
Jonik,

183

Una soluzione molto snella basata su Scanner:

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

Oppure, se si desidera impostare il set di caratteri:

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

Oppure, con un blocco try-with-resources , che chiamerà scanner.close()per te:

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

Ricorda che il Scannercostruttore può lanciare un IOException. E non dimenticare di importare java.ioe java.util.

Fonte: blog di Pat Niemeyer


4
\\ A funziona perché non esiste un "altro inizio del file", quindi in realtà stai leggendo l'ultimo token ... che è anche il primo. Non ho mai provato con \\ Z. Nota anche che puoi leggere tutto ciò che è leggibile, come File, InputStreams, canali ... A volte uso questo codice per leggere dalla finestra di visualizzazione di Eclipse, quando non sono sicuro di leggere un file o un altro ... .yes, classpath mi confonde.
Pablo Grisafi,

1
Come poster, posso dire che davvero non so se e quando il file sarà chiuso correttamente ... Non scrivo mai questo nel codice di produzione, lo uso solo per test o debug.
Pablo Grisafi,

2
Ha un limite di 1024 caratteri credo
Whimusical

20
Lo scanner implementa Chiudibile (invoca vicino alla fonte) - quindi, sebbene elegante, non dovrebbe essere davvero una linea. La dimensione predefinita del buffer è 1024, ma Scanner aumenterà le dimensioni necessarie (vedere Scanner # makeSpace ())
earcam

8
Questo fallisce per file vuoti con a java.util.NoSuchElementException.
SpaceTrucker,

117
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

da java 7 puoi farlo in questo modo.


Questo dovrebbe essere accettato come risposta - riga singola, senza librerie esterne.
Cherry,

Ciò ha aggiunto un carattere newline alla fine, anche se non era presente nel file
Stefan Haberl,

79

Se stai cercando un'alternativa che non coinvolga una libreria di terze parti (ad es. I / O Commons ), puoi utilizzare la classe Scanner :

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}

2
Penso che questo sia il modo migliore. Dai
Tarski,

3
Il costruttore dello scanner che accetta una stringa non considera la stringa come il nome di un file da leggere, ma come il testo da scansionare. Faccio quell'errore tutto il tempo. : - /
Alan Moore,

@Alan, buona cattura. Ho modificato leggermente la risposta di Don per risolvere il problema (spero).
Jonik,

3
fileContents.append (scanner.nextLine ()) append (lineSeparator).;
divieto di geoingegneria

1
Cambia l'istruzione di inizializzazione in Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));. In caso contrario, è possibile acquisire solo parte del file.
Wei Yang,

71

La guava ha un metodo simile a quello di Commons IOUtils menzionato da Willi aus Rohr:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

EDIT di PiggyPiglet
Files#toString è obsoleto e dovrebbe essere rimosso da Octobor 2019. Invece usa Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

EDIT di Oscar Reyes

Questo è il codice sottostante (semplificato) nella libreria citata:

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

Modifica (di Jonik): quanto sopra non corrisponde al codice sorgente delle recenti versioni di Guava. Per l'origine corrente, vedere le classi File , CharStreams , ByteSource e CharSource nel pacchetto com.google.common.io .


Questo codice ha un casting da lungo a int che potrebbe far apparire un comportamento folle con file di grandi dimensioni. Ha spazi extra e dove chiudi l'inputstream?
Mohamed Taher Alrefaie,

@MTA: il flusso è chiuso, notare l'uso di Closerin CharSource . Il codice nella risposta non è l'attuale, attuale fonte di Guava.
Jonik,

54
import java.nio.file.Files;

.......

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }

6
O ancora più semplice:new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));

12
oppure new String(Files.readAllBytes(Paths.get(filename)));:-)
assafmo,

1
Ben giocato, e per salvare il prossimo ragazzo di Google, Pathsè apparentemente 1.7+ come è FileSystems. (Dang it!)
ruffin

4
È un peccato che questa risposta non abbia più voti. Stavo cercando il modo più rapido e semplice per ottenere un file di testo in una stringa. Questo è tutto e se non avessi fatto scorrere verso il basso, il basso e il basso, mi sarei perso. L'OP dovrebbe considerare di accettare questa risposta per spostarla in alto.
Spina

@Thorn Questa risposta ha una gestione degli errori orribile. Non utilizzare questo metodo nel codice di produzione, o meglio: mai.
xehpuk,

51

Se hai bisogno di un'elaborazione di stringhe (elaborazione parallela) Java 8 ha la grande API Stream.

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

Altri esempi sono disponibili negli esempi JDK sample/lambda/BulkDataOperationsche possono essere scaricati dalla pagina di download di Oracle Java SE 8

Un altro esempio di copertina

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));

Il .parallel () si verifica dopo aver letto le righe o prima?
Istvan,

Il vero lavoro inizia dal momento in cui viene invocata l'operazione di raccolta (...). Stream è popolato pigramente riga per riga. Non è necessario leggere l'intero file in memoria prima dell'elaborazione (ad es. Filtro e mappatura).
Andrei N,

tagliare prima di scegliere linee non vuote?
Thorbjørn Ravn Andersen,

50

Tale codice normalizzerà le interruzioni di riga, che potrebbero essere o meno ciò che si desidera veramente fare.

Ecco un'alternativa che non lo fa e che è (IMO) più semplice da capire rispetto al codice NIO (anche se lo utilizza ancora java.nio.charset.Charset):

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}

1
Perdonami per aver rianimato un commento così vecchio, ma intendevi passare un oggetto String chiamato "file", o dovrebbe essere invece un oggetto File?
Bryan Larson,

28

Raccolti tutti i modi possibili per leggere il file come stringa da disco o rete.

  • Guava: Google utilizza le classi Resources,Files

    static Charset charset = com.google.common.base.Charsets.UTF_8;
    public static String guava_ServerFile( URL url ) throws IOException {
        return Resources.toString( url, charset );
    }
    public static String guava_DiskFile( File file ) throws IOException {
        return Files.toString( file, charset );
    }

  • APACHE - IO COMUNI usando le classi IOUtils, FileUtils

    static Charset encoding = org.apache.commons.io.Charsets.UTF_8;
    public static String commons_IOUtils( URL url ) throws IOException {
        java.io.InputStream in = url.openStream();
        try {
            return IOUtils.toString( in, encoding );
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    public static String commons_FileUtils( File file ) throws IOException {
        return FileUtils.readFileToString( file, encoding );
        /*List<String> lines = FileUtils.readLines( fileName, encoding );
        return lines.stream().collect( Collectors.joining("\n") );*/
    }

  • Java 8 BufferReader utilizzando l' API Stream

    public static String streamURL_Buffer( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( source ) );
        //List<String> lines = reader.lines().collect( Collectors.toList() );
        return reader.lines().collect( Collectors.joining( System.lineSeparator() ) );
    }
    public static String streamFile_Buffer( File file ) throws IOException {
        BufferedReader reader = new BufferedReader( new FileReader( file ) );
        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
    }

  • Classe scanner con regex \A. che corrisponde all'inizio dell'input.

    static String charsetName = java.nio.charset.StandardCharsets.UTF_8.toString();
    public static String streamURL_Scanner( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    public static String streamFile_Scanner( File file ) throws IOException {
        Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }

  • Java 7 ( java.nio.file.Files.readAllBytes)

    public static String getDiskFile_Java7( File file ) throws IOException {
        byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
        return new String( readAllBytes );
    }

  • BufferedReaderusando InputStreamReader.

    public static String getDiskFile_Lines( File file ) throws IOException {
        StringBuffer text = new StringBuffer();
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }

Esempio con metodo principale per accedere ai metodi precedenti.

public static void main(String[] args) throws IOException {
    String fileName = "E:/parametarisation.csv";
    File file = new File( fileName );

    String fileStream = commons_FileUtils( file );
            // guava_DiskFile( file );
            // streamFile_Buffer( file );
            // getDiskFile_Java7( file );
            // getDiskFile_Lines( file );
    System.out.println( " File Over Disk : \n"+ fileStream );


    try {
        String src = "https://code.jquery.com/jquery-3.2.1.js";
        URL url = new URL( src );

        String urlStream = commons_IOUtils( url );
                // guava_ServerFile( url );
                // streamURL_Scanner( url );
                // streamURL_Buffer( url );
        System.out.println( " File Over Network : \n"+ urlStream );
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

@vedere


26

Se è un file di testo, perché non usare apache commons-io ?

Ha il seguente metodo

public static String readFileToString(File file) throws IOException

Se si desidera utilizzare le righe come elenco

public static List<String> readLines(File file) throws IOException

25

Dal JDK 11:

String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8

Perché, oh perché, introdurre nuovi metodi che si basano sul set di caratteri predefinito nel 2018?
mryan,

2
@mryan questo metodo non si basa sul set di caratteri di sistema predefinito. L'impostazione predefinita è UTF-8, va bene.
leventov,

@leventov hai ragione! così fa Files.readAllLines! ciò rende l'API dei file non molto coerente con i metodi precedenti ma è in meglio :)
mryan

17

Per leggere un file come binario e convertirlo alla fine

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}

16

Con Java 7, questa è la mia opzione preferita per leggere un file UTF-8:

String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");

A partire da Java 7, JDK ha la nuova java.nio.fileAPI, che fornisce molte scorciatoie, quindi le librerie di terze parti non sono sempre necessarie per semplici operazioni sui file.


15

Java cerca di essere estremamente generale e flessibile in tutto ciò che fa. Di conseguenza, qualcosa che è relativamente semplice in un linguaggio di scripting (il tuo codice verrebbe sostituito con " open(file).read()" in Python) è molto più complicato. Non sembra esserci un modo più breve di farlo, tranne usare una libreria esterna (come menzionato Willi aus Rohr ). Le tue opzioni:

  • Utilizzare una libreria esterna.
  • Copia questo codice in tutti i tuoi progetti.
  • Crea la tua mini-biblioteca che contiene funzioni che usi spesso.

La tua scommessa migliore è probabilmente la seconda, poiché ha il minor numero di dipendenze.


4
Yeap. Rende il linguaggio di livello "alto" assumere un significato diverso. Java è di alto livello rispetto a C ma basso rispetto a Python o Ruby
OscarRyz,

3
Concordo sul fatto che Java è a lungo sulle astrazioni di alto livello ma sui metodi di convenienza
Dónal

3
È vero, Java ha un numero folle di modi per gestire i file e molti di loro sembrano complicati. Ma questo è abbastanza vicino a quello che abbiamo nelle lingue di livello superiore:byte[] bytes = Files.readAllBytes(someFile.toPath());
Thorn,

11

Utilizzando JDK 8 o versioni successive:

nessuna libreria esterna utilizzata

È possibile creare un nuovo oggetto String dal contenuto del file (utilizzando le classi dal java.nio.filepacchetto):

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}

Duplica della risposta di Moritz Petersen che ha scritto: String content = new String (Files.readAllBytes (Paths.get (nomefile)), "UTF-8");
Jean-Christophe Blanchard,

8

Esiste una variazione sullo stesso tema che utilizza un ciclo for, anziché un ciclo while, per limitare l'ambito della variabile di linea. Se è "migliore" è una questione di gusti personali.

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}

3
Ciò cambierà le nuove righe nella scelta di nuova riga predefinita. Questo può essere desiderabile o non intenzionale.
Peter Lawrey,

Ripristina la modifica a questa risposta perché il punto era restringere l'ambito della linevariabile. La modifica lo ha dichiarato due volte, il che sarebbe un errore di compilazione.
Dan Dyer

7

Se non si ha accesso alla Filesclasse, è possibile utilizzare una soluzione nativa.

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}

esempio charset da invocare?
Giovedì

4

Una soluzione flessibile che utilizza IOUtils di Apache commons-io in combinazione con StringWriter :

Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
  IOUtils.copy(input, output);
} finally {
  input.close();
}
String fileContents = output.toString();

Funziona con qualsiasi lettore o flusso di input (non solo con i file), ad esempio durante la lettura da un URL.


3

Fare attenzione quando si utilizza fileInputStream.available()l'intero restituito non deve rappresentare la dimensione effettiva del file, ma piuttosto la quantità indovinata di byte che il sistema dovrebbe essere in grado di leggere dallo stream senza bloccare IO. Un modo semplice e sicuro potrebbe apparire così

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

Va considerato che questo approccio non è adatto per codifiche di caratteri multi-byte come UTF-8.


1
Questo codice può dare risultati imprevedibili. Secondo la documentazione del available()metodo, non vi è alcuna garanzia che venga raggiunta la fine del file nel caso in cui il metodo restituisca 0. In tal caso si potrebbe finire con un file incompleto. Quel che è peggio, il numero di byte effettivamente letti può essere inferiore al valore restituito da available(), nel qual caso si ottiene un output danneggiato.
wau,

3

Questo usa il metodo RandomAccessFile.readFully, sembra essere disponibile da JDK 1.0!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}

3

Puoi provare la classe Scanner e File, una soluzione a poche righe

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}

3

Utente java.nio.Filesper leggere tutte le righe del file.

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}

3
public static String slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

    BufferedReader reader = new BufferedReader(new FileReader(file));

    try {
        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}

Penso che questo abbia l'inconveniente di utilizzare la codifica predefinita della piattaforma. +1 comunque :)
OscarRyz

7
Mi sembra che il blocco finally non conosca le variabili definite nel blocco try. javac 1.6.0_21 genera l'errore cannot find symbol.
ceving

Hai mai provato il tuo codice? Hai definito il lettore nel blocco try / catch, quindi non sarà accessibile nel blocco finally.
mauron85,

2

Non posso ancora commentare altre voci, quindi la lascerò qui.

Una delle migliori risposte qui ( https://stackoverflow.com/a/326448/1521167 ):

private String readFile(String pathname) throws IOException {

File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int)file.length());
Scanner scanner = new Scanner(file);
String lineSeparator = System.getProperty("line.separator");

try {
    while(scanner.hasNextLine()) {        
        fileContents.append(scanner.nextLine() + lineSeparator);
    }
    return fileContents.toString();
} finally {
    scanner.close();
}
}

ha ancora un difetto. Mette sempre il nuovo carattere di riga alla fine della stringa, il che può causare alcuni bug strani. Il mio consiglio è di cambiarlo in:

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

    try {
        if (scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine());
        }
        while (scanner.hasNextLine()) {
            fileContents.append(lineSeparator + scanner.nextLine());
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}

Nel primo caso potresti aggiungere una nuova riga in più alla fine. nel secondo caso potresti ometterne uno. Quindi entrambi sono ugualmente sbagliati. Vedi questo articolo
Patrick Parker,

2

Dopo aver premuto Ctrl + F dopo Scanner, penso che anche la soluzione Scanner debba essere elencata. Nel modo più semplice da leggere va così:

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

Se usi Java 7 o più recenti (e dovresti davvero) prendere in considerazione l'utilizzo di try-with-resources per rendere più facile la lettura del codice. Niente più cose ravvicinate che sporcano tutto. Ma questa è principalmente una scelta stilistica.

Sto pubblicando questo principalmente per completezza, dal momento che se devi farlo molto, dovrebbero esserci delle cose java.nio.file.Files che dovrebbero fare meglio il lavoro.

Il mio suggerimento sarebbe di usare Files # readAllBytes (Path) per afferrare tutti i byte e alla nuova stringa (byte [] Charset) per ottenere una stringa di cui ti puoi fidare. I set di caratteri saranno cattivi per te durante la tua vita, quindi fai attenzione a queste cose ora.

Altri hanno dato codice e cose e non voglio rubare la loro gloria. ;)


2

Usando questa libreria , è una riga:

String data = IO.from(new File("data.txt")).toString();

1
se le righe all'interno della libreria non vengono conteggiate.
Ari

2

Inoltre, se il tuo file si trova all'interno di un vaso, puoi anche usare questo:

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

Il percorso dovrebbe iniziare / ad esempio se lo è il tuo vaso

my.jar/com/some/thing/a.txt

Quindi vuoi invocarlo in questo modo:

String myTxt = fromFileInJar("/com/com/thing/a.txt");

2

In una riga (Java 8), supponendo che tu abbia un Reader:

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));

2

Sulla base della risposta di @erickson, puoi usare:

public String readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.