读取文件并解析每一行的有效方法

问题描述 投票:0回答:4

我有一个以下格式的文本文件:每行以一个字符串开头,后面跟着数字序列。每行的长度未知(未知数量的数字,数量从 0 到 1000)。

string_1 3 90 12 0 3
string_2 49 0 12 94 13 8 38 1 95 3
.......
string_n 9 43

之后,我必须使用

handleLine
方法处理每一行,该方法接受两个参数:字符串名称和数字集(参见下面的代码)。

如何高效地读取文件并用

handleLine
处理每一行?

我的解决方法:

  1. 使用 java8 流逐行读取文件
    Files.lines
    有阻塞吗?
  2. 用正则表达式分割每一行
  3. 将每一行转换为标题字符串和一组数字

我认为由于第二步和第三步,它非常无效。第一步意味着java首先将文件字节转换为字符串,然后在第二步和第三步中我将它们转换回

String
/
Set<Integer>
这对性能影响很大吗?如果是 - 如何做得更好?

public handleFile(String filePath) {
    try (Stream<String> stream = Files.lines(Paths.get(filePath))) {
        stream.forEach(this::indexLine);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void handleLine(String line) {
    List<String> resultList = this.parse(line);
    String string_i = resultList.remove(0);
    Set<Integer> numbers = resultList.stream().map(Integer::valueOf).collect(Collectors.toSet());
    handleLine(string_i, numbers); // Here is te final computation which must to be done only with string_i & numbers arguments
}

private List<String> parse(String str) {
    List<String> output = new LinkedList<String>();
    Matcher match = Pattern.compile("[0-9]+|[a-z]+|[A-Z]+").matcher(str);
    while (match.find()) {
        output.add(match.group());
    }
    return output;
}
java nio java-io
4个回答
3
投票

关于你的第一个问题,这取决于你如何引用

Stream
Streams
本质上是懒惰的,如果你不打算使用它,就不做工作。例如,对
Files.lines
的调用实际上不会读取文件,直到您在
Stream
上添加终端操作。

来自java文档:

从文件中读取所有行作为流。与 readAllLines 不同,此方法不会将所有行读取到列表中,而是在消耗流时延迟填充

forEach(Consumer<T>)
调用是一个终端操作,此时,文件的行将被逐行读取并传递给您的
indexLine
方法。

关于您的其他评论,您在这里并没有真正的问题。您想衡量/最小化什么?仅仅因为某件事是多个步骤并不一定意味着它的性能较差。即使您创建了一个 wizbang oneliner 来从

File
字节直接转换为
String
Set
,您可能只是匿名进行了中间映射,或者您调用了一些会导致编译器执行此操作的内容.


1
投票

这是将行解析为名称和数字的代码

stream.forEach(line -> {
    String[] split = line.split("\\b"); //split with blank seperator
    Set<String> numbers = IntStream.range(1, split.length)
                                .mapToObj(index -> split[index])
                                .filter(str -> str.matches("\\d+")) //filter numbers
                                .collect(Collectors.toSet());
    handleLine(split[0], numbers);
});

或者其他方式

Map<Boolean, List<String>> collect = Pattern.compile("\\b")
                                            .splitAsStream(line)
                                            .filter(str -> !str.matches("\\b"))
                                            .collect(Collectors.groupingBy(str -> str.matches("\\d+")));
handleLine(collect.get(Boolean.FALSE).get(0), collect.get(Boolean.TRUE));

1
投票

我开始测试几种解决这个问题的方法,并在指定条件下尽可能地测量性能。以下是我测试的内容、测试方法以及随附的结果:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
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.Random;
import java.util.Scanner;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class App {

    public static void method1(String testFile) {
        List<Integer> nums = null;
        try (Scanner s = new Scanner(Paths.get(testFile))) {
            while (s.hasNext()) {
                if (s.hasNextInt())
                    nums.add(s.nextInt());
                else {
                    nums = new ArrayList<Integer>();
                    String pre = s.next();
                    // handleLine( s.next() ... nums ... );
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method2(String testFile) {
        List<Integer> nums = null;
        try (BufferedReader in = new BufferedReader(new FileReader(testFile));
                Scanner s = new Scanner(in)) {
            while (s.hasNext()) {
                if (s.hasNextInt())
                    nums.add(s.nextInt());
                else {
                    nums = new ArrayList<Integer>();
                    String pre = s.next();
                    // handleLine( s.next() ... nums ... );
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method3(String testFile) {
        List<Integer> nums = null;
        try (BufferedReader br = new BufferedReader(new FileReader(testFile))) {
            String line = null;
            while ((line = br.readLine()) != null) {
                String[] arr = line.split(" ");
                nums = new ArrayList<Integer>();
                for (int i = 1; i < arr.length; ++i)
                    nums.add(Integer.valueOf(arr[i]));
                // handleLine( ... );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method3_1(String testFile) {
        List<Integer> nums = null;
        try (BufferedReader br = new BufferedReader(new FileReader(testFile))) {
            String line = null;
            while ((line = br.readLine()) != null) {
                String[] arr = line.split(" ");
                nums = new ArrayList<Integer>();
                for (int i = 1; i < arr.length; ++i)
                    nums.add(Integer.parseInt(arr[i]));
                // handleLine( ... );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method4(String testFile) {
        List<Integer> nums = null;
        try {
            List<String> lines = Files.readAllLines(Paths.get(testFile));
            for (String s : lines) {
                String[] arr = s.split(" ");
                nums = new ArrayList<Integer>();
                for (int i = 1; i < arr.length; ++i)
                    nums.add(Integer.valueOf(arr[i]));
                // handleLine( ... );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method4_1(String testFile) {
        List<Integer> nums = null;
        try {
            List<String> lines = Files.readAllLines(Paths.get(testFile));
            for (String s : lines) {
                String[] arr = s.split(" ");
                nums = new ArrayList<Integer>();
                for (int i = 1; i < arr.length; ++i)
                    nums.add(Integer.parseInt(arr[i]));
                // handleLine( ... );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method5(String testFile) {
        List<Integer> nums = null;
        try (BufferedReader br = Files.newBufferedReader(Paths.get(testFile))) {
            List<String> lines = br.lines().collect(Collectors.toList());
            for (String s : lines) {
                String[] arr = s.split(" ");
                nums = new ArrayList<Integer>();
                for (int i = 1; i < arr.length; ++i)
                    nums.add(Integer.valueOf(arr[i]));
                // handleLine( ... );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method5_1(String testFile) {
        List<Integer> nums = null;
        try (BufferedReader br = Files.newBufferedReader(Paths.get(testFile))) {
            List<String> lines = br.lines().collect(Collectors.toList());
            for (String s : lines) {
                String[] arr = s.split(" ");
                nums = new ArrayList<Integer>();
                for (int i = 1; i < arr.length; ++i)
                    nums.add(Integer.parseInt(arr[i]));
                // handleLine( ... );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method6(String testFile) {
        List<Integer> nums = new LinkedList<Integer>();
        try (Stream<String> stream = Files.lines(Paths.get(testFile))) {
            stream.forEach(line -> {
                String[] split = line.split("\\b"); // split with blank seperator
                Set<String> numbers = IntStream.range(1, split.length)
                        .mapToObj(index -> split[index])
                        .filter(str -> str.matches("\\d+")) // filter numbers
                        .collect(Collectors.toSet());
                numbers.forEach((k) -> nums.add(Integer.parseInt(k)));
                // handleLine( ... );
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {

        args = new String[] { "C:\\Users\\Nick\\Desktop\\test.txt" };

        Random r = new Random();

        System.out.println("warming up a little...");
        for (int i = 0; i < 100000; ++i) {
            int x = r.nextInt();
        }

        long s1 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method1(args[0]);
        long e1 = System.currentTimeMillis();

        long s2 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method2(args[0]);
        long e2 = System.currentTimeMillis();

        long s3 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method3(args[0]);
        long e3 = System.currentTimeMillis();

        long s3_1 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method3_1(args[0]);
        long e3_1 = System.currentTimeMillis();

        long s4 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method4(args[0]);
        long e4 = System.currentTimeMillis();

        long s4_1 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method4_1(args[0]);
        long e4_1 = System.currentTimeMillis();

        long s5 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method5(args[0]);
        long e5 = System.currentTimeMillis();

        long s5_1 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method5_1(args[0]);
        long e5_1 = System.currentTimeMillis();

        long s6 = System.currentTimeMillis();
        for (int i = 0; i < 10000; ++i)
            method6(args[0]);
        long e6 = System.currentTimeMillis();

        System.out.println("method 1 = " + (e1 - s1) + " ms");
        System.out.println("method 2 = " + (e2 - s2) + " ms");
        System.out.println("method 3 = " + (e3 - s3) + " ms");
        System.out.println("method 3_1 = " + (e3_1 - s3_1) + " ms");
        System.out.println("method 4 = " + (e4 - s4) + " ms");
        System.out.println("method 4_1 = " + (e4_1 - s4_1) + " ms");
        System.out.println("method 5 = " + (e5 - s5) + " ms");
        System.out.println("method 5_1 = " + (e5_1 - s5_1) + " ms");
        System.out.println("method 6 = " + (e6 - s6) + " ms");
    }
}
  • 与 java.version = 1.8.0_101 (Oracle) 一起使用
  • x64 操作系统/处理器

结果输出:

warming up a little...
method 1 = 1103 ms
method 2 = 872 ms
method 3 = 440 ms
method 3_1 = 418 ms
method 4 = 413 ms
method 4_1 = 376 ms
method 5 = 439 ms
method 5_1 = 384 ms
method 6 = 646 ms

据我了解,我测试的示例中的最佳方法是使用

Files.readAllLines
s.split(" ")
Integer.parseInt
。在我创建和测试的示例中,这三种组合再次产生了最快的,至少也许您会更改为Integer.parseInt
来提供一些帮助。

注意我使用资源来帮助获得一些受欢迎的方法并将它们应用于这个问题/示例。例如。

这篇博文本教程,还有这个很棒的家伙@Peter-Lawrey。另外,始终可以进行进一步的改进

另外,test.txt 文件:

my_name 15 00 29 101 1234 cool_id 11 00 01 10 010101 longer_id_name 1234 dynamic_er 1 2 3 4 5 6 7 8 9 10 11 12 123 1456 15689 555555555

(注意:性能可能会因文件大小而有很大差异!)


0
投票
您好,我正在尝试生成 .vb 文件的副本并创建具有相同信息的 .txt,我有代码并且正在工作,问题是我必须逐行读取并在每一行中添加数字,如果该代码有一个错误,必须在 .txt 中显示

这是我的代码。 0001 是我应该在 .txt 中生成的代码,例如,如果“FileWriter fw = null”没有

; 我的代码必须读取该行并显示“错误 01-Filereader 没有” ;

**0001** public static void main(String[] args) { **0002** FileReader fr = null; FileWriter fw = null try { fr = new FileReader("C:\\Users\\etc"); fw = new FileWriter("C:\\Users\\etc\\example.txt"); int c = fr.read(); while(c!=-1) { fw.write(c); c = fr.read(); } } catch(IOException e) { } finally { close(fr); close(fw); } } public static void close(Closeable stream) { try { if (stream != null) { stream.close(); } } catch(IOException e) { //... } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.