40

目前我正在使用扫描仪/文件阅读器并使用 while hasextline。我认为这种方法效率不高。有没有其他方法可以读取具有类似功能的文件?

public void Read(String file) {
        Scanner sc = null;


        try {
            sc = new Scanner(new FileReader(file));

            while (sc.hasNextLine()) {
                String text = sc.nextLine();
                String[] file_Array = text.split(" ", 3);

                if (file_Array[0].equalsIgnoreCase("case")) {
                    //do something
                } else if (file_Array[0].equalsIgnoreCase("object")) {
                    //do something
                } else if (file_Array[0].equalsIgnoreCase("classes")) {
                    //do something
                } else if (file_Array[0].equalsIgnoreCase("function")) {
                    //do something
                } 
                else if (file_Array[0].equalsIgnoreCase("ignore")) {
                    //do something
                }
                else if (file_Array[0].equalsIgnoreCase("display")) {
                    //do something
                }
            }

        } catch (FileNotFoundException e) {
            System.out.println("Input file " + file + " not found");
            System.exit(1);
        } finally {
            sc.close();
        }
    }
4

8 回答 8

43

你会发现它BufferedReader.readLine()和你需要的一样快:你可以用它每秒读取数百万行。您的字符串拆分和处理更有可能导致您遇到的任何性能问题。

于 2013-10-21T04:43:42.727 回答
21

我做了一个比较不同方法的要点:

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.function.Function;

public class Main {

    public static void main(String[] args) {

        String path = "resources/testfile.txt";
        measureTime("BufferedReader.readLine() into LinkedList", Main::bufferReaderToLinkedList, path);
        measureTime("BufferedReader.readLine() into ArrayList", Main::bufferReaderToArrayList, path);
        measureTime("Files.readAllLines()", Main::readAllLines, path);
        measureTime("Scanner.nextLine() into ArrayList", Main::scannerArrayList, path);
        measureTime("Scanner.nextLine() into LinkedList", Main::scannerLinkedList, path);
        measureTime("RandomAccessFile.readLine() into ArrayList", Main::randomAccessFileArrayList, path);
        measureTime("RandomAccessFile.readLine() into LinkedList", Main::randomAccessFileLinkedList, path);
        System.out.println("-----------------------------------------------------------");
    }

    private static void measureTime(String name, Function<String, List<String>> fn, String path) {
        System.out.println("-----------------------------------------------------------");
        System.out.println("run: " + name);
        long startTime = System.nanoTime();
        List<String> l = fn.apply(path);
        long estimatedTime = System.nanoTime() - startTime;
        System.out.println("lines: " + l.size());
        System.out.println("estimatedTime: " + estimatedTime / 1_000_000_000.);
    }

    private static List<String> bufferReaderToLinkedList(String path) {
        return bufferReaderToList(path, new LinkedList<>());
    }

    private static List<String> bufferReaderToArrayList(String path) {
        return bufferReaderToList(path, new ArrayList<>());
    }

    private static List<String> bufferReaderToList(String path, List<String> list) {
        try {
            final BufferedReader in = new BufferedReader(
                new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null) {
                list.add(line);
            }
            in.close();
        } catch (final IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    private static List<String> readAllLines(String path) {
        try {
            return Files.readAllLines(Paths.get(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static List<String> randomAccessFileLinkedList(String path) {
        return randomAccessFile(path, new LinkedList<>());
    }

    private static List<String> randomAccessFileArrayList(String path) {
        return randomAccessFile(path, new ArrayList<>());
    }

    private static List<String> randomAccessFile(String path, List<String> list) {
        try {
            RandomAccessFile file = new RandomAccessFile(path, "r");
            String str;
            while ((str = file.readLine()) != null) {
                list.add(str);
            }
            file.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    private static List<String> scannerLinkedList(String path) {
        return scanner(path, new LinkedList<>());
    }

    private static List<String> scannerArrayList(String path) {
        return scanner(path, new ArrayList<>());
    }

    private static List<String> scanner(String path, List<String> list) {
        try {
            Scanner scanner = new Scanner(new File(path));
            while (scanner.hasNextLine()) {
                list.add(scanner.nextLine());
            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return list;
    }


}

运行:BufferedReader.readLine() 进入 LinkedList,行数:1000000,估计时间:0.105118655

运行:BufferedReader.readLine() 进入 ArrayList,行数:1000000,估计时间:0.072696934

运行:Files.readAllLines(),行:1000000,估计时间:0.087753316

运行:Scanner.nextLine() 进入 ArrayList,行数:1000000,估计时间:0.743121734

运行:Scanner.nextLine() 进入 LinkedList,行数:1000000,估计时间:0.867049885

运行:RandomAccessFile.readLine() 进入 ArrayList,行数:1000000,估计时间:11.413323046

运行:RandomAccessFile.readLine() 进入 LinkedList,行数:1000000,估计时间:11.423862897

BufferedReader是最快的,Files.readAllLines()也是可以接受的,Scanner由于正则表达式很慢RandomAccessFile,不能接受

于 2018-11-04T19:42:02.723 回答
8

Scanner不能那么快BufferedReader,因为它使用正则表达式来读取文本文件,这使得它比BufferedReader. 通过使用BufferedReader,您可以从文本文件中读取块。

BufferedReader bf = new BufferedReader(new FileReader("FileName"));

您接下来可以使用readLine()从 bf 中读取。

希望它符合您的目的。

于 2015-06-08T14:16:09.760 回答
4

您可以使用JAVA NIO 的FileChannelByteBuffer。ByteBuffer 大小是我观察到的更快读取数据的最关键部分。下面的代码将读取文件的内容。

static public void main( String args[] ) throws Exception 
    {
        FileInputStream fileInputStream = new FileInputStream(
                                        new File("sample4.txt"));
        FileChannel fileChannel = fileInputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        fileChannel.read(byteBuffer);
        byteBuffer.flip();
        int limit = byteBuffer.limit();
        while(limit>0)
        {
            System.out.print((char)byteBuffer.get());
            limit--;
        }

        fileChannel.close();
    }

您可以在此处检查新行的 '\n'。谢谢。


即使您可以分散和获取方式来更快地读取文件,即

fileChannel.get(buffers);

在哪里

      ByteBuffer b1 = ByteBuffer.allocate(B1);
      ByteBuffer b2 = ByteBuffer.allocate(B2);
      ByteBuffer b3 = ByteBuffer.allocate(B3);

      ByteBuffer[] buffers = {b1, b2, b3};

这使用户进程免于进行多次系统调用(这可能很昂贵),并允许内核优化数据处理,因为它具有有关总传输的信息,如果多个 CPU 可用,甚至可以填充和耗尽多个缓冲区同时。

从这本书

于 2013-10-21T04:54:58.863 回答
3

使用BufferedReader进行高性能文件访问。但 8192 字节的默认缓冲区大小通常太小。对于大文件,您可以将缓冲区大小增加几个数量级,以提高文件读取性能。例如:

BufferedReader br = new BufferedReader("file.dat", 1000 * 8192);
while ((thisLine = br.readLine()) != null) {
    System.out.println(thisLine);
}  
于 2017-06-22T14:46:27.143 回答
0

您必须调查程序的哪个部分需要时间。

根据 EJP 的回答,您应该使用 BufferedReader。

如果真的字符串处理需要时间,那么你应该考虑使用线程,一个线程将从文件和队列行中读取。其他字符串处理器线程将使行出列并处理它们。您将需要调查要使用多少线程,您应该在应用程序中使用的线程数必须与 CPU 中的内核数相关,这样才能使用完整的 CPU。

于 2013-10-21T05:07:08.783 回答
0

只是更新这个线程,现在我们有 java 8 来完成这项工作:

List<String> lines = Files.readAllLines(Paths.get(file_path);
于 2019-02-13T15:16:42.230 回答
-2

如果您想一起阅读所有行,那么您应该查看 java 7 的 Files API。它使用起来非常简单。

但更好的方法是批量处理这个文件。有一个从文件中读取大块行的读取器和一个执行所需处理或保存数据的写入器。拥有批处理将确保即使将来生产线增加到十亿,它也能正常工作。您也可以拥有一个使用多线程的批处理来提高批处理的整体性能。我建议你看看春季批次。

于 2013-10-21T05:11:58.290 回答