java - new - jtextpane html




Eine Nur-Text-Datei in Java lesen (16)

Es scheint, dass es verschiedene Möglichkeiten gibt, Daten von Dateien in Java zu lesen und zu schreiben.

Ich möchte ASCII-Daten aus einer Datei lesen. Was sind die möglichen Wege und ihre Unterschiede?


ASCII ist eine TEXT-Datei, daher würden Sie Readers zum Lesen verwenden. Java unterstützt auch das Lesen aus einer Binärdatei mit InputStreams . Wenn die gelesenen Dateien sehr groß sind, sollten Sie einen FileReader über einem FileReader , um die FileReader zu verbessern.

Lesen Sie diesen Artikel zur Verwendung eines Readers

Ich würde Ihnen auch empfehlen, dieses wundervolle (noch freie) Buch namens Thinking In Java herunterzuladen und zu lesen

In Java 7 :

neue Zeichenfolge (Files.readAllBytes (...)) oder Files.readAllLines(...)

In Java 8 :

Files.lines(..).forEach(...)


BufferedReader verwenden:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

BufferedReader br;
try {
    br = new BufferedReader(new FileReader("/fileToRead.txt"));
    try {
        String x;
        while ( (x = br.readLine()) != null ) {
            // Printing out each line in the file
            System.out.println(x);
        }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}
catch (FileNotFoundException e) {
    System.out.println(e);
    e.printStackTrace();
}

Die Methoden in org.apache.commons.io.FileUtils können ebenfalls sehr nützlich sein, zB:

/**
 * Reads the contents of a file line by line to a List
 * of Strings using the default encoding for the VM.
 */
static List readLines(File file)

Die einfachste Möglichkeit, Daten aus einer Datei in Java zu lesen, besteht darin, die Dateiklasse zum Lesen der Datei und die Scannerklasse zum Lesen des Inhalts der Datei zu verwenden.

public static void main(String args[])throws Exception
{
   File f = new File("input.txt");
   takeInputIn2DArray(f);
}

public static void takeInputIn2DArray(File f) throws Exception
{
    Scanner s = new Scanner(f);
    int a[][] = new int[20][20];
    for(int i=0; i<20; i++)
    {
        for(int j=0; j<20; j++)
        {
            a[i][j] = s.nextInt();
        }
    }
}

PS: Vergessen Sie nicht, java.util. *; damit der Scanner funktioniert.


Dies ist möglicherweise nicht die genaue Antwort auf die Frage. Es ist nur eine andere Möglichkeit, eine Datei zu lesen, in der Sie den Pfad zu Ihrer Datei nicht explizit in Ihrem Java-Code angeben, sondern stattdessen als Befehlszeilenargument.

Mit folgendem Code

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class InputReader{

    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s="";
        while((s=br.readLine())!=null){
            System.out.println(s);
        }
    }
}

mach einfach weiter und lauf es mit:

java InputReader < input.txt

Dies würde den Inhalt der input.txt und auf die Konsole drucken.

Sie können Ihre System.out.println() auch so System.out.println() , dass sie über die Befehlszeile in eine bestimmte Datei schreibt:

java InputReader < input.txt > output.txt

Dies würde von input.txt lesen und in output.txt schreiben.


Dieser Code, den ich programmiert habe, ist viel schneller für sehr große Dateien:

public String readDoc(File f) {
    String text = "";
    int read, N = 1024 * 1024;
    char[] buffer = new char[N];

    try {
        FileReader fr = new FileReader(f);
        BufferedReader br = new BufferedReader(fr);

        while(true) {
            read = br.read(buffer, 0, N);
            text += new String(buffer, 0, read);

            if(read < N) {
                break;
            }
        }
    } catch(Exception ex) {
        ex.printStackTrace();
    }

    return text;
}

Hier ist eine einfache Lösung:

String content;

content = new String(Files.readAllBytes(Paths.get("sample.txt")));

Hier sind die drei arbeitenden und getesteten Methoden:

Verwenden von BufferedReader

package io;
import java.io.*;
public class ReadFromFile2 {
    public static void main(String[] args)throws Exception {
        File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
        BufferedReader br = new BufferedReader(new FileReader(file));
        String st;
        while((st=br.readLine()) != null){
            System.out.println(st);
        }
    }
}

Scanner

package io;

import java.io.File;
import java.util.Scanner;

public class ReadFromFileUsingScanner {
    public static void main(String[] args) throws Exception {
        File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
        Scanner sc = new Scanner(file);
        while(sc.hasNextLine()){
            System.out.println(sc.nextLine());
        }
    }
}

Verwenden von FileReader

package io;
import java.io.*;
public class ReadingFromFile {

    public static void main(String[] args) throws Exception {
        FileReader fr = new FileReader("C:\\Users\\pankaj\\Desktop\\test.java");
        int i;
        while ((i=fr.read()) != -1){
            System.out.print((char) i);
        }
    }
}

Lesen Sie die gesamte Datei ohne eine Schleife mit der Scanner Klasse

package io;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ReadingEntireFileWithoutLoop {

    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
        Scanner sc = new Scanner(file);
        sc.useDelimiter("\\Z");
        System.out.println(sc.next());
    }
}

Ich musste die verschiedenen Wege benchmarken. Ich werde meine Ergebnisse kommentieren, aber kurz gesagt, der schnellste Weg ist die Verwendung eines einfachen alten BufferedInputStream über einen FileInputStream. Wenn viele Dateien gelesen werden müssen, reduzieren drei Threads die Gesamtausführungszeit auf ungefähr die Hälfte, aber das Hinzufügen von mehr Threads verschlechtert die Leistung progressiv, bis es mit zwanzig Threads dreimal länger dauert als mit nur einem Thread.

Die Annahme ist, dass Sie eine Datei lesen und mit ihrem Inhalt etwas Sinnvolles tun müssen. In den Beispielen lesen Sie Zeilen aus einem Protokoll und zählen diejenigen, die Werte enthalten, die einen bestimmten Schwellenwert überschreiten. Ich Files.lines(Paths.get("/path/to/file.txt")).map(line -> line.split(";")) davon aus, dass die Files.lines(Paths.get("/path/to/file.txt")).map(line -> line.split(";")) Java 8 Files.lines(Paths.get("/path/to/file.txt")).map(line -> line.split(";")) keine Option ist .

Ich habe auf Java 1.8, Windows 7 und sowohl SSD als auch HDD-Laufwerken getestet.

Ich habe sechs verschiedene Implementierungen geschrieben:

rawParse : Verwenden Sie BufferedInputStream über einen FileInputStream und schneiden Sie dann Zeilen aus, die byteweise gelesen werden. Dies hat alle anderen Single-Thread-Ansätze übertroffen, ist aber für Nicht-ASCII-Dateien möglicherweise sehr unpraktisch.

lineReaderParse : Verwenden Sie einen BufferedReader über einen FileReader, lesen Sie Zeile für Zeile, trennen Sie Zeilen, indem Sie String.split () aufrufen. Dies ist ungefähr 20% langsamer als rawParse.

lineReaderParseParallel : Dies ist dasselbe wie lineReaderParse, aber es verwendet mehrere Threads. Dies ist in allen Fällen die schnellste Option.

nioFilesParse : Benutze java.nio.files.Files.lines ()

nioAsyncParse : Verwenden Sie einen AsynchronousFileChannel mit einem Beendigungshandler und einem Thread-Pool.

nioMemoryMappedParse : Verwenden Sie eine Memory-Mapped-Datei. Dies ist wirklich eine schlechte Idee, die Ausführungszeiten mindestens drei Mal länger als jede andere Implementierung liefert.

Dies sind die durchschnittlichen Zeiten für das Lesen von 204 Dateien mit jeweils 4 MB auf einem Quad-Core-i7- und SSD-Laufwerk. Die Dateien werden im laufenden Betrieb generiert, um ein Disk-Caching zu vermeiden.

rawParse                11.10 sec
lineReaderParse         13.86 sec
lineReaderParseParallel  6.00 sec
nioFilesParse           13.52 sec
nioAsyncParse           16.06 sec
nioMemoryMappedParse    37.68 sec

Ich fand einen Unterschied kleiner als ich erwartet hatte zwischen dem Laufen auf einer SSD oder einem Festplattenlaufwerk, das die SSD ungefähr 15% schneller ist. Dies liegt möglicherweise daran, dass die Dateien auf einer unfragmentierten Festplatte erstellt und sequenziell gelesen werden. Daher kann das drehende Laufwerk fast wie eine SSD ausgeführt werden.

Ich war überrascht von der geringen Leistung der nioAsyncParse-Implementierung. Entweder habe ich etwas falsch implementiert oder die Multithread-Implementierung mit NIO und ein Completion-Handler führt dasselbe (oder sogar schlechter) aus als eine Single-Thread-Implementierung mit der java.io-API. Darüber hinaus ist das asynchrone Parsen mit einem CompletionHandler in Codezeilen viel länger und schwierig zu implementieren als eine direkte Implementierung in alten Streams.

Nun folgt auf die sechs Implementierungen eine Klasse, die sie alle enthält, sowie eine parametrisierbare main () -Methode, die es erlaubt, mit der Anzahl der Dateien, der Dateigröße und dem Grad der Nebenläufigkeit zu spielen. Beachten Sie, dass die Größe der Dateien plus minus 20% variiert. Dies verhindert, dass alle Dateien genau gleich groß sind.

rawParse

public void rawParse(final String targetDir, final int numberOfFiles) throws IOException, ParseException {
    overrunCount = 0;
    final int dl = (int) ';';
    StringBuffer lineBuffer = new StringBuffer(1024);
    for (int f=0; f<numberOfFiles; f++) {
        File fl = new File(targetDir+filenamePreffix+String.valueOf(f)+".txt");
        FileInputStream fin = new FileInputStream(fl);
        BufferedInputStream bin = new BufferedInputStream(fin);
        int character;
        while((character=bin.read())!=-1) {
            if (character==dl) {

                // Here is where something is done with each line
                doSomethingWithRawLine(lineBuffer.toString());
                lineBuffer.setLength(0);
            }
            else {
                lineBuffer.append((char) character);
            }
        }
        bin.close();
        fin.close();
    }
}

public final void doSomethingWithRawLine(String line) throws ParseException {
    // What to do for each line
    int fieldNumber = 0;
    final int len = line.length();
    StringBuffer fieldBuffer = new StringBuffer(256);
    for (int charPos=0; charPos<len; charPos++) {
        char c = line.charAt(charPos);
        if (c==DL0) {
            String fieldValue = fieldBuffer.toString();
            if (fieldValue.length()>0) {
                switch (fieldNumber) {
                    case 0:
                        Date dt = fmt.parse(fieldValue);
                        fieldNumber++;
                        break;
                    case 1:
                        double d = Double.parseDouble(fieldValue);
                        fieldNumber++;
                        break;
                    case 2:
                        int t = Integer.parseInt(fieldValue);
                        fieldNumber++;
                        break;
                    case 3:
                        if (fieldValue.equals("overrun"))
                            overrunCount++;
                        break;
                }
            }
            fieldBuffer.setLength(0);
        }
        else {
            fieldBuffer.append(c);
        }
    }
}

lineReaderParsen

public void lineReaderParse(final String targetDir, final int numberOfFiles) throws IOException, ParseException {
    String line;
    for (int f=0; f<numberOfFiles; f++) {
        File fl = new File(targetDir+filenamePreffix+String.valueOf(f)+".txt");
        FileReader frd = new FileReader(fl);
        BufferedReader brd = new BufferedReader(frd);

        while ((line=brd.readLine())!=null)
            doSomethingWithLine(line);
        brd.close();
        frd.close();
    }
}

public final void doSomethingWithLine(String line) throws ParseException {
    // Example of what to do for each line
    String[] fields = line.split(";");
    Date dt = fmt.parse(fields[0]);
    double d = Double.parseDouble(fields[1]);
    int t = Integer.parseInt(fields[2]);
    if (fields[3].equals("overrun"))
        overrunCount++;
}

lineReaderParseParallel

public void lineReaderParseParallel(final String targetDir, final int numberOfFiles, final int degreeOfParalelism) throws IOException, ParseException, InterruptedException {
    Thread[] pool = new Thread[degreeOfParalelism];
    int batchSize = numberOfFiles / degreeOfParalelism;
    for (int b=0; b<degreeOfParalelism; b++) {
        pool[b] = new LineReaderParseThread(targetDir, b*batchSize, b*batchSize+b*batchSize);
        pool[b].start();
    }
    for (int b=0; b<degreeOfParalelism; b++)
        pool[b].join();
}

class LineReaderParseThread extends Thread {

    private String targetDir;
    private int fileFrom;
    private int fileTo;
    private DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private int overrunCounter = 0;

    public LineReaderParseThread(String targetDir, int fileFrom, int fileTo) {
        this.targetDir = targetDir;
        this.fileFrom = fileFrom;
        this.fileTo = fileTo;
    }

    private void doSomethingWithTheLine(String line) throws ParseException {
        String[] fields = line.split(DL);
        Date dt = fmt.parse(fields[0]);
        double d = Double.parseDouble(fields[1]);
        int t = Integer.parseInt(fields[2]);
        if (fields[3].equals("overrun"))
            overrunCounter++;
    }

    @Override
    public void run() {
        String line;
        for (int f=fileFrom; f<fileTo; f++) {
            File fl = new File(targetDir+filenamePreffix+String.valueOf(f)+".txt");
            try {
            FileReader frd = new FileReader(fl);
            BufferedReader brd = new BufferedReader(frd);
            while ((line=brd.readLine())!=null) {
                doSomethingWithTheLine(line);
            }
            brd.close();
            frd.close();
            } catch (IOException | ParseException ioe) { }
        }
    }
}

nioFilesParsen

public void nioFilesParse(final String targetDir, final int numberOfFiles) throws IOException, ParseException {
    for (int f=0; f<numberOfFiles; f++) {
        Path ph = Paths.get(targetDir+filenamePreffix+String.valueOf(f)+".txt");
        Consumer<String> action = new LineConsumer();
        Stream<String> lines = Files.lines(ph);
        lines.forEach(action);
        lines.close();
    }
}


class LineConsumer implements Consumer<String> {

    @Override
    public void accept(String line) {

        // What to do for each line
        String[] fields = line.split(DL);
        if (fields.length>1) {
            try {
                Date dt = fmt.parse(fields[0]);
            }
            catch (ParseException e) {
            }
            double d = Double.parseDouble(fields[1]);
            int t = Integer.parseInt(fields[2]);
            if (fields[3].equals("overrun"))
                overrunCount++;
        }
    }
}

nioAsyncParse

public void nioAsyncParse(final String targetDir, final int numberOfFiles, final int numberOfThreads, final int bufferSize) throws IOException, ParseException, InterruptedException {
    ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(numberOfThreads);
    ConcurrentLinkedQueue<ByteBuffer> byteBuffers = new ConcurrentLinkedQueue<ByteBuffer>();

    for (int b=0; b<numberOfThreads; b++)
        byteBuffers.add(ByteBuffer.allocate(bufferSize));

    for (int f=0; f<numberOfFiles; f++) {
        consumerThreads.acquire();
        String fileName = targetDir+filenamePreffix+String.valueOf(f)+".txt";
        AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get(fileName), EnumSet.of(StandardOpenOption.READ), pool);
        BufferConsumer consumer = new BufferConsumer(byteBuffers, fileName, bufferSize);
        channel.read(consumer.buffer(), 0l, channel, consumer);
    }
    consumerThreads.acquire(numberOfThreads);
}


class BufferConsumer implements CompletionHandler<Integer, AsynchronousFileChannel> {

        private ConcurrentLinkedQueue<ByteBuffer> buffers;
        private ByteBuffer bytes;
        private String file;
        private StringBuffer chars;
        private int limit;
        private long position;
        private DateFormat frmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        public BufferConsumer(ConcurrentLinkedQueue<ByteBuffer> byteBuffers, String fileName, int bufferSize) {
            buffers = byteBuffers;
            bytes = buffers.poll();
            if (bytes==null)
                bytes = ByteBuffer.allocate(bufferSize);

            file = fileName;
            chars = new StringBuffer(bufferSize);
            frmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            limit = bufferSize;
            position = 0l;
        }

        public ByteBuffer buffer() {
            return bytes;
        }

        @Override
        public synchronized void completed(Integer result, AsynchronousFileChannel channel) {

            if (result!=-1) {
                bytes.flip();
                final int len = bytes.limit();
                int i = 0;
                try {
                    for (i = 0; i < len; i++) {
                        byte by = bytes.get();
                        if (by=='\n') {
                            // ***
                            // The code used to process the line goes here
                            chars.setLength(0);
                        }
                        else {
                                chars.append((char) by);
                        }
                    }
                }
                catch (Exception x) {
                    System.out.println(
                        "Caught exception " + x.getClass().getName() + " " + x.getMessage() +
                        " i=" + String.valueOf(i) + ", limit=" + String.valueOf(len) +
                        ", position="+String.valueOf(position));
                }

                if (len==limit) {
                    bytes.clear();
                    position += len;
                    channel.read(bytes, position, channel, this);
                }
                else {
                    try {
                        channel.close();
                    }
                    catch (IOException e) {
                    }
                    consumerThreads.release();
                    bytes.clear();
                    buffers.add(bytes);
                }
            }
            else {
                try {
                    channel.close();
                }
                catch (IOException e) {
                }
                consumerThreads.release();
                bytes.clear();
                buffers.add(bytes);
            }
        }

        @Override
        public void failed(Throwable e, AsynchronousFileChannel channel) {
        }
};

VOLLE RUNNABLE UMSETZUNG ALLER FÄLLE

https://github.com/sergiomt/javaiobenchmark/blob/master/FileReadBenchmark.java



Sie können readAllLines und die join Methode verwenden, um den gesamten Dateiinhalt in einer Zeile abzurufen:

String str = String.join("\n",Files.readAllLines(Paths.get("e:\\text.txt")));

Es verwendet standardmäßig die UTF-8-Codierung, die ASCII-Daten korrekt liest.

Sie können auch readAllBytes verwenden:

String str = new String(Files.readAllBytes(Paths.get("e:\\text.txt")), StandardCharsets.UTF_8);

Ich denke, readAllBytes ist schneller und präziser, weil es keine neue Zeile mit \n und auch eine neue Zeile kann \r\n . Es hängt von Ihren Bedürfnissen ab, welcher geeignet ist.


Unten ist ein One-Liner, es in Java 8 zu tun. Angenommen, text.txt Datei text.txt befindet sich im Stammverzeichnis des Projektverzeichnisses von Eclipse.

Files.lines(Paths.get("text.txt")).collect(Collectors.toList());

Verwenden Sie für JSF-basierte Maven-Webanwendungen einfach ClassLoader und den Ordner Resources , um alle gewünschten Dateien einzulesen:

  1. Legen Sie eine Datei, die Sie lesen möchten, in den Ordner Resources.
  2. Setzen Sie die Apache Commons IO Abhängigkeit in Ihr POM:

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.3.2</version>
    </dependency>
    
  3. Verwenden Sie den folgenden Code, um es zu lesen (z. B. lesen Sie unten in einer .json-Datei):

    String metadata = null;
    FileInputStream inputStream;
    try {
    
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        inputStream = (FileInputStream) loader
                .getResourceAsStream("/metadata.json");
        metadata = IOUtils.toString(inputStream);
        inputStream.close();
    }
    catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return metadata;
    

Sie können das Gleiche für Textdateien, .properties-Dateien, XSD Schemas usw. tun.


Wahrscheinlich nicht so schnell wie mit gepufferter I / O, aber ziemlich knapp:

    String content;
    try (Scanner scanner = new Scanner(textFile).useDelimiter("\\Z")) {
        content = scanner.next();
    }

Das \Z Muster teilt dem Scanner dass das Trennzeichen EOF ist.


Cactoos geben Ihnen einen deklarativen One-Liner:

new TextOf(new File("a.txt")).asString();

Guava bietet hierfür einen One-Liner:

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

String contents = Files.toString(filePath, Charsets.UTF_8);






ascii