简体   繁体   English

非阻塞 (NIO) 读取行

[英]Non-blocking (NIO) reading of lines

I need to read a file line by line using java.nio , but nio doesn't have a method like readline() to read one, complete line at a time.我需要使用java.nio逐行读取文件,但是nio没有像readline()这样的方法来一次读取一个完整的行。 What solutions are there?有哪些解决方案?

I understand you guys don't like limitations, but in case the one asking don't have access to IO package or not allowed to import it for some reason the top answer is not helpful...我知道你们不喜欢限制,但是如果询问的人无权访问 IO 包或由于某种原因不允许导入它,那么最佳答案没有帮助...

Two ways to do it completely IO free:两种完全无IO的方法:

  1. java.nio.file.Files.lines , Returns a stream of lines, which is part of .util package and not .io package like bufferedReader. java.nio.file.Files.lines ,返回一个行流,它是 .util 包的一部分,而不是像 bufferedReader 这样的 .io 包。

  2. java.nio.file.Files.readAllLines , Returns a collection of lines which is iterable. java.nio.file.Files.readAllLines ,返回可迭代的行集合。 Proceed to use an iterator or for each to extract a single line.继续使用iteratorfor each提取一行。

cheers干杯

Why?为什么? NIO doesn't support reading lines. NIO 不支持读行。 You can read millions of lines a second with BufferedReader.readLine().您可以使用BufferedReader.readLine().每秒读取数百万行BufferedReader.readLine(). I suggest that is sufficient.我建议这就足够了。

Oracle introduces a example in the tutorial. Oracle 在教程中介绍了一个示例。 https://docs.oracle.com/javase/tutorial/essential/io/file.html#streams https://docs.oracle.com/javase/tutorial/essential/io/file.html#streams

Path file = ...;
try (InputStream in = Files.newInputStream(file);
    BufferedReader reader =
      new BufferedReader(new InputStreamReader(in))) {
    String line = null;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException x) {
    System.err.println(x);
}

Using java.nio.file.Files you can do:使用java.nio.file.Files你可以:

Path path = FileSystems.getDefault().getPath("/path/to", "file.txt");
Files.lines(path).forEach(line ->
    // consume line
);

As the lines(path) method returns a Stream , you can take advantage of any other method of the Stream API, like reading just the first line (if one exists) with:由于lines(path)方法返回一个Stream ,您可以利用 Stream API 的任何其他方法,例如仅读取第一行(如果存在):

Optional<String> firstLine = Files.lines(path).findFirst();

It works for me....这个对我有用....

 public static void main(String[] args) throws IOException 
    {
        RandomAccessFile aFile = new RandomAccessFile
                ("F:\\DetailsMy1.txt", "r");
        FileChannel inChannel = aFile.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1);
        StringBuffer line = new StringBuffer();
        while(inChannel.read(buffer) > 0)
        {
            buffer.flip();
            for (int i = 0; i < buffer.limit(); i++)
            {
                char ch = ((char) buffer.get());
                if(ch=='\r'){
                    System.out.print(line+"[EOL]");
                    line=new StringBuffer();
                }else{
                    line.append(ch);
                }
            }
            buffer.clear(); // do something with the data and clear/compact it.
        }
        inChannel.close();
        aFile.close();
    }

In support of EJP and others above, you might reference this article: http://www.javaworld.com/article/2078654/java-se/java-se-five-ways-to-maximize-java-nio-and-nio-2.html为了支持 EJP 和上述其他内容,您可以参考这篇文章: http : //www.javaworld.com/article/2078654/java-se/java-se-five-ways-to-maximize-java-nio-and- nio-2.html

In particular: "While NIO is often promoted for its performance advantages, it's more precise to say it is highly responsive. In some cases NIO actually performs worse than basic Java I/O. For simple sequential reads and writes of small files, for instance, a straightforward streams implementation might be two or three times faster than the corresponding event-oriented channel-based coding. Also, non-multiplexed channels -- that is, channels in separate threads -- can be much slower than channels that register their selectors in a single thread."特别是:“虽然 NIO 经常因其性能优势而被宣传,但更准确地说它是高度响应的。在某些情况下,NIO 实际上比基本的 Java I/O 性能更差。例如,对于小文件的简单顺序读写,例如, 一个简单的流实现可能比相应的面向事件的基于通道的编码快两到三倍。此外,非多路复用通道——即单独线程中的通道——可能比注册其选择器的通道慢得多在一个线程中。”

I would highlight the statement that NIO In some cases [...] performs worse than basic Java I/O .我要强调 NIO在某些情况下 [...] 性能比基本 Java I/O 更差的声明。 The author follows up with a list of questions to drive a quick analysis of whether NIO is the right choice.作者随后列出了一系列问题,以推动对 NIO 是否是正确选择的快速分析。 If you (or the next person to come along) still decides to pursue NIO there is a good explanation of its use with code example.如果您(或下一个来的人)仍然决定追求 NIO,那么可以通过代码示例很好地解释它的用法。

1) You could convert a BufferedReader to a Stream using the lines method 1) 您可以使用 lines 方法将 BufferedReader 转换为 Stream

List<String> list = new ArrayList<>();

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    list = br.lines().collect(Collectors.toList());    
}

2) Get a Stream directly using the Files.lines method: 2)直接使用Files.lines方法获取Stream:

try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
    stream
        .filter(s -> s.endswith("/"))
        .map(String::toUpperCase)
        .forEach(System.out::println);
}

As DanielBraun points out in his answer, you could also use the readAllLines method instead of the lines method, difference being, straight from the docs:正如 DanielBraun 在他的回答中指出的那样,您也可以使用 readAllLines 方法而不是 lines 方法,区别在于,直接来自文档:

Unlike readAllLines, this method does not read all lines into a List, but instead populates lazily as the stream is consumed.与 readAllLines 不同,此方法不会将所有行读入 List,而是在消耗流时延迟填充。

The package summary page from Java docs gives a nice and concise overview about Streams, and this article also lists out a few other ways of reading a file by line in Java. Java 文档中的包摘要页面提供了关于 Streams 的简洁明了的概述,本文还列出了其他一些在 Java 中逐行读取文件的方法。

NIO is typically used to do either direct memory access or block mediated bulk data transfers. NIO 通常用于进行直接内存访问或块介导的批量数据传输。 It does do other things, but other features have more to do with blocking and non-blocking data access.它确实做其他事情,但其他功能更多地与阻塞和非阻塞数据访问有关。

As such, you might want to use NIO to grab the data quickly (or in a non-blocking manner);因此,您可能希望使用 NIO 快速(或以非阻塞方式)抓取数据; however, if you want to "read line by line" you would be better served by doing the line detection after NIO has read in the available data.但是,如果您想“逐行读取”,则最好在 NIO 读取可用数据后进行行检测。 This could easily be implemented by putting a "line reading" facade over the buffer that NIO just read.这可以通过在 NIO 刚刚读取的缓冲区上放置一个“行读取”外观来轻松实现。

simply use: https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#lines-java.nio.file.Path-只需使用: https : //docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#lines-java.nio.file.Path-

EDIT (humanreadable translation, regards to MeetTitan): Which means: use java.nio.file.Files.lines(Path) - it returns a Stream<String> representing the lines of the file.编辑(人类可读的翻译,关于 MeetTitan):这意味着:使用java.nio.file.Files.lines(Path) - 它返回一个Stream<String>表示文件的行。 It's an method provided by the Java API.它是 Java API 提供的一种方法。 One could consult the Javadoc in order to see the details.可以查阅 Javadoc 以查看详细信息。 The most relevant information is therefore: Files.lines() exists since Java 1.8.因此,最相关的信息是: Files.lines()从 Java 1.8 开始存在。 Use it.用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM