杀死Java进程时关闭BufferedReader和BufferedWriter

时间:2014-03-30 10:17:40

标签: java

我有一个java程序,它在更新时读取日志信息,并将过滤后的数据写入新文件。当我以jar形式执行它时,它将一直运行直到我终止进程。

如何确保在我终止此过程时关闭BufferedReader和BufferedWriter以防止内存泄漏?

我已尝试使用其他人建议的try ... finally块方法,但这会在程序仍在运行时关闭流。提前谢谢。

FileWatcher.java

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*

public class FileWatcher implements Runnable
{
  boolean running = true;
  File file;
  BufferedReader reader;
  BufferedWriter writer;
  String pathToLog, pathToOutput;

  public FileWatcher(String pathToLog, String pathToOutput)
  {
    this.pathToLog = pathToLog;
    this.pathToOutput = pathToOutput;
  }

  public void run()
  {
    try
    {
      file = new File(pathToOutput);
      reader = new BufferedReader(new FileReader(pathToLog));
      writer = new BufferedWriter(new FileWriter(pathToOutput));

      if (!file.exists())
      {
        file.createNewFile();
      }
    }
    catch (FileNotFoundException e)
    {
      e.printStackTrace();
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }

    String line = null;

    System.out.println("Running...");
    while (running)
    {
      try
      {
        /* For each packet logged */
        for (int i = 0; i < 7; i++)
        {
          line = reader.readLine(); //Analyse text in line

          /* If no text then break */
          if (line == null)
          {
            break;
          }

          /* If the line begins with valid IP address then break to find Src and Dest IP */
          if (line.startsWith("192", 22))
          {
            break;
          }
        }

        /* If line is not null then filter out the Source IP and Destination IP */
        if (line != null)
        {
          int lastIndexOfSrcIP = StringUtils.ordinalIndexOf(line, ":", 3); // Position to stop reading Source IP
          int firstIndexOfDestIP = StringUtils.ordinalIndexOf(line, ">", 1) + 2; // Position to start reading Destination IP
          int lastIndexOfDestIP = StringUtils.ordinalIndexOf(line, ":", 4); // Position to stop reading Destination IP

          String sourceIP = line.substring(22, lastIndexOfSrcIP); // Source IP
          String destinationIP = line.substring(firstIndexOfDestIP, lastIndexOfDestIP); // Destination IP

          /* Check if Source IP is the IP address of the node  we are running Snort on
           * if so then don't append to malicious clients file */
          if (!(sourceIP.equals("192.168.7.5")))
          {
            //If Source IP is not in file then add it
            if (!(FileUtils.readFileToString(file).contains(sourceIP)))
            {
              writer.write(sourceIP + "\n");
              writer.flush();
            }

            System.out.println(sourceIP + "\t" + destinationIP);
          }
        }
        else
        {
          //Sleep whilst there are no new logging alert information
          try
          {
            Thread.sleep(1000);
          }
          catch (InterruptedException e)
          {
            running = false;
            writer.close();
            reader.close();
          }
        }
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }
    }
  }
}

Main.java

public class Daemon
{
  public static void main(String[] args)
  {
    String pathToLog = args[0];
    String pathToOutput = args[1];

    Thread daemon = new Thread(new FileWatcher(pathToLog, pathToOutput));
    daemon.start();
  }
}

2 个答案:

答案 0 :(得分:1)

要直接回答你的问题,我会在构造函数中创建文件,这样你就可以让代码快速失败并让调用者知道这不会起作用。

然后我会有一个try / finally块包装所有代码,比如

public void run() {
    try {
        run0();
    } catch(Throwable t) {
        System.err.println("Process dying");
        t.printStackTrace();
    } finally {
        // close all resources
    }
}

private void run0() throws Stuff... {
    // does the real work
}
  

如何确保在我终止此过程时关闭BufferedReader和BufferedWriter以防止内存泄漏?

当您终止某个进程时,操作系统将回收所有进程资源,因此无论您如何编写代码,都无法获得内存泄漏。您可以获得的唯一资源泄漏是留下不需要的临时文件。

BTW

  • 当您调用FileWriter时,它将根据需要创建新文件或截断。没有必要检查文件是否仍然存在,因为即使它已被删除(这是极不可能的),你也不会使用刚创建的文件。

  • 我不会在main的末尾创建一个新的线程,因为这不会让你获益。

  • 如果它是一个守护程序线程,我只会调用一个线程daemon。给它一个误导性的名字可能会令人困惑。

答案 1 :(得分:0)

如果您使用的是Java 7或更高版本,则可以使用try-with-resources来声明您的读者/作者,并且当您终止该过程时,它们应自动关闭。

在您的示例中,它看起来像这样:

try(reader = new BufferedReader(new FileReader(pathToLog));
    writer = new BufferedWriter(new FileWriter(pathToOutput));) {
        ...
}