2010-04-02 27 views
2

我有一个文本文件,它看起来像这样:我该如何解析Java中的这个简单的文本文件?

grn129   agri- 
ac-214   ahss 
hud114   ahss 
lov1150   ahss 
lov1160   ahss 
lov1170   ahss 
lov1210   ahss 

什么是解析使用Java,如果我想创建与第一列作为键和第二列作为一个HashMap这个文件的最好方法值。

我应该使用Scanner类吗?尝试读取整个文件作为一个字符串和分裂?

什么是最好的方法?

回答

1

使用扫描仪或正常的FileReader + String.split()应该都可以正常工作。我认为速度差异很小,除非你打算一遍又一遍地读取一个非常大的文件,这并不重要。

编辑:实际上,对于第二种方法,请使用BufferedReader。它有一个getLine()方法,它使事情变得更容易一些。

0

如果您希望遵循教科书解决方案,请使用StringTokenizer。它直截了当,易于学习,非常简单。它可以克服结构中的简单偏差(可变数量的空白字符,不规则的格式化线等)

但是,如果您的文本已知为100%格式良好且可预测,那么只需将一堆行一个缓冲区,一次带一个,并将部分字符串取出到你的HashMap键和值中。它比StringTokenizer更快,但缺乏灵活性。

+4

的StringTokenizer正在如果不是很过时,至少根据它的JavaDoc认为是传统类,是不是教科书的解决方案了。 – Thilo 2010-04-02 06:15:13

+0

@Thilo:你应该用什么来代替? – 2010-04-02 06:38:38

+0

根据JavaDoc,String.split。 – Thilo 2010-04-02 07:10:33

2

我不知道最好的方法,但我怀疑最有效的方法是一次只读一行(使用BufferedReader),然后通过查找第一个空格字符来拆分每一行,然后分割,然后修剪双方。然而,除非它需要超快速,否则你最喜欢的是好的。

我个人偏见反对一次加载整个文件......除了它假定有足够的内存来容纳整个文件,它不允许任何并行计算(例如,if输入来自管道)。能够在输入仍然生成时处理输入是有意义的。

+0

是的,我已经使用BufferedReader和Scanners进行了一些测试,使用BufferedReader并自己进行分割(不使用String的.split()方法)比Scanner快得多,但BufferedReader + String.split()是关于同样的速度。无论哪种方式,这是更多的工作,可能大部分时间都不值得。 – 2010-04-02 06:13:26

+0

@Brendan,我建议手动分割(而不是使用String.split函数),但你是对的......它可能不是一个显着的差异。 – 2010-04-02 06:26:43

4

下面是我该怎么做的!自2000年以来,我几乎完全是一名Java程序员,所以它可能有点老套。有一行特别我有点得意:

new InputStreamReader(fin, "UTF-8"); 

http://www.joelonsoftware.com/articles/Unicode.html

享受!

import java.io.*; 
import java.util.*; 

public class StackOverflow2565230 { 

    public static void main(String[] args) throws Exception { 
    Map<String, String> m = new LinkedHashMap<String, String>(); 
    FileInputStream fin = null; 
    InputStreamReader isr = null; 
    BufferedReader br = null; 
    try { 
     fin = new FileInputStream(args[0]); 
     isr = new InputStreamReader(fin, "UTF-8"); 
     br = new BufferedReader(isr); 
     String line = br.readLine(); 
     while (line != null) { 
     // Regex to scan for 1 or more whitespace characters 
     String[] toks = line.split("\\s+"); 
     m.put(toks[0], toks[1]); 
     line = br.readLine(); 
     } 
    } finally { 
     if (br != null) { br.close(); } 
     if (isr != null) { isr.close(); } 
     if (fin != null) { fin.close(); } 
    } 

    System.out.println(m); 
    } 

} 

而这里的输出:

[email protected]:~$ javac StackOverflow2565230.java 
[email protected]:~$ java -cp . StackOverflow2565230 file.txt 
{grn129=agri-, ac-214=ahss, hud114=ahss, lov1150=ahss, lov1160=ahss, lov1170=ahss, lov1210=ahss} 

是的,我的电脑的名字是花。以Bambi的臭鼬命名。

最后一点:因为close()方法可以抛出IOException,这是我会怎样真的关闭流:

} finally { 
    try { 
    if (br != null) br.close(); 
    } finally { 
    try { 
     if (isr != null) isr.close(); 
    } finally { 
     if (fin != null) fin.close(); 
    } 
    } 
} 
+1

+1将是我的解决方案+ LinkedHashMap,很好! “有一行我特别感到有点骄傲” - > lol – Karussell 2010-04-02 10:15:43

+0

你不能假设输入文件是用UTF-8编码的。它应该是一个参数。 – 2012-06-18 14:40:40

3

基于@Julius戴维斯,这里是一个较短的版本。

import java.io.*; 
import java.util.*; 

public class StackOverflow2565230b { 
    public static void main(String... args) throws IOException { 
    Map<String, String> m = new LinkedHashMap<String, String>(); 
    BufferedReader br = null; 
    try { 
     br = new BufferedReader(new FileReader(args[0])); 
     String line; 
     while ((line = br.readLine()) != null) { 
     // Regex to scan for 1 or more whitespace characters 
     String[] toks = line.split("\\s+"); 
     m.put(toks[0], toks[1]); 
     } 
    } finally { 
     if (br != null) br.close(); // dont throw an NPE because the file wasn't found. 
    } 

    System.out.println(m); 
    } 
} 
+0

好点! if(br!= null)br.close(); – 2010-04-02 22:25:13

-1

朱利叶斯戴维斯的回答很好。

但是,我恐怕你将不得不定义你的文本文件的格式将被解析。例如,第一列和第二列之间的单独字符是什么,如果不是固定的,会造成更多的困难。

0

如何缓存正则表达式? (String.split()会在每次调用时编译正则表达式)

如果性能测试了几个大文件(100,1k,100k,1m,10m条目)上的每种方法,并且看到性能如何比较。

import java.io.*; 
import java.util.*; 
import java.util.regex.*; 

public class So2565230 { 

    private static final Pattern rgx = Pattern.compile("^([^ ]+)[ ]+(.*)$"); 

    private static InputStream getTestData(String charEncoding) throws UnsupportedEncodingException { 
     String nl = System.getProperty("line.separator"); 
     StringBuilder data = new StringBuilder(); 
     data.append(" bad data " + nl); 
     data.append("grn129   agri-" + nl); 
     data.append("grn129   agri-" + nl); 
     data.append("ac-214   ahss" + nl); 
     data.append("hud114   ahss" + nl); 
     data.append("lov1150   ahss" + nl); 
     data.append("lov1160   ahss" + nl); 
     data.append("lov1170   ahss" + nl); 
     data.append("lov1210   ahss" + nl); 
     byte[] dataBytes = data.toString().getBytes(charEncoding); 
     return new ByteArrayInputStream(dataBytes); 
    } 

    public static void main(final String[] args) throws IOException { 
     String encoding = "UTF-8"; 

     Map<String, String> valuesMap = new LinkedHashMap<String, String>(); 

     InputStream is = getTestData(encoding); 
     new So2565230().fill(valuesMap, is, encoding); 

     for (Map.Entry<String, String> entry : valuesMap.entrySet()) { 
      System.out.format("K=[%s] V=[%s]%n", entry.getKey(), entry.getValue()); 
     } 
    } 

    private void fill(Map<String, String> map, InputStream is, String charEncoding) throws IOException { 
     BufferedReader bufReader = new BufferedReader(new InputStreamReader(is, charEncoding)); 
     for (String line = bufReader.readLine(); line != null; line = bufReader.readLine()) { 
      Matcher m = rgx.matcher(line); 
      if (!m.matches()) { 
       System.err.println("Line has improper format (" + line + ")"); 
       continue; 
      } 
      String key = m.group(1); 
      String value = m.group(2); 
      if (map.put(key, value) != null) { 
       System.err.println("Duplicate key detected: (" + line + ")"); 
      } 
     } 
    } 
}