将文件拆分为流
上周,我討論了類Pattern新的(@since 1.8)方法splitAsStream可以處理字符序列,僅從流中讀取該字符序列,并且不進行模式匹配以創建所有可能的元素并返回它作為流。 這種行為是流的本質,它是支持高性能應用程序的必經之路。
正如我在上周所承諾的那樣,在本文中,我將展示splitAsStream的實際應用,在該應用中,處理流而不是將整個字符串拆分成數組并對其進行處理確實有意義。
您可能已經從文章標題中猜到了該應用程序正在將文件與一些標記分離。 只要文件長度不超過2GB,就可以將其表示為CharSequence 。 限制來自以下事實: CharSequence的長度是int值,在Java中為32位。 文件長度為long ,為64位。 由于從文件讀取比從已在內存中的字符串讀取要慢得多,因此使用流處理的惰性是有意義的。 我們需要的是一個由文件備份的字符序列實現。 如果可以的話,我們可以編寫如下程序:
public static void main(String[] args) throws FileNotFoundException {Pattern p = Pattern.compile("[,\\.\\-;]");final CharSequence splitIt = new FileAsCharSequence(new File("path_to_source\\SplitFileAsStream.java"));p.splitAsStream(splitIt).forEach(System.out::println);}此代碼不讀取文件的任何部分,但不需要,假定實現FileAsCharSequence不會讀取文件貪婪的內容。 FileAsCharSequence類的實現可以是:
package com.epam.training.regex;import java.io.*;public class FileAsCharSequence implements CharSequence {private final int length;private final StringBuilder buffer = new StringBuilder();private final InputStream input;public FileAsCharSequence(File file) throws FileNotFoundException {if (file.length() > (long) Integer.MAX_VALUE) {throw new IllegalArgumentException("File is too long to handle as character sequence");}this.length = (int) file.length();this.input = new FileInputStream(file);}@Overridepublic int length() {return length;}@Overridepublic char charAt(int index) {ensureFilled(index + 1);return buffer.charAt(index);}@Overridepublic CharSequence subSequence(int start, int end) {ensureFilled(end + 1);return buffer.subSequence(start, end);}private void ensureFilled(int index) {if (buffer.length() < index) {buffer.ensureCapacity(index);final byte[] bytes = new byte[index - buffer.length()];try {int length = input.read(bytes);if (length < bytes.length) {throw new IllegalArgumentException("File ended unexpected");}} catch (IOException e) {throw new RuntimeException(e);}try {buffer.append(new String(bytes, "utf-8"));} catch (UnsupportedEncodingException ignored) {}}} }該實現僅從文件中讀取那么多字節,這是對charAt或subSequence的最后一個實際方法調用所需要的。
如果您有興趣,可以改進此代碼,以僅將真正需要的字節保留在內存中,并刪除已經返回到流中的字節。 要知道不需要什么字節,上一篇文章提供了一個很好的提示,那就是splitAsStream絕不會接觸索引比最后一次調用subSequence的第一個( start )參數小的subSequence 。 但是,如果您以一種丟棄字符的方式實現代碼,并且如果有人要訪問已經拋出的字符而失敗,那么它將無法真正實現CharSequence接口,盡管只要使用splitAsStream ,它仍然可以很好地工作。只要實現不會改變,并且開始需要一些已經傳遞的字符。 (嗯,我不確定,但是如果我們使用一些復雜的正則表達式作為拆分模式,也可能會發生這種情況。)
編碼愉快!
翻譯自: https://www.javacodegeeks.com/2017/11/split-file-stream.html
總結
- 上一篇: 两个迭代器的故事
- 下一篇: 瑞士是哪个国家(是一个怎样的国家,真实的