【问题标题】:Fastest way to parse txt file in Java用Java解析文本文件的最快方法
【发布时间】:2015-04-30 09:09:55
【问题描述】:

我必须为具有这种形式的税收计算器解析一个 txt 文件:

Name: Mary Jane
Age: 23
Status: Married
Receipts:

Id: 1
Place: Restaurant
Money Spent: 20

Id: 2
Place: Mall
Money Spent: 30

所以,到目前为止我所做的是:

public void read(File file) throws FileNotFoundException{
    Scanner scanner = new Scanner(file);
    String[] tokens = null;

    while(scanner.hasNext()){
        String line= scanner.nextLine();
        tokens = line.split(":");
        String lastToken = tokens[tokens.length - 1];
        System.out.println(lastToken);

所以,我只想访问该文件的第二列(Mary Jane,23 岁,已婚)到一个班级纳税人(姓名、年龄、状态),并将收据信息访问到一个 Arraylist。

我想把最后一个标记保存到字符串数组中,但我不能这样做,因为我不能将字符串保存到字符串数组中。有人能帮我吗?谢谢。

【问题讨论】:

  • 为什么不能保存到String数组中?是要求吗?您可以使用ìndexOf(':') 定位冒号字符(或空格),然后使用substring() 提取您想要的部分。
  • 不,字符串数组不是必需的,我只是想到了这一点。如果我使用ìndexOf(':'),我如何才能获得正确的部分。例如,在Name: Mary Jane 行中,我只想要玛丽珍,然后将其放入纳税人的构造函数中,与其他字段相同。我应该逐行处理吗?
  • int pos = line.indexOf(':'); String lastToken = line.substring(pos+1).trim(); 假设只有一个冒号:

标签: java parsing text


【解决方案1】:

如果您的数据是 ASCII 并且您不需要字符集转换,那么最快的方法是使用 BufferedInputStream 并自己进行所有解析——找到行终止符,解析数字。不要使用阅读器,或创建字符串,或每行创建任何对象,或使用 parseInt。只需使用字节数组并查看字节。有点乱,但是假设你在写 C 代码,它会更快。

还要考虑一下您正在创建的数据结构有多紧凑,以及您是否也可以通过巧妙地避免在那里每行创建一个对象。

【讨论】:

    【解决方案2】:

    坦率地说,我认为“最快”是一条红鲱鱼。除非您拥有数百万这样的文件,否则您的代码速度不太可能是相关的。

    事实上,您的基本解析方法(使用 Scanner 读取行,使用String.split(...) 分割行似乎很合理。

    您缺少的是代码的结构需要与文件的结构相匹配。这是我将如何做的草图。

    • 如果你要忽略每一行的第一个字段,你需要一个方法:

      1. 读取一行,跳过空行
      2. 拆分它,然后
      3. 返回第二个字段。
    • 如果您要检查第一个字段是否包含预期的关键字,则修改方法以获取参数,并检查该字段。 (我会推荐这个版本...)

    • 然后以正确的模式调用上述方法;例如

      • 调用3次提取姓名、年龄和婚姻状况
      • 调用 1 次以跳过“收据”行
      • 使用 while 循环调用该方法 3 次,以读取每个收据的 3 个字段。

    【讨论】:

      【解决方案3】:

      首先,您为什么需要花时间寻找最快的解决方案?是因为输入文件很大吗?我也不明白你想如何存储解析结果?考虑新类,其中包含您需要从每个人的文件中提取的所有字段。

      小贴士: - 避免不必要的每行内存分配。您的代码中的line.split(":") 就是一个例子。 - 使用缓冲输入。 - 最小化输入/输出操作。

      如果这些还不够你尝试阅读这篇文章http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly

      【讨论】:

        【解决方案4】:

        您真的需要尽可能快吗?在这种情况下,通常可以创建一些对象并在此过程中进行一些垃圾收集,以获得更多可维护的代码。

        我自己会使用两个正则表达式(一个用于纳税人,另一个用于收据循环)。

        我的代码如下所示:

        public class ParsedFile {
            private Taxpayer taxpayer;
            private List<Receipt> receipts;
        
            // getters and setters etc.
        }
        
        public class FileParser {
            private static final Pattern TAXPAYER_PATTERN =
                // this pattern includes capturing groups in brackets ()
                Pattern.compile("Name: (.*?)\\s*Age: (.*?)\\s*Status: (.*?)\\s*Receipts:", Pattern.DOTALL);
        
            public ParsedFile parse(File file) {
                BufferedReader reader = new BufferedReader(new FileReader(file)));
                String firstChunk = getNextChunk(reader);
                Taxpayer taxpayer = parseTaxpayer(firstChunk);
                List<Receipt> receipts = new ArrayList<Receipt>();
                String chunk;
                while ((chunk = getNextChunk(reader)) != null) {
                    receipts.add(parseReceipt(chunk));
                }
                return new ParsedFile(taxpayer, receipts);
            }
        
            private TaxPayer parseTaxPayer(String chunk) {
               Matcher matcher = TAXPAYER_PATTERN.matcher(chunk);
               if (!matcher.matches()) {
                   throw new Exception(chunk + " does not match " + TAXPAYER_PATTERN.pattern());
               }
               // this is where we use the capturing groups from the regular expression
               return new TaxPayer(matcher.group(1), matcher.group(2), ...);
            }
        
            private Receipt parseReceipt(String chunk) {
               // TODO implement
            }
        
            private String getNextChunk(BufferedReader reader) {
               // keep reading lines until either a blank line or end of file
               // return the chunk as a string
            }
        }
        

        【讨论】:

        • 您能向我解释一下吗?我不确定我明白你的意思。谢谢
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-04
        • 1970-01-01
        • 2010-09-06
        • 1970-01-01
        • 2019-10-20
        • 1970-01-01
        相关资源
        最近更新 更多