2011-05-01 55 views
0

我的代码有问题。我需要做几个操作的日志文件上有这样的结构:Java文件I/O帮助

190.12.1.100 2011-03-02 12:12 test.html 
190.12.1.100 2011-03-03 13:18 data.html 
128.33.100.1 2011-03-03 15:25 test.html 
128.33.100.1 2011-03-04 18:30 info.html 

我需要每月访问,每页和基于IP唯一身份访问者人数访问次数的数量。这不是问题,我设法让所有三个操作都起作用。问题是,只有第一个选项正确运行,而其他选择只是返回0后的值,就好像该文件是空的,所以我猜我犯了一个错误的I/O的地方。这里的代码:

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

public class WebServerAnalyzer { 

private Map<String, Integer> hm1; 
private Map<String, Integer> hm2; 
private int[] months; 
private Scanner input; 

public WebServerAnalyzer() throws IOException { 
    hm1 = new HashMap<String, Integer>(); 
    hm2 = new HashMap<String, Integer>(); 
    months = new int[12]; 
    for (int i = 0; i < 12; i++) { 
     months[i] = 0; 
    } 
    File file = new File("webserver.log"); 
    try { 
     input = new Scanner(file); 
    } catch (FileNotFoundException fne) { 
     input = null; 
    } 
} 

public String nextLine() { 
    String line = null; 
    if (input != null && input.hasNextLine()) { 
    line = input.nextLine(); 
    } 
    return line; 
} 

public int getMonth(String line) { 
    StringTokenizer tok = new StringTokenizer(line); 
    if (tok.countTokens() == 4) { 
    String ip = tok.nextToken(); 
    String date = tok.nextToken(); 
    String hour = tok.nextToken(); 
    String page = tok.nextToken(); 
    StringTokenizer dtok = new StringTokenizer(date, "-"); 
    if (dtok.countTokens() == 3) { 
     String year = dtok.nextToken(); 
     String month = dtok.nextToken(); 
     String day = dtok.nextToken(); 
     int m = Integer.parseInt(month); 
     return m; 
    } 
    } 
    return -1; 
} 

public String getIP(String line) { 
    StringTokenizer tok = new StringTokenizer(line); 
    if (tok.countTokens() == 4) { 
    String ip = tok.nextToken(); 
    String date = tok.nextToken(); 
    String hour = tok.nextToken(); 
    String page = tok.nextToken(); 
    StringTokenizer dtok = new StringTokenizer(date, "-"); 
     return ip; 
    } 
    return null; 
} 

public String getPage(String line) { 
    StringTokenizer tok = new StringTokenizer(line); 
    if (tok.countTokens() == 4) { 
    String ip = tok.nextToken(); 
    String date = tok.nextToken(); 
    String hour = tok.nextToken(); 
    String page = tok.nextToken(); 
    StringTokenizer dtok = new StringTokenizer(date, "-"); 
     return page; 
    } 
    return null; 
} 

public void visitsPerMonth() { 
    String line = null; 
    do { 
    line = nextLine(); 
    if (line != null) { 
     int m = getMonth(line); 
     if (m != -1) { 
     months[m - 1]++; 
     } 
    } 
    } while (line != null); 

    // Print the result 
    String[] monthName = {"JAN ", "FEB ", "MAR ", 
     "APR ", "MAY ", "JUN ", "JUL ", "AUG ", "SEP ", 
     "OCT ", "NOV ", "DEC "}; 
    for (int i = 0; i < 12; i++) { 
    System.out.println(monthName[i] + months[i]); 
    } 
} 

public int count() throws IOException { 
    InputStream is = new BufferedInputStream(new FileInputStream("webserver.log")); 
    try { 
    byte[] c = new byte[1024]; 
    int count = 0; 
    int readChars = 0; 
    while ((readChars = is.read(c)) != -1) { 
     for (int i = 0; i < readChars; ++i) { 
     if (c[i] == '\n') 
      ++count; 
     } 
    } 
    return count; 
    } finally { 
    is.close(); 
    } 
} 


public void UniqueIP() throws IOException{ 
    String line = null; 
    for (int x = 0; x <count(); x++){ 
    line = nextLine(); 
    if (line != null) { 
     if(hm1.containsKey(getIP(line)) == false) { 
     hm1.put(getIP(line), 1); 
     } else { 
     hm1.put(getIP(line), hm1.get(getIP(line)) +1); 
     } 
    } 
    } 

    Set set = hm1.entrySet(); 
    Iterator i = set.iterator(); 
    System.out.println("\nNumber of unique visitors: " + hm1.size()); 
    while(i.hasNext()) { 
    Map.Entry me = (Map.Entry)i.next(); 
    System.out.print(me.getKey() + " - "); 
    System.out.println(me.getValue() + " visits"); 
    } 
} 

public void pageVisits() throws IOException{ 
    String line = null; 
    for (int x = 0; x <count(); x++){ 
    line = nextLine(); 
    if (line != null) { 
     if(hm2.containsKey(getPage(line)) == false) 
     hm2.put(getPage(line), 1); 
     else 
     hm2.put(getPage(line), hm2.get(getPage(line)) +1); 
    } 
    } 
    Set set = hm2.entrySet(); 
    Iterator i = set.iterator(); 
    System.out.println("\nNumber of pages visited: " + hm2.size()); 
    while(i.hasNext()) { 
    Map.Entry me = (Map.Entry)i.next(); 
    System.out.print(me.getKey() + " - "); 
    System.out.println(me.getValue() + " visits"); 
    } 
} 

任何帮助搞清楚这个问题将不胜感激,因为我很卡住。

+0

您应该使用字符串类的Split方法而不是StringTokenizer – Clayton 2011-05-01 09:32:25

+0

它会导致除了被混乱之外的任何问题吗?在所有其他工作完成后,我很可能会这样做。 – Terezi 2011-05-01 09:36:58

+0

不,StringTokenizer仍然适用于你想要完成的工作,它只是被弃用了。所以除非标记器因为某种原因没有正确地断开字符串,在功能上它基本上是相同的。 – Clayton 2011-05-01 09:40:25

回答

2

reset方法BufferedReaderThomas建议只会如果文件大小大于缓冲区的大小小于或工作,如果你有一个大的叫mark足够的预读限制。

我会建议阅读文件一次,并更新您的地图和每一行数组。顺便说一句,你不需要一个扫描仪只是读取线,BufferedReader有一个readLine方法本身。

BufferedReader br = ...; 
String line; 
while (null != (line = br.readLine())) { 
    String ip = getIP(line); 
    String page = getPage(line); 
    int month = getMonth(line); 
    // update hashmaps and arrays 
} 
+0

是的,我发现了重置。然而,这,完美地工作。谢谢! – Terezi 2011-05-01 10:28:29

4

我还没有彻底地读过代码,但我想你在开始一个新的操作时没有将读取位置设置回文件的开头。因此nextLine()将返回null。

您应该为每个操作创建一个新的扫描仪,然后关闭它。 AFAIK扫描器不提供返回第一个字节的方法。

目前我也能想到的3种选择:

  1. 使用BufferedReader,并呼吁reset()每个新的操作。这应该会导致读者返回字节0,前提是您没有在某处拨打mark()

  2. 只读一次文件内容并遍历内存中的行,即将所有行写入List<String>,然后从每行开始。

  3. 只读一次文件,解析每一行并构建一个包含所需数据的适当数据结构。例如,您可以使用TreeMap<Date, Map<Page, Map<IPAdress, List<Visit>>>>,即您将每个日期的每个IP地址每页的访问数存储起来。然后,您可以按日期,页面和IP地址选择适当的子图。

+0

啊,谢谢。我将尝试BufferedReader方法。 – Terezi 2011-05-01 09:37:37