Czytanie zwykłego pliku tekstowego w Javie

933

Wygląda na to, że istnieją różne sposoby odczytu i zapisu danych plików w Javie.

Chcę odczytać dane ASCII z pliku. Jakie są możliwe sposoby i ich różnice?

Tim Zaklinacz
źródło
24
Nie zgadzam się również z zamknięciem jako „niekonstruktywne”. Na szczęście można to zamknąć jako duplikat . Dobre odpowiedzi np. W Jak utworzyć ciąg znaków z zawartości pliku? , Jaki jest najprostszy sposób wczytania pliku do ciągu? , Jakie są najprostsze klasy do odczytu plików?
Jonik
Bez pętli: {{{Scanner sc = nowy skaner (plik, „UTF-8”); sc.useDelimiter („$ ^”); // wyrażenie regularne nic pasujące String text = sc.next (); sc.close (); }}}
Aivar
3
jest tak interesujące, że w pythonie nie ma nic takiego jak „read ()”, aby odczytać cały plik do łańcucha
kommradHomer
2
Jest to najprostszy sposób na zrobienie tego: mkyong.com/java/…
dellasavia

Odpowiedzi:

567

ASCII to plik TEXT, więc możesz go użyć Readersdo czytania. Java obsługuje również odczyt z pliku binarnego przy użyciu InputStreams. Jeśli odczytywane pliki są ogromne, należy użyć jednego BufferedReaderz nich, FileReaderaby poprawić wydajność odczytu.

Przejrzyj ten artykuł na temat korzystania zReader

Polecam również pobranie i przeczytanie tej wspaniałej (jeszcze bezpłatnej) książki o nazwie Thinking In Java

W Javie 7 :

new String(Files.readAllBytes(...))

(dokumenty) lub

Files.readAllLines(...)

(dokumenty)

W Javie 8 :

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

(dokumenty)

Aravind Yarram
źródło
14
Wybór Czytnika naprawdę zależy od tego, do czego potrzebujesz zawartości pliku. Jeśli plik jest mały (ish) i potrzebujesz go wszystko, to szybciej (testowane przez nas: 1,8-2x) wystarczy użyć FileReadera i odczytać wszystko (lub przynajmniej wystarczająco duże fragmenty). Jeśli przetwarzasz go wiersz po wierszu, wybierz BufferedReader.
Vlad
3
Czy kolejność linii zostanie zachowana podczas korzystania z „Files.lines (..). ForEach (...)”. Rozumiem, że po tej operacji kolejność będzie dowolna.
Daniil Shevelev
38
Files.lines(…).forEach(…)nie zachowuje kolejności wierszy, ale jest wykonywany równolegle @Dash. Jeśli kolejność jest ważna, możesz użyć Files.lines(…).forEachOrdered(…), która powinna zachować kolejność (jednak nie zweryfikowała).
Palec
2
@Palec jest to interesujące, ale czy możesz cytować z dokumentów, w których jest napisane, że Files.lines(...).forEach(...)jest wykonywany równolegle? Myślałem, że dzieje się tak tylko wtedy, gdy wyraźnie ustawiasz strumień równolegle Files.lines(...).parallel().forEach(...).
Klitos Kyriacou,
3
Moja oryginalna formuła nie jest kuloodporna, @KlitosKyriacou. Chodzi o to, że forEachnie gwarantuje żadnego zamówienia, a przyczyną jest łatwa równoległość. Aby zachować porządek, użyj forEachOrdered.
Palec,
687

Moim ulubionym sposobem na odczytanie małego pliku jest użycie BufferedReader i StringBuilder. Jest to bardzo proste i na temat (choć nie jest szczególnie skuteczne, ale wystarczające w większości przypadków):

BufferedReader br = new BufferedReader(new FileReader("file.txt"));
try {
    StringBuilder sb = new StringBuilder();
    String line = br.readLine();

    while (line != null) {
        sb.append(line);
        sb.append(System.lineSeparator());
        line = br.readLine();
    }
    String everything = sb.toString();
} finally {
    br.close();
}

Niektórzy zauważyli, że po Javie 7 powinieneś używać funkcji try-with-resources (tj. Automatycznego zamykania):

try(BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    StringBuilder sb = new StringBuilder();
    String line = br.readLine();

    while (line != null) {
        sb.append(line);
        sb.append(System.lineSeparator());
        line = br.readLine();
    }
    String everything = sb.toString();
}

Kiedy czytam takie ciągi, zwykle i tak chcę trochę obsługiwać ciągi dla linii, więc idę do tej implementacji.

Chociaż jeśli chcę po prostu odczytać plik do ciągu, zawsze używam Apache Commons IO z klasą metody IOUtils.toString (). Możesz zajrzeć do źródła tutaj:

http://www.docjar.com/html/api/org/apache/commons/io/IOUtils.java.html

FileInputStream inputStream = new FileInputStream("foo.txt");
try {
    String everything = IOUtils.toString(inputStream);
} finally {
    inputStream.close();
}

A nawet prostsze w Javie 7:

try(FileInputStream inputStream = new FileInputStream("foo.txt")) {     
    String everything = IOUtils.toString(inputStream);
    // do something with everything string
}
Knubo
źródło
6
Wprowadziłem niewielką korektę, aby przestać dodawać nową linię (\ n), jeśli dojdzie do ostatniej linii. code while (linia! = null) {sb.append (linia); line = br.readLine (); // Dodaj nową linię tylko wtedy, gdy curline NIE jest ostatnim wierszem .. if (line! = Null) {sb.append ("\ n"); }}code
Ramon Fincken
2
Podobnie do Apache Common IO IOUtils # toString () to sun.misc.IOUtils # readFully (), który jest zawarty w JRE Sun / Oracle.
gb96
3
Aby uzyskać wydajność, zawsze wywoływaj sb.append ('\ n') zamiast sb.append ("\ n"), ponieważ znak jest dodawany do StringBuilder szybciej niż String
gb96
2
FileReader może zgłaszać wyjątek FileNotFoundException, a BufferedRead może zgłaszać wyjątek IOException, więc musisz je złapać.
kamaci
4
nie ma potrzeby bezpośredniego korzystania z czytników, a także nie ma potrzeby korzystania z ioutils. java7 ma wbudowane metody odczytu całego pliku / wszystkich linii: Zobacz docs.oracle.com/javase/7/docs/api/java/nio/file/… i docs.oracle.com/javase/7/docs/api / java / nio / file /…
kritzikratzi
142

Najprostszym sposobem jest użycie Scannerklasy w Javie i obiektu FileReader. Prosty przykład:

Scanner in = new Scanner(new FileReader("filename.txt"));

Scanner ma kilka metod odczytu ciągów, cyfr itp. Więcej informacji na ten temat można znaleźć na stronie dokumentacji Java.

Na przykład czytanie całej treści w String:

StringBuilder sb = new StringBuilder();
while(in.hasNext()) {
    sb.append(in.next());
}
in.close();
outString = sb.toString();

Również jeśli potrzebujesz konkretnego kodowania, możesz użyć tego zamiast FileReader:

new InputStreamReader(new FileInputStream(fileUtf8), StandardCharsets.UTF_8)
Jesus Ramos
źródło
28
while (in.hasNext ()) {System.out.println (in.next ()); }
Gene Bo,
16
@Hissain Ale o wiele łatwiejszy w użyciu niżBufferedReader
Jesus Ramos
3
Must Surround it with try Catch
Rahal Kanishka
@JesusRamos Naprawdę, dlaczego tak uważasz? Co jest w tym łatwiejszego niż while ((line = br.readLine()) != null) { sb.append(line); }?
user207421
83

Oto proste rozwiązanie:

String content;

content = new String(Files.readAllBytes(Paths.get("sample.txt")));
Nery Jr
źródło
2
@Nery Jr, elegancki i prosty
Mahmoud Saleh
1
Najlepszy i najprostszy.
Dary
57

Oto inny sposób, aby to zrobić bez użycia bibliotek zewnętrznych:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public String readFile(String filename)
{
    String content = null;
    File file = new File(filename); // For example, foo.txt
    FileReader reader = null;
    try {
        reader = new FileReader(file);
        char[] chars = new char[(int) file.length()];
        reader.read(chars);
        content = new String(chars);
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(reader != null){
            reader.close();
        }
    }
    return content;
}
Umorusany
źródło
10
lub użyj „try-with-resources” try (czytnik FileReader = nowy FileReader (plik))
Hernán Eche
3
Zauważyłem file.length (), jak dobrze to działa z plikami utf-16?
Wayne
5
Ta technika zakłada, że ​​read () wypełnia bufor; że liczba znaków jest równa liczbie bajtów; że liczba bajtów mieści się w pamięci; i że liczba bajtów mieści się w liczbie całkowitej. -1
użytkownik207421,
1
@HermesTrismegistus Podałem cztery powody, dla których jest to błąd. StefanReich ma całkowitą rację, zgadzając się ze mną.
user207421
34

Musiałem porównać różne sposoby. Skomentuję moje ustalenia, ale w skrócie, najszybszym sposobem jest użycie zwykłego starego BufferedInputStream zamiast FileInputStream. Jeśli trzeba odczytać wiele plików, trzy wątki skrócą całkowity czas wykonania do około połowy, ale dodawanie kolejnych wątków stopniowo obniży wydajność, aż do ukończenia trzykrotnie dłużej niż w przypadku dwudziestu wątków niż tylko jednego wątku.

Zakładamy, że musisz przeczytać plik i zrobić coś sensownego z jego zawartością. W przykładach tutaj jest czytanie linii z dziennika i policzenie tych, które zawierają wartości przekraczające określony próg. Zakładam więc, że jednowierszowa Java 8Files.lines(Paths.get("/path/to/file.txt")).map(line -> line.split(";")) nie jest opcją.

Testowałem na Java 1.8, Windows 7 oraz na dyskach SSD i HDD.

Napisałem sześć różnych implementacji:

rawParse : użyj BufferedInputStream na FileInputStream, a następnie wytnij linie czytające bajt po bajcie. To przewyższyło każde inne podejście z jednym wątkiem, ale może być bardzo niewygodne w przypadku plików innych niż ASCII.

lineReaderParse : Użyj BufferedReader nad FileReader, czytaj wiersz po wierszu, dziel linie, wywołując String.split (). Jest to około 20% wolniej niż rawParse.

lineReaderParseParallel : Jest taki sam jak lineReaderParse, ale używa kilku wątków. Jest to najszybsza opcja we wszystkich przypadkach.

nioFilesParse : Użyj java.nio.files.Files.lines ()

nioAsyncParse : użyj AsynchronousFileChannel z modułem obsługi zakończenia i pulą wątków.

nioMemoryMappedParse : Użyj pliku odwzorowanego w pamięci. To naprawdę zły pomysł, który zapewnia czas wykonania co najmniej trzy razy dłuższy niż jakakolwiek inna implementacja.

Są to średnie czasy odczytu 204 plików po 4 MB każdy na czterordzeniowym dysku i7 i dysku SSD. Pliki są generowane w locie, aby uniknąć buforowania dysku.

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

Znalazłem różnicę mniejszą niż się spodziewałem między uruchomieniem na dysku SSD lub dysku HDD będącym dyskiem SSD o około 15% szybszym. Może to być spowodowane tym, że pliki są generowane na niefragmentowanym dysku twardym i są odczytywane sekwencyjnie, dlatego wirujący napęd może działać prawie jak dysk SSD.

Byłem zaskoczony niską wydajnością implementacji nioAsyncParse. Albo zaimplementowałem coś w niewłaściwy sposób, albo implementację wielowątkową za pomocą NIO, a moduł obsługi zakończenia wykonuje tę samą (lub nawet gorszą) niż implementacja jednowątkowa z API java.io. Ponadto asynchroniczna analiza składniowa z CompletionHandler jest znacznie dłuższa w liniach kodu i trudna do prawidłowego wdrożenia niż prosta implementacja na starych strumieniach.

Teraz sześć implementacji, po których następuje klasa zawierająca je wszystkie oraz parametryzowalna metoda main (), która pozwala grać z liczbą plików, rozmiarem pliku i stopniem współbieżności. Pamiętaj, że rozmiar plików różni się plus minus 20%. Ma to na celu uniknięcie jakiegokolwiek efektu, ponieważ wszystkie pliki mają dokładnie taki sam rozmiar.

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

lineReaderParse

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

nioFilesParse

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

PEŁNE URUCHOMIENIE WSZYSTKICH PRZYPADKÓW

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

Serg M Ten
źródło
24

Oto trzy działające i przetestowane metody:

Za pomocą 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);
        }
    }
}

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

Za pomocą 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);
        }
    }
}

Przeczytaj cały plik bez pętli za pomocą Scannerklasy

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());
    }
}
pankaj
źródło
1
Jak podać ścieżkę, jeśli foldery są obecne w projekcie?
Kavipriya
2
Co java.nio.file.Files? Teraz możemy po prostu użyć readAllLines, readAllBytesi lines.
Claude Martin
21

Dostępne metody org.apache.commons.io.FileUtilsmogą być również bardzo przydatne, np .:

/**
 * 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)
Claude
źródło
Lub jeśli wolisz Guava (bardziej nowoczesną, aktywnie utrzymywaną bibliotekę), ma podobne narzędzia w swojej klasie Files . Proste przykłady w tej odpowiedzi .
Jonik
1
lub po prostu użyj wbudowanej metody, aby uzyskać wszystkie linie: docs.oracle.com/javase/7/docs/api/java/nio/file/…
kritzikratzi
Link do wspólnego apache wydaje się martwy.
kebs
17

Co chcesz zrobić z tekstem? Czy plik jest wystarczająco mały, aby zmieścił się w pamięci? Spróbuję znaleźć najprostszy sposób obsługi pliku dla twoich potrzeb. Biblioteka FileUtils doskonale się do tego nadaje.

for(String line: FileUtils.readLines("my-text-file"))
    System.out.println(line);
Peter Lawrey
źródło
2
jest również wbudowany w java7: docs.oracle.com/javase/7/docs/api/java/nio/file/…
kritzikratzi
@PeterLawrey prawdopodobnie oznacza org.apache.commons.io.FileUtils. Link Google może z czasem zmieniać treść, ponieważ najbardziej rozpowszechnione znaczenie zmienia się, ale odpowiada to jego zapytaniu i wygląda poprawnie.
Palec
2
Niestety, obecnie nie ma go readLines(String)i readLines(File)jest przestarzały na korzyść readLines(File, Charset). Kodowanie może być również dostarczone jako ciąg.
Palec
12

Udokumentowałem 15 sposobów odczytywania pliku w Javie, a następnie przetestowałem go pod kątem szybkości przy różnych rozmiarach plików - od 1 KB do 1 GB, a oto trzy najlepsze sposoby na zrobienie tego:

  1. java.nio.file.Files.readAllBytes()

    Testowany do pracy w Javie 7, 8 i 9.

    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    
    public class ReadFile_Files_ReadAllBytes {
      public static void main(String [] pArgs) throws IOException {
        String fileName = "c:\\temp\\sample-10KB.txt";
        File file = new File(fileName);
    
        byte [] fileBytes = Files.readAllBytes(file.toPath());
        char singleChar;
        for(byte b : fileBytes) {
          singleChar = (char) b;
          System.out.print(singleChar);
        }
      }
    }
  2. java.io.BufferedReader.readLine()

    Testowany do pracy w Javie 7, 8, 9.

    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class ReadFile_BufferedReader_ReadLine {
      public static void main(String [] args) throws IOException {
        String fileName = "c:\\temp\\sample-10KB.txt";
        FileReader fileReader = new FileReader(fileName);
    
        try (BufferedReader bufferedReader = new BufferedReader(fileReader)) {
          String line;
          while((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
          }
        }
      }
    }
  3. java.nio.file.Files.lines()

    Zostało to przetestowane pod kątem działania w Javie 8 i 9, ale nie będzie działać w Javie 7 z powodu wymagań wyrażenia lambda.

    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.util.stream.Stream;
    
    public class ReadFile_Files_Lines {
      public static void main(String[] pArgs) throws IOException {
        String fileName = "c:\\temp\\sample-10KB.txt";
        File file = new File(fileName);
    
        try (Stream linesStream = Files.lines(file.toPath())) {
          linesStream.forEach(line -> {
            System.out.println(line);
          });
        }
      }
    }
Gomisha
źródło
9

Poniżej znajduje się jedna linijka robienia tego w sposób Java 8. Zakładając, że text.txtplik znajduje się w katalogu głównym projektu Eclipse.

Files.lines(Paths.get("text.txt")).collect(Collectors.toList());
Zeus
źródło
7

Za pomocą BufferedReader:

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();
}
Neo
źródło
7

Jest to w zasadzie dokładnie to samo, co odpowiedź Jezusa Ramosa, z wyjątkiem File zamiast FileReadera i iteracji umożliwiającej przeglądanie zawartości pliku.

Scanner in = new Scanner(new File("filename.txt"));

while (in.hasNext()) { // Iterates each line in the file
    String line = in.nextLine();
    // Do something with line
}

in.close(); // Don't forget to close resource leaks

... rzuca FileNotFoundException

ThisClark
źródło
3
File vs FileReader: W przypadku FileReadera plik musi istnieć, a uprawnienia systemu operacyjnego muszą umożliwiać dostęp. Za pomocą pliku można przetestować te uprawnienia lub sprawdzić, czy plik jest katalogiem. Plik ma przydatne funkcje: isFile (), isDirectory (), listFiles (), canExecute (), canRead (), canWrite (), istnieje (), mkdir (), delete (). File.createTempFile () zapisuje w domyślnym katalogu temp systemu. Ta metoda zwróci obiekt pliku, którego można użyć do otwarcia obiektów FileOutputStream itp. Źródło
ThisClark
7

Buforowane klasy strumieni są w praktyce znacznie wydajniejsze, do tego stopnia, że ​​interfejs API NIO.2 zawiera metody, które zwracają te klasy strumieni, po części, aby zachęcić Cię do korzystania z buforowanych strumieni w aplikacji.

Oto przykład:

Path path = Paths.get("/myfolder/myfile.ext");
try (BufferedReader reader = Files.newBufferedReader(path)) {
    // Read from the stream
    String currentLine = null;
    while ((currentLine = reader.readLine()) != null)
        //do your code here
} catch (IOException e) {
    // Handle file I/O exception...
}

Możesz zastąpić ten kod

BufferedReader reader = Files.newBufferedReader(path);

z

BufferedReader br = new BufferedReader(new FileReader("/myfolder/myfile.ext"));

Polecam ten artykuł, aby poznać główne zastosowania Java NIO i IO.

Imar
źródło
6

Prawdopodobnie nie tak szybko, jak w przypadku buforowanych operacji we / wy, ale dość zwięzłe:

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

\ZWzór opowiada Scanner, że separatorem jest EOF.

David Soroko
źródło
1
Bardzo pokrewną, już istniejącą odpowiedzią jest Jezus Ramos.
Palec
1
To prawda, powinien być: if(scanner.hasNext()) content = scanner.next();
David Soroko,
1
W przypadku Androida 4.4 to mi się nie udaje. Odczytywane są tylko 1024 bajty. YMMV.
Roger Keays
3

Nie widzę tego jeszcze w innych odpowiedziach. Ale jeśli „Najlepsza” oznacza szybkość, to nowe Java I / O (NIO) może zapewnić najszybszą wydajność, ale nie zawsze najłatwiejszą do znalezienia dla kogoś, kto się uczy.

http://download.oracle.com/javase/tutorial/essential/io/file.html

jzd
źródło
Powinieneś był powiedzieć, jak to się robi i nie podawać linku do śledzenia
Orar
3

Najprostszym sposobem odczytu danych z pliku w Javie jest użycie klasy File do odczytania pliku oraz klasy Scanner do odczytania zawartości pliku.

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: Nie zapomnij zaimportować java.util. *; dla skanera do pracy.

anadir47
źródło
2

Guava zapewnia do tego jedno-liniową linię:

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

String contents = Files.toString(filePath, Charsets.UTF_8);
Rahul Mehra
źródło
2

To może nie być dokładna odpowiedź na pytanie. To po prostu inny sposób odczytywania pliku, w którym nie podajesz wprost ścieżki do pliku w kodzie Java, a zamiast tego czytasz go jako argument wiersza poleceń.

Za pomocą następującego kodu

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

po prostu uruchom i uruchom z:

java InputReader < input.txt

Spowoduje to odczytanie zawartości input.txti wydrukowanie jej na konsoli.

Możesz także System.out.println()napisać do określonego pliku za pomocą wiersza poleceń w następujący sposób:

java InputReader < input.txt > output.txt

Odczytuje to input.txti pisze output.txt.

Sztolnia A. Pillai
źródło
2

Możesz użyć readAllLines i joinmetody, aby uzyskać całą zawartość pliku w jednym wierszu:

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

Domyślnie wykorzystuje kodowanie UTF-8, które poprawnie odczytuje dane ASCII.

Możesz także użyć readAllBytes:

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

Myślę, że readAllBytes jest szybszy i bardziej precyzyjny, ponieważ nie zastępuje nowej linii, \na także może być nowa linia \r\n. To zależy od twoich potrzeb.

Mostafa Vatanpour
źródło
1

W przypadku aplikacji internetowych Maven opartych na JSF wystarczy użyć ClassLoader i Resourcesfolderu, aby odczytać dowolny plik:

  1. Umieść dowolny plik, który chcesz przeczytać, w folderze Zasoby.
  2. Umieść zależność IO Apache Commons w swojej POM:

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.3.2</version>
    </dependency>
  3. Użyj poniższego kodu, aby go przeczytać (np. Poniżej czyta plik .json):

    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;

To samo możesz zrobić dla plików tekstowych, plików .properties, schematów XSD itp.

Analiza rozmyta
źródło
Nie możesz tego użyć w „dowolnym pliku”. Możesz go używać tylko do zasobów, które zostały spakowane do pliku JAR lub WAR.
user207421
0

Użyj pocałunku Java, jeśli chodzi o prostotę struktury:

import static kiss.API.*;

class App {
  void run() {
    String line;
    try (Close in = inOpen("file.dat")) {
      while ((line = readLine()) != null) {
        println(line);
      }
    }
  }
}
Warren MacEvoy
źródło
0
import java.util.stream.Stream;
import java.nio.file.*;
import java.io.*;

class ReadFile {

 public static void main(String[] args) {

    String filename = "Test.txt";

    try(Stream<String> stream = Files.lines(Paths.get(filename))) {

          stream.forEach(System.out:: println);

    } catch (IOException e) {

        e.printStackTrace();
    }

 }

 }

Wystarczy użyć strumienia Java 8.

Archit Bhadauria
źródło
0
try {
  File f = new File("filename.txt");
  Scanner r = new Scanner(f);  
  while (r.hasNextLine()) {
    String data = r.nextLine();
    JOptionPane.showMessageDialog(data);
  }
  r.close();
} catch (FileNotFoundException ex) {
  JOptionPane.showMessageDialog("Error occurred");
  ex.printStackTrace();
}
Fridjato Part Fridjat
źródło
0

Najbardziej intuicyjna metoda została wprowadzona w Javie 11 Files.readString

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String args[]) throws IOException {
        String content = Files.readString(Paths.get("D:\\sandbox\\mvn\\my-app\\my-app.iml"));
        System.out.print(content);
    }
}

PHP ma ten luksus sprzed kilkudziesięciu lat! ☺

PHPst
źródło
-3

Ten kod, który zaprogramowałem, jest znacznie szybszy dla bardzo dużych plików:

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;
}
Juan Carlos Kuri Pinto
źródło
10
O wiele szybciej, wątpię, jeśli użyjesz prostej konkatenacji łańcucha zamiast StringBuilder ...
PhiLho
6
Myślę, że głównym wzrostem prędkości jest odczyt w blokach 1 MB (1024 * 1024). Jednak możesz zrobić to samo, przekazując 1024 * 1024 jako drugi argument do konstruktora BufferedReader.
gb96
3
nie sądzę, żeby to zostało w ogóle przetestowane. użycie +=w ten sposób zapewnia kwadratową (!) złożoność zadania, które powinno być złożonością liniową. zacznie to indeksować pliki powyżej kilku MB. aby obejść ten problem, powinieneś trzymać bloki tekstowe na liście <ciąg> lub użyć wyżej wspomnianego konstruktora łańcuchów.
kritzikratzi
5
Znacznie szybciej niż co? Z pewnością nie jest szybsze niż dołączanie do StringBuffer. -1
użytkownik207421,
1
@ gb96 Tak samo myślałem o rozmiarach buforów, ale szczegółowy eksperyment w tym pytaniu dał zaskakujące wyniki w podobnym kontekście: bufor 16 KB był konsekwentnie i zauważalnie szybszy.
chiastic-security
-3
String fileName = 'yourFileFullNameWithPath';
File file = new File(fileName); // Creates a new file object for your file
FileReader fr = new FileReader(file);// Creates a Reader that you can use to read the contents of a file read your file
BufferedReader br = new BufferedReader(fr); //Reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines.

Powyższy zestaw linii można zapisać w 1 pojedynczej linii jako:

BufferedReader br = new BufferedReader(new FileReader("file.txt")); // Optional

Dodawanie do konstruktora łańcuchów (jeśli plik jest ogromny, zaleca się użycie konstruktora łańcuchów, w przeciwnym razie należy użyć zwykłego obiektu String)

try {
        StringBuilder sb = new StringBuilder();
        String line = br.readLine();

        while (line != null) {
        sb.append(line);
        sb.append(System.lineSeparator());
        line = br.readLine();
        }
        String everything = sb.toString();
        } finally {
        br.close();
    }
Vaibhav Rai
źródło