Hoe maak ik een Java-string van de inhoud van een bestand?

Ik gebruik het onderstaande idioom al een tijdje. En het lijkt het meest verspreid te zijn, tenminste op de sites die ik heb bezocht.

Is er een betere/andere manier om een ​​bestand in een string in Java in te lezen?

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();
    }
}

Antwoord 1, autoriteit 100%

Alle tekst uit een bestand lezen

Java 11 heeft de readString()methode om kleine bestanden te lezen als een String, met behoud van regelafsluitingen:

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

Voor versies tussen Java 7 en 11 is hier een compact, robuust idioom, verpakt in een hulpprogramma-methode:

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

Regels tekst uit een bestand lezen

Java 7 heeft een gemakkelijke methode om een ​​bestand te lezen als regels tekst,weergegeven als een List<String>. Deze benadering is “lossy” omdat de lijnscheidingstekens aan het einde van elke regel worden verwijderd.

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

Java 8 heeft de Files.lines()methode om een ​​Stream<String>te produceren. Nogmaals, deze methode is verliesgevend omdat lijnscheidingstekens worden verwijderd. Als een IOExceptionwordt aangetroffen tijdens het lezen van het bestand, wordt deze verpakt in een UncheckedIOException, aangezien Streamgeen lambda’s accepteert die gecontroleerde uitzonderingen genereren.

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

Deze Streamheeft wel een close()aanroep; dit is slecht gedocumenteerd in de API, en ik vermoed dat veel mensen niet eens merken dat Streameen close()methode heeft. Zorg ervoor dat u een ARM-blok gebruikt zoals weergegeven.

Als u met een andere bron dan een bestand werkt, kunt u de lines()methode in plaats daarvan in BufferedReader.

Geheugengebruik

De eerste methode, die regeleinden behoudt, kan tijdelijk geheugen nodig hebben dat meerdere keren zo groot is als het bestand, omdat gedurende korte tijd de onbewerkte bestandsinhoud (een bytearray) en de gedecodeerde tekens (die elk 16 bits zijn) zelfs indien gecodeerd als 8 bits in het bestand) zich in één keer in het geheugen bevinden. Het is het veiligst om bestanden toe te passen waarvan u weet dat ze klein zijn in verhouding tot het beschikbare geheugen.

De tweede methode, het lezen van regels, is gewoonlijk efficiënter met het geheugen, omdat de invoerbytebuffer voor het decoderen niet het hele bestand hoeft te bevatten. Het is echter nog steeds niet geschikt voor bestanden die erg groot zijn in verhouding tot het beschikbare geheugen.

Voor het lezen van grote bestanden heb je een ander ontwerp voor je programma nodig, een die een stuk tekst uit een stream leest, deze verwerkt en vervolgens doorgaat naar de volgende, waarbij hetzelfde geheugenblok van vaste grootte opnieuw wordt gebruikt. Hier hangt “groot” af van de computerspecificaties. Tegenwoordig kan deze drempel vele gigabytes RAM zijn. De derde methode, het gebruik van een Stream<String>is een manier om dit te doen, als uw invoer “records” individuele regels zijn. (Het gebruik van de readLine()-methode van BufferedReaderis het procedurele equivalent van deze aanpak.)

Tekencodering

Een ding dat ontbreekt in het voorbeeld in de originele post is de tekencodering. Er zijn enkele speciale gevallen waarin de standaard van het platform is wat u wilt, maar ze zijn zeldzaam en u zou uw keuze moeten kunnen rechtvaardigen.

De StandardCharsetsdefinieert enkele constanten voor de coderingen die vereist zijn voor alle Java-runtimes:

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

De platformstandaard is beschikbaar via de klasse Charsetzelf:

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

Opmerking: dit antwoord vervangt grotendeels mijn Java 6-versie. Het nut van Java 7 vereenvoudigt de code veilig en het oude antwoord, dat een toegewezen bytebuffer gebruikte, verhinderde dat het gelezen bestand werd verwijderd totdat de toegewezen buffer was verzameld. Je kunt de oude versie bekijken via de “bewerkte” link op dit antwoord.


Antwoord 2, autoriteit 22%

Als je bereid bent een externe bibliotheek te gebruiken, bekijk dan Apache Commons IO(200KB JAR). Het bevat een org.apache.commons.io.FileUtils.readFileToString()methode waarmee je een hele Filein een Stringmet één regel code.

Voorbeeld:

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);
}

Antwoord 3, autoriteit 11%

Een zeer slanke oplossing gebaseerd op Scanner:

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

Of, als u de tekenset wilt instellen:

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

Of, met een try-with-resources-blok , die scanner.close()voor je aanroept:

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

Onthoud dat de Scanner-constructor een IOExceptionkan genereren. En vergeet niet om java.ioen java.utilte importeren.

Bron: Pat Niemeyer’s blog


Antwoord 4, autoriteit 9%

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);

sinds java 7 kun je het op deze manier doen.


Antwoord 5, autoriteit 5%

Als u op zoek bent naar een alternatief dat geen bibliotheek van derden nodig heeft (bijv. Commons I/O), kunt u de Scannerklasse:

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();
    }
}

Antwoord 6, autoriteit 4%

Guavaheeft een methode die vergelijkbaar is met die van Commons IOUtils die Willi aus Rohr noemde:

import com.google.common.base.Charsets;
import com.google.common.io.Files;
// ...
String text = Files.toString(new File(path), Charsets.UTF_8);

BEWERKEN door PiggyPiglet
Files#toStringis verouderd en moet in oktober 2019 worden verwijderd. Gebruik in plaats daarvan
Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

BEWERKEN door Oscar Reyes

Dit is de (vereenvoudigde) onderliggende code van de geciteerde bibliotheek:

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 );

Bewerken(door Jonik): Het bovenstaande komt niet overeen met de broncode van recente Guava-versies. Zie voor de huidige bron de klassen Bestanden, CharStreams, ByteSource en CharSourcein com.google.common.io pakket.


Antwoord 7, autoriteit 3%

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 "";
    }

Antwoord 8, autoriteit 3%

Als je een stringverwerking nodig hebt (parallelle verwerking), heeft Java 8 de geweldige Stream API.

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

Meer voorbeelden zijn beschikbaar in JDK-voorbeelden sample/lambda/BulkDataOperationsdie kunnen worden gedownload van Oracle Java SE 8 downloadpagina

Nog een one-liner-voorbeeld

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

Antwoord 9, autoriteit 3%

Die code zal regeleinden normaliseren, wat misschien wel of niet is wat je echt wilt doen.

Hier is een alternatief dat dat niet doet en dat (IMO) eenvoudiger te begrijpen is dan de NIO-code (hoewel het nog steeds java.nio.charset.Charsetgebruikt):

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();
    }        
}

Antwoord 10, autoriteit 2%

Alle mogelijke manieren verzameld om het bestand als string van schijf of netwerk te lezen.

  • Guava: Googlemet klassen 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 – COMMONS IOmet klassen 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 BufferReadermet behulp van Stream-API

    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()));
    }
    

  • Scannerklasse met regex \A. die overeenkomt met het begin van de invoer.

    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 );
    }
    

  • BufferedReadermet behulp van 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();
    }
    

Voorbeeld met hoofdmethode om toegang te krijgen tot de bovenstaande methoden.

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();
    }
}

@see


Antwoord 11, autoriteit 2%

Als het een tekstbestand is, waarom gebruikt u dan niet apache commons-io?

Het heeft de volgende methode

public static String readFileToString(File file) throws IOException

Als je de regels als lijst wilt gebruiken, gebruik dan

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

Antwoord 12

Sinds 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

Antwoord 13

Een bestand als binair lezen en aan het einde converteren

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();
    }
}

Antwoord 14

Met Java 7 is dit mijn voorkeursoptie om een ​​UTF-8-bestand te lezen:

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

Sinds Java 7 heeft de JDK de nieuwe java.nio.fileAPI, die veel snelkoppelingen biedt, zodat bibliotheken van derden niet altijd nodig zijn voor eenvoudige bestandsbewerkingen.


Antwoord 15

Java probeert in alles wat het doet extreem algemeen en flexibel te zijn. Als gevolg hiervan is iets dat relatief eenvoudig is in een scripttaal (je code zou worden vervangen door “open(file).read()” in python) een stuk ingewikkelder. Er lijkt geen kortere manier te zijn om dit te doen, behalve het gebruik van een externe bibliotheek (zoals Willi aus Rohrgenoemd). Uw opties:

  • Gebruik een externe bibliotheek.
  • Kopieer deze code naar al uw projecten.
  • Maak je eigen minibibliotheek met functies die je vaak gebruikt.

Je beste gok is waarschijnlijk de 2e, omdat deze de minste afhankelijkheden heeft.


Antwoord 16

JDK 8 of hoger gebruiken:

geen externe bibliotheken gebruikt

U kunt een nieuw String-object maken van de bestandsinhoud (met klassen uit het pakket java.nio.file):

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

Antwoord 17

Er is een variatie op hetzelfde thema die een for-lus gebruikt in plaats van een while-lus, om de reikwijdte van de regelvariabele te beperken. Of het “beter” is, is een kwestie van persoonlijke smaak.

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

Antwoord 18

Als je geen toegang hebt tot de klasse Files, kun je een native oplossing gebruiken.

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);
}

Antwoord 19

Een flexibele oplossing met behulp van IOUtilsvan Apache commons-ioin combinatie met StringWriter:

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

Het werkt met elke lezer of invoerstroom (niet alleen met bestanden), bijvoorbeeld bij het lezen van een URL.


Antwoord 20

Houd er rekening mee dat bij het gebruik van fileInputStream.available()het geretourneerde gehele getal niet de werkelijke bestandsgrootte hoeft te vertegenwoordigen, maar eerder het geschatte aantal bytes dat het systeem uit de stream zou moeten kunnen lezen zonder IO blokkeren. Een veilige en eenvoudige manier zou er zo uit kunnen zien

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();
}

Er moet rekening mee worden gehouden dat deze benadering nietgeschikt is voor multi-byte tekencoderingen zoals UTF-8.


Antwoord 21

Deze gebruikt de methode RandomAccessFile.readFully, het lijkt beschikbaar te zijn vanaf 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
        }
    }
}

Antwoord 22

U kunt de klasse Scanner en Bestand proberen, een oplossing van een paar regels

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

Antwoord 23

Op basis van het antwoord van @erickson kun je het volgende gebruiken:

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()]));
}

Antwoord 24

Gebruiker java.nio.Filesom alle regels van het bestand te lezen.

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

Antwoord 25

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();
}

Antwoord 26

Ik kan nog geen commentaar geven op andere inzendingen, dus ik laat het hier gewoon achter.

Een van de beste antwoorden hier (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();
}
}

heeft nog steeds één fout. Het plaatst altijd een nieuwe regel char aan het einde van de tekenreeks, wat enkele rare bugs kan veroorzaken. Mijn suggestie is om het te veranderen 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();
    }
}

Antwoord 27

Na Ctrl+F’ing na Scanner, denk ik dat de Scanner-oplossing ook moet worden vermeld. Op de gemakkelijkst te lezen manier gaat het als volgt:

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;
}

Als je Java 7 of nieuwer gebruikt (en dat zou je ook moeten doen), overweeg dan om try-with-resources te gebruiken om de code leesbaarder te maken. Geen dot-close-dingen meer die alles vervuilen. Maar dat is volgens mij vooral een stilistische keuze.

Ik post dit voornamelijk voor voltooiing, want als je dit veel moet doen, zouden er dingen moeten staan ​​in java.nio.file.Filesdie het werk beter zou moeten doen.

Mijn suggestie zou zijn om Files#readAllBytes(Path)om alle bytes te pakken en door te voeren naar nieuwe String(byte[] Charset)om er een string uit te halen die je kunt vertrouwen. Tekensets zullen tijdens je leven gemeen tegen je zijn, dus pas nu op voor dit soort dingen.

Anderen hebben code en zo gegeven, en ik wil hun glorie niet stelen. 😉


Antwoord 28

Als u deze bibliotheekgebruikt, is het één regel:

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

Antwoord 29

Ook als je bestand toevallig in een pot zit, kun je dit ook gebruiken:

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

Het pad moet beginnen met /, bijvoorbeeld als uw jar is

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

Dan wil je het als volgt aanroepen:

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

Antwoord 30

In één regel (Java 8), ervan uitgaande dat je een Reader hebt:

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

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes