Lambda 每100行Java 8流读取文件

Lambda 每100行Java 8流读取文件,lambda,java-8,stream,Lambda,Java 8,Stream,假设我有一个很大的文件,我想读100行每行,做一个操作。(我想合并100行并发送一个rest请求) 在Java7中,我将执行以下操作 try (BufferedReader br = new BufferedReader(new FileReader(fileName))) { String line; int count = 0; List<String> list = new ArrayList<>(); while (

假设我有一个很大的文件,我想读100行每行,做一个操作。(我想合并100行并发送一个rest请求)

在Java7中,我将执行以下操作

try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {

    String line;
    int count = 0;
    List<String> list = new ArrayList<>();       
    while ((line = br.readLine()) != null) {
        list.add(line);
        count++;
        if (count % 100 == 0) {
            //do the operation on list
            list = new ArrayList();
        }
    }
} catch (IOException e) {
    e.printStackTrace();
}
try(BufferedReader br=new BufferedReader(new FileReader(fileName))){
弦线;
整数计数=0;
列表=新的ArrayList();
而((line=br.readLine())!=null){
列表。添加(行);
计数++;
如果(计数%100==0){
//在列表中执行此操作
列表=新的ArrayList();
}
}
}捕获(IOE异常){
e、 printStackTrace();
}
这里有什么东西可以利用Java8流吗? 我知道我们可以做类似的事情,但它在每条线路上运行,而不是在100条线路上运行。所以我认为foreach不是这里的选择

try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
    stream.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}
try(Stream=Files.line(path.get(fileName))){
stream.forEach(System.out::println);
}捕获(IOE异常){
e、 printStackTrace();
}

您可以使用and拆分流,然后每100行并行发送一个rest请求。例如:

split(Paths.get("file"), 100).parallel().forEach(this::sendRequest);
split(Paths.get("file"), 100).forEach(this::sendRequest);

void sendRequest(List<String> each) {
  // then you must send the rest request in parallel here
}

注意:行信息文件中没有分隔符
|
。每个值都必须使用
DataOutputStream#writeLong
long
的形式写入,因为以这种格式写入行信息文件,可以按字节计算
offsetN
的位置,例如:
8*M;M=(1..N)
,然后您可以通过从
offsetN
读取8个字节来获得
offsetN


实际上,索引文件应该在创建大文件时创建(如果文件太大,它也需要拆分),这样可以节省您进一步使用的时间。

如果您不喜欢上述方法,您可以简单地使用第二种方法,但是您不能并行创建部分流,因为您必须按顺序读取
行。例如:

split(Paths.get("file"), 100).parallel().forEach(this::sendRequest);
split(Paths.get("file"), 100).forEach(this::sendRequest);

void sendRequest(List<String> each) {
  // then you must send the rest request in parallel here
}
split(path.get(“file”),100.forEach(this::sendRequest);
作废发送请求(列出每个请求){
//那么您必须在这里并行发送rest请求
}

流拆分(路径,整数限制)引发IOException{
//如果其大小<限制,则跳过其余行
返回拆分(Files.lines(path)、limit、true);
}
流分割(流源、,
整数极限,布尔值(最小元素){
//仅用于打印目的的变量
Spliterator it=source.Spliterator();
long size=it.estimateSize();
int c=it.characteristics();//特征
返回流(新的抽象拆分器(大小,c){
私有整数阈值=SkipPreMiningElements?限制:1;
@凌驾
@SuppressWarnings(“StatementWithEmptyBody”)

公共布尔型优先权(Consumery您可以在java-8流中每100行并行发送一个rest请求。@Eugene您为什么说不建议使用
skip
操作?@Eugene否。您需要首先计算所有行,这既简单又快速。然后将耗时的操作放在并行流中。我不想将所有内容加载到列表(内存)中然后处理所有文件。文件将超过100GB,所以我正在寻找一些惰性操作或类似的东西,从文件中读取100行,然后执行该操作并继续执行相同的操作…@holi java那么您将遇到内存问题…OP明确表示不希望,但这会为每个新页面创建一个新流!它读取文件多次,多次创建对磁盘、文件句柄和其他操作系统资源等的大量访问。您测试过吗?@Federicoperaltachaffner是的,算法是
N+1
,但它可以创建部分流并并行发送请求。@Federicoperaltachaffner您可以合理地控制fork-join-pool线程大小,对于请求,i我只是在读书,所以我想没问题,先生。
Stream<List<String>> split(Path path, int limit) throws IOException {
    // skip the remaining lines if its size < limit
    return split(Files.lines(path), limit, true);
}

<T> Stream<List<T>> split(Stream<T> source,
                          int limit, boolean skipRemainingElements) {

    //variables just for printing purpose
    Spliterator<T> it = source.spliterator();
    long size = it.estimateSize();
    int c = it.characteristics();// characteristics

    return stream(new AbstractSpliterator<List<T>>(size, c) {
        private int thresholds = skipRemainingElements ? limit : 1;

        @Override
        @SuppressWarnings("StatementWithEmptyBody")
        public boolean tryAdvance(Consumer<? super List<T>> action) {
            List<T> each = new ArrayList<>(limit);

            while (each.size() < limit && it.tryAdvance(each::add)) ;

            if (each.size() < thresholds) return false;

            action.accept(each);
            return true;
        }

    }, false).onClose(source::close);
}