Java File I / O help - PullRequest
       5

Java File I / O help

0 голосов
/ 01 мая 2011

У меня проблема с моим кодом.Мне нужно выполнить несколько операций над файлом журнала с такой структурой:

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 впоследствии, как если бы файл был пуст, поэтому я предполагаю, что где-то допустил ошибку при вводе / выводе.Вот код:

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");
  }
}

Любая помощь в выяснении проблемы будет принята с благодарностью, так как я застрял.

Ответы [ 2 ]

4 голосов
/ 01 мая 2011

Я еще не полностью прочитал код, но, полагаю, вы не устанавливаете позицию чтения обратно в начало файла при запуске новой операции. Таким образом, nextLine() вернет ноль.

Вы должны создать новый сканер для каждой операции и затем закрыть его. Сканер AFAIK не предоставляет метод возврата к первому байту.

В настоящее время я мог бы также подумать о 3 альтернативах:

  1. Используйте BufferedReader и вызывайте reset() для каждой новой операции. Это должно заставить читателя вернуться к байту 0, если вы не вызывали mark() где-нибудь.

  2. Считайте содержимое файла один раз и переберите строки в памяти, то есть поместите все строки в List<String>, а затем начните с каждой строки.

  3. Прочитайте файл один раз, проанализируйте каждую строку и создайте подходящую структуру данных, которая содержит нужные вам данные. Например, вы можете использовать TreeMap<Date, Map<Page, Map<IPAdress, List<Visit>>>>, то есть вы будете хранить посещения по ip-адресу на страницу для каждой даты. Затем вы можете выбрать соответствующие подкарты по дате, странице и IP-адресу.

2 голосов
/ 01 мая 2011

Метод reset BufferedReader, рекомендуемый Thomas , будет работать только в том случае, если размер файла меньше размера буфера или если вы вызываете 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...