2011-05-01 56 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