Đọc một tệp văn bản thuần trong Java


933

Dường như có nhiều cách khác nhau để đọc và ghi dữ liệu của các tệp trong Java.

Tôi muốn đọc dữ liệu ASCII từ một tệp. Những cách có thể và sự khác biệt của họ là gì?


24
Tôi cũng không đồng ý với việc đóng cửa là "không mang tính xây dựng". May mắn thay, điều này cũng có thể được đóng lại như là bản sao . Câu trả lời hay, ví dụ như trong Cách tạo Chuỗi từ nội dung của tệp? , Cách đơn giản nhất để đọc tệp vào Chuỗi là gì? , Các lớp đơn giản nhất để đọc các tập tin là gì?
Jonik

Không có vòng lặp: {{{Scanner sc = new Scanner (tệp, "UTF-8"); sc.useD006iter ("$ ^"); // regex không khớp với chuỗi String text = sc.next (); sc.close (); }}}
Aivar

3
Thật thú vị khi không có gì giống như "read ()" trong python, để đọc toàn bộ tệp thành một chuỗi
kommradHomer

2
Đây là cách đơn giản nhất để làm điều này: mkyong.com/java/ Kẻ
dellasavia 17/03/2015

Câu trả lời:


567

ASCII là một tệp văn bản, do đó bạn sẽ sử dụng Readersđể đọc. Java cũng hỗ trợ đọc từ tệp nhị phân bằng cách sử dụng InputStreams. Nếu các tệp đang đọc là rất lớn thì bạn sẽ muốn sử dụng một BufferedReaderđầu trang FileReaderđể cải thiện hiệu suất đọc.

Xem qua bài viết này về cách sử dụngReader

Tôi cũng khuyên bạn nên tải xuống và đọc cuốn sách tuyệt vời (nhưng miễn phí) này có tên Thinking In Java

Trong Java 7 :

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

(tài liệu) hoặc

Files.readAllLines(...)

(tài liệu)

Trong Java 8 :

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

(tài liệu)


14
Chọn một Reader thực sự phụ thuộc vào những gì bạn cần nội dung của tệp. Nếu tệp nhỏ (ish) và bạn cần tất cả, nó sẽ nhanh hơn (được điểm chuẩn bởi chúng tôi: 1,8-2x) để chỉ sử dụng FileReader và đọc mọi thứ (hoặc ít nhất là đủ khối lớn). Nếu bạn đang xử lý từng dòng một thì hãy tìm BufferedReader.
Vlad

3
Thứ tự dòng sẽ được giữ nguyên khi sử dụng "Files.lines (..). ForEach (...)". Hiểu biết của tôi là thứ tự sẽ tùy ý sau hoạt động này.
Daniil Shevelev

39
Files.lines(…).forEach(…)không bảo toàn thứ tự các dòng nhưng được thực thi song song, @Dash. Nếu đơn hàng là quan trọng, bạn có thể sử dụng Files.lines(…).forEachOrdered(…), việc này sẽ giữ nguyên đơn hàng (mặc dù không xác minh).
Palec

2
@Palec điều này thật thú vị, nhưng bạn có thể trích dẫn từ các tài liệu mà nó nói Files.lines(...).forEach(...)được thực thi song song không? Tôi nghĩ rằng đây chỉ là trường hợp khi bạn rõ ràng tạo luồng song song bằng cách sử dụng Files.lines(...).parallel().forEach(...).
Klitos Kyriacou

3
Công thức ban đầu của tôi không chống đạn, @KlitosKyriacou. Vấn đề là forEachkhông đảm bảo bất kỳ trật tự nào và lý do là song song dễ dàng. Nếu trật tự được bảo tồn, sử dụng forEachOrdered.
Palec

687

Cách ưa thích của tôi để đọc một tệp nhỏ là sử dụng BufferedReader và StringBuilder. Nó rất đơn giản và đến mức (mặc dù không đặc biệt hiệu quả, nhưng đủ tốt cho hầu hết các trường hợp):

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

Một số người đã chỉ ra rằng sau Java 7, bạn nên sử dụng các tính năng try-with-resource (nghĩa là tự động đóng):

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

Khi tôi đọc các chuỗi như thế này, tôi thường muốn thực hiện một số xử lý chuỗi trên mỗi dòng, vì vậy sau đó tôi sẽ thực hiện việc này.

Mặc dù nếu tôi thực sự chỉ muốn đọc một tệp thành Chuỗi, tôi luôn sử dụng Apache Commons IO với phương thức lớp IOUtils.toString (). Bạn có thể xem nguồn tại đây:

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

Và thậm chí đơn giản hơn với Java 7:

try(FileInputStream inputStream = new FileInputStream("foo.txt")) {     
    String everything = IOUtils.toString(inputStream);
    // do something with everything string
}

6
Tôi đã thực hiện một điều chỉnh nhỏ để dừng thêm dòng mới (\ n) nếu đạt đến dòng cuối cùng. code while (dòng! = null) {sb.append (dòng); dòng = br.readLine (); // Chỉ thêm dòng mới khi đường cong KHÔNG phải là dòng cuối cùng .. if (line! = Null) {sb.append ("\ n"); }}code
Ramon Fincken

2
Tương tự như Apache IOUtils # toString () của Apache là sun.misc.IOUtils # readFully (), được bao gồm trong Sun / Oracle JREs.
gb96

3
Để có hiệu suất, hãy luôn gọi sb.append ('\ n') để ưu tiên cho sb.append ("\ n") vì một char được gắn vào StringBuilder nhanh hơn String
gb96

2
FileReader có thể ném FileNotFoundException và BufferedRead có thể ném IOException để bạn phải bắt chúng.
kamaci

4
không cần sử dụng độc giả trực tiếp và cũng không cần ioutils. java7 đã xây dựng các phương thức để đọc toàn bộ tệp / tất cả các dòng: Xem docs.oracle.com/javase/7/docs/api/java/nio/file/iêudocs.oracle.com/javase/7/docs/api / java / nio / file /
SSH

142

Cách dễ nhất là sử dụng Scannerlớp trong Java và đối tượng FileReader. Ví dụ đơn giản:

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

Scanner có một số phương pháp để đọc theo chuỗi, số, v.v ... Bạn có thể tìm thêm thông tin về điều này trên trang tài liệu Java.

Ví dụ: đọc toàn bộ nội dung thành một String:

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

Ngoài ra nếu bạn cần một mã hóa cụ thể, bạn có thể sử dụng mã này thay vì FileReader:

new InputStreamReader(new FileInputStream(fileUtf8), StandardCharsets.UTF_8)

28
while (in.hasNext ()) {System.out.println (in.next ()); }
Gene Bo

16
@Hissain Nhưng dễ sử dụng hơn nhiều so vớiBufferedReader
Jesus Ramos

3
Phải bao quanh nó bằng thử Catch
Rahal K Biếnka

@JesusRamos Không hẳn vậy, tại sao bạn lại nghĩ như vậy? Điều gì dễ dàng hơn về điều này hơn while ((line = br.readLine()) != null) { sb.append(line); }?
Hầu tước Lorne

83

Đây là một giải pháp đơn giản:

String content;

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

2
@Nery Jr, thanh lịch và đơn giản
Mahmoud Saleh

1
Tốt nhất và đơn giản nhất.
Dary

57

Đây là một cách khác để làm điều đó mà không cần sử dụng các thư viện bên ngoài:

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

10
hoặc sử dụng thử "thử với tài nguyên" (Trình đọc tệp = trình đọc tệp mới (tệp))
Hernán Eche

3
Tôi nhận thấy file.length (), cái này hoạt động tốt như thế nào với các tập tin utf-16?
Wayne

5
Kỹ thuật này giả định rằng read () lấp đầy bộ đệm; số lượng ký tự bằng số byte; số lượng byte phù hợp với bộ nhớ; và số lượng byte phù hợp với một số nguyên. -1
Hầu tước Lorne

1
@HermesTrismegistus Tôi đã cung cấp bốn lý do tại sao nó sai. StefanReich hoàn toàn chính xác để đồng ý với tôi.
Hầu tước Lorne

34

Tôi đã phải điểm chuẩn các cách khác nhau. Tôi sẽ nhận xét về những phát hiện của mình, nhưng nói ngắn gọn, cách nhanh nhất là sử dụng BufferedInputStream cũ đơn giản trên FileInputStream. Nếu nhiều tệp phải được đọc thì ba luồng sẽ giảm tổng thời gian thực hiện xuống khoảng một nửa, nhưng việc thêm nhiều luồng sẽ làm giảm dần hiệu suất cho đến khi hoàn thành thời gian dài hơn ba lần với hai luồng so với chỉ một luồng.

Giả định là bạn phải đọc một tệp và làm một cái gì đó có ý nghĩa với nội dung của nó. Trong các ví dụ ở đây là đọc các dòng từ một bản ghi và đếm những cái có chứa các giá trị vượt quá một ngưỡng nhất định. Vì vậy, tôi giả định rằng Java 8 một lớp Files.lines(Paths.get("/path/to/file.txt")).map(line -> line.split(";"))không phải là một tùy chọn.

Tôi đã thử nghiệm trên Java 1.8, Windows 7 và cả ổ SSD và ổ cứng.

Tôi đã viết sáu triển khai khác nhau:

rawPude : Sử dụng BufferedInputStream trên FileInputStream và sau đó cắt các dòng đọc từng byte. Điều này vượt trội hơn bất kỳ cách tiếp cận đơn luồng nào khác, nhưng nó có thể rất bất tiện cho các tệp không phải ASCII.

lineReaderPude : Sử dụng BufferedReader trên FileReader, đọc từng dòng, chia dòng bằng cách gọi String.split (). Đây là chậm hơn khoảng 20% ​​mà rawPude.

lineReaderPudeParallel : Điều này giống như lineReaderPude, nhưng nó sử dụng một số chủ đề. Đây là tùy chọn nhanh nhất tổng thể trong mọi trường hợp.

nioFilesPude : Sử dụng java.nio.files.Files.lines ()

nioAsyncPude : Sử dụng với trình xử lý hoàn thành và nhóm luồng.

nioMemoryMappedPude : Sử dụng tệp ánh xạ bộ nhớ. Đây thực sự là một ý tưởng tồi mang lại thời gian thực hiện lâu hơn ít nhất ba lần so với bất kỳ triển khai nào khác.

Đây là thời gian trung bình để đọc 204 tệp 4 MB trên mỗi ổ i7 và SSD lõi tứ. Các tập tin được tạo ra một cách nhanh chóng để tránh bộ nhớ đệm đĩa.

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

Tôi tìm thấy một sự khác biệt nhỏ hơn tôi mong đợi giữa việc chạy trên ổ SSD hoặc ổ đĩa cứng là SSD nhanh hơn khoảng 15%. Điều này có thể là do các tệp được tạo trên ổ cứng không phân mảnh và chúng được đọc tuần tự, do đó ổ đĩa quay có thể hoạt động gần như một ổ SSD.

Tôi đã rất ngạc nhiên bởi hiệu suất thấp của việc triển khai nioAsyncPude. Hoặc tôi đã triển khai một cái gì đó sai cách hoặc triển khai đa luồng bằng NIO và trình xử lý hoàn thành thực hiện tương tự (hoặc thậm chí tệ hơn) so với triển khai một luồng với API java.io. Ngoài ra, phân tích cú pháp không đồng bộ với CompleteionHandler dài hơn nhiều trong các dòng mã và khó thực hiện chính xác hơn so với triển khai thẳng trên các luồng cũ.

Bây giờ sáu triển khai theo sau là một lớp chứa tất cả chúng cộng với một phương thức main () có thể tham số cho phép chơi với số lượng tệp, kích thước tệp và mức độ tương tranh. Lưu ý rằng kích thước của các tệp khác nhau cộng trừ 20%. Điều này là để tránh bất kỳ ảnh hưởng nào do tất cả các tệp có cùng kích thước.

rawPude

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

lineReaderPude

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

lineReaderPudeParallel

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

nioFilesPude

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

nioAsyncPude

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

THỰC HIỆN RUNNABLE HOÀN TOÀN TẤT CẢ CÁC TRƯỜNG HỢP

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


24

Dưới đây là ba phương pháp làm việc và thử nghiệm:

Sử dụng 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);
        }
    }
}

Sử dụng 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());
        }
    }
}

Sử dụng 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);
        }
    }
}

Đọc toàn bộ tệp mà không có vòng lặp sử dụng Scannerlớp

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

1
Làm thế nào để đưa ra đường dẫn nếu các thư mục có mặt trong dự án?
Kavipriya

2
Thế còn java.nio.file.Files? Chúng tôi bây giờ có thể chỉ cần sử dụng readAllLines, readAllByteslines.
Claude Martin

21

Các phương thức bên trong org.apache.commons.io.FileUtilscũng có thể rất tiện dụng, ví dụ:

/**
 * 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)

Hoặc nếu bạn thích Guava (một thư viện hiện đại hơn, được bảo trì tích cực), nó có các tiện ích tương tự trong lớp Tệp . Ví dụ đơn giản trong câu trả lời này .
Jonik

1
hoặc bạn chỉ đơn giản sử dụng phương thức dựng sẵn để nhận tất cả các dòng: docs.oracle.com/javase/7/docs/api/java/nio/file/ trộm
kritzikratzi

Liên kết trên apache commons dường như đã chết.
kebs

17

Bạn muốn làm gì với văn bản? Là tập tin đủ nhỏ để phù hợp với bộ nhớ? Tôi sẽ cố gắng tìm cách đơn giản nhất để xử lý tệp cho nhu cầu của bạn. Thư viện FileUtils rất xử lý việc này.

for(String line: FileUtils.readLines("my-text-file"))
    System.out.println(line);

2
nó cũng được tích hợp vào java7: docs.oracle.com/javase/7/docs/api/java/nio/file/ trộm
kritzikratzi

@PeterLawrey có lẽ có nghĩa org.apache.commons.io.FileUtils. Liên kết Google có thể thay đổi nội dung theo thời gian, vì ý nghĩa phổ biến nhất sẽ thay đổi, nhưng điều này phù hợp với truy vấn của anh ấy và có vẻ đúng.
Palec

2
Thật không may, ngày nay không có readLines(String)readLines(File)không được ủng hộ readLines(File, Charset). Mã hóa cũng có thể được cung cấp dưới dạng một chuỗi.
Palec


12

Tôi đã ghi lại 15 cách để đọc một tệp trong Java và sau đó kiểm tra tốc độ của chúng với các kích cỡ tệp khác nhau - từ 1 KB đến 1 GB và đây là ba cách hàng đầu để làm điều này:

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

    Đã thử nghiệm để làm việc trong Java 7, 8 và 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()

    Đã thử nghiệm để làm việc trong Java 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()

    Điều này đã được thử nghiệm để hoạt động trong Java 8 và 9 nhưng sẽ không hoạt động trong Java 7 vì yêu cầu biểu thức 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);
          });
        }
      }
    }

9

Dưới đây là một hướng dẫn thực hiện theo cách Java 8. Giả địnhtext.txt tệp nằm trong thư mục gốc của thư mục dự án của Eclipse.

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

7

Sử dụng 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();
}

7

Điều này về cơ bản giống như câu trả lời của Jesus Ramos, ngoại trừ với Tệp thay vì FileReader cộng với phép lặp để chuyển qua nội dung của tệp.

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

... ném FileNotFoundException


3
File vs FileReader: Với FileReader, tệp phải tồn tại và quyền của hệ điều hành phải cho phép truy cập. Với một tệp, có thể kiểm tra các quyền đó hoặc kiểm tra xem tệp có phải là thư mục không. Tệp có các hàm hữu ích: isFile (), isDirectory (), listFiles (), canExecute (), canRead (), canWrite (), tồn tại (), mkdir (), xóa (). File.createTempFile () ghi vào thư mục temp mặc định của hệ thống. Phương thức này sẽ trả về một đối tượng tệp có thể được sử dụng để mở các đối tượng FileOutputStream, v.v. nguồn
ThisClark

7

Các lớp luồng được đệm có hiệu suất cao hơn nhiều trong thực tế, đến nỗi API NIO.2 bao gồm các phương thức trả về các lớp luồng này một phần, để khuyến khích bạn luôn sử dụng các luồng được đệm trong ứng dụng của mình.

Đây là một ví dụ:

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

Bạn có thể thay thế mã này

BufferedReader reader = Files.newBufferedReader(path);

với

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

Tôi khuyên bạn nên này bài viết để học hỏi những ứng dụng chính của Java NIO và IO.


6

Có lẽ không nhanh như với I / O được đệm, nhưng khá ngắn gọn:

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

Các \Zmô hình kể Scannerrằng delimiter là EOF.


1
Một câu trả lời rất liên quan, đã có sẵn là của Jesus Ramos.
Palec

1
Đúng, nên là: if(scanner.hasNext()) content = scanner.next();
David Soroko

1
Điều này không thành công với tôi trên Android 4.4. Chỉ có 1024 byte được đọc. YMMV.
Roger Keays

3

Tôi không thấy nó được đề cập đến trong các câu trả lời khác cho đến nay. Nhưng nếu "Tốt nhất" có nghĩa là tốc độ, thì I / O Java (NIO) mới có thể cung cấp hiệu suất nhanh nhất, nhưng không phải lúc nào cũng dễ dàng nhất để tìm ra ai đó đang học.

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


Bạn nên nói rõ cách thức thực hiện và không đưa ra liên kết để theo dõi
Orar

3

Cách đơn giản nhất để đọc dữ liệu từ một tệp trong Java là sử dụng lớp Tệp để đọc tệp và lớp Máy quét để đọc nội dung của tệp.

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: Đừng quên nhập java.util. *; cho Máy quét hoạt động.


2

Quả ổi cung cấp một lớp lót cho việc này:

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

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

2

Đây có thể không phải là câu trả lời chính xác cho câu hỏi. Đó chỉ là một cách khác để đọc một tệp mà bạn không chỉ định rõ ràng đường dẫn đến tệp của mình trong mã Java và thay vào đó, bạn đọc nó dưới dạng đối số dòng lệnh.

Với đoạn mã sau,

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

chỉ cần tiếp tục và chạy nó với:

java InputReader < input.txt

Điều này sẽ đọc nội dung của input.txtvà in nó ra bàn điều khiển của bạn.

Bạn cũng có thể thực hiện System.out.println()ghi vào một tệp cụ thể thông qua dòng lệnh như sau:

java InputReader < input.txt > output.txt

Điều này sẽ đọc từ input.txtvà viết cho output.txt.


2

Bạn có thể sử dụng readAllLines và joinphương thức để lấy toàn bộ nội dung tệp trong một dòng:

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

Nó sử dụng mã hóa UTF-8 theo mặc định, đọc dữ liệu ASCII chính xác.

Ngoài ra, bạn có thể sử dụng readAllBytes:

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

Tôi nghĩ readAllBytes nhanh hơn và chính xác hơn, bởi vì nó không thay thế dòng mới bằng \nvà dòng mới cũng có thể \r\n. Nó phụ thuộc vào nhu cầu của bạn mà phù hợp.


1

Đối với các ứng dụng web Maven dựa trên JSF, chỉ cần sử dụng ClassLoader và Resourcesthư mục để đọc trong bất kỳ tệp nào bạn muốn:

  1. Đặt bất kỳ tệp nào bạn muốn đọc trong thư mục Tài nguyên.
  2. Đặt phần phụ thuộc IO Commons IO vào POM của bạn:

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.3.2</version>
    </dependency>
  3. Sử dụng mã bên dưới để đọc nó (ví dụ bên dưới đang đọc trong tệp .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;

Bạn có thể làm tương tự cho các tệp văn bản, tệp .properations, lược đồ XSD , v.v.


Bạn không thể sử dụng điều này trên 'bất kỳ tập tin nào bạn muốn'. Bạn chỉ có thể sử dụng nó cho các tài nguyên đã được đóng gói vào tệp JAR hoặc WAR.
Hầu tước Lorne

1

Cactoos cung cấp cho bạn một lớp lót khai báo:

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

0

Sử dụng nụ hôn Java nếu đây là về sự đơn giản của cấu trúc:

import static kiss.API.*;

class App {
  void run() {
    String line;
    try (Close in = inOpen("file.dat")) {
      while ((line = readLine()) != null) {
        println(line);
      }
    }
  }
}

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

 }

 }

Chỉ cần sử dụng java 8 Stream.


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

0

Phương thức trực quan nhất được giới thiệu trong Java 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 có sự xa xỉ này từ nhiều thập kỷ trước! ☺


-3

Mã này tôi đã lập trình nhanh hơn nhiều cho các tệp rất lớn:

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

10
Nhanh hơn nhiều, tôi nghi ngờ điều đó, nếu bạn sử dụng nối chuỗi đơn giản thay vì StringBuilder ...
PhiLho

6
Tôi nghĩ rằng tốc độ tăng chính là từ việc đọc trong các khối 1MB (1024 * 1024). Tuy nhiên, bạn có thể làm tương tự chỉ bằng cách chuyển 1024 * 1024 dưới dạng đối số thứ hai cho hàm tạo BufferedReader.
gb96

3
Tôi không tin rằng điều này đã được thử nghiệm. sử dụng +=theo cách này cung cấp cho bạn độ phức tạp bậc hai (!) cho một nhiệm vụ phải là độ phức tạp tuyến tính. điều này sẽ bắt đầu thu thập dữ liệu cho các tập tin trong một vài mb. để giải quyết vấn đề này, bạn nên giữ các chuỗi văn bản trong danh sách <chuỗi> hoặc sử dụng trình tạo chuỗi đã nói ở trên.
kritzikratzi

5
Nhanh hơn nhiều so với những gì? Nó chắc chắn không nhanh hơn việc gắn vào StringBuffer. -1
Hầu tước Lorne

1
@ gb96 Tôi cũng nghĩ giống như vậy về kích thước bộ đệm, nhưng thử nghiệm chi tiết trong câu hỏi này đã cho kết quả đáng ngạc nhiên trong bối cảnh tương tự: bộ đệm 16KB luôn ổn định và nhanh hơn đáng kể.
chiastic-an ninh

-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.

Tập hợp dòng trên có thể được viết thành 1 dòng đơn như:

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

Thêm vào trình tạo chuỗi (Nếu tệp của bạn rất lớn, bạn nên sử dụng trình tạo chuỗi khác, sử dụng đối tượng Chuỗi bình thường)

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();
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.