3

我使用 ScheduledThreadPoolExecutor 每 fileIntervalInSeconds 秒创建一个文件:

executorService = new ScheduledThreadPoolExecutor(1);
        executorService.scheduleAtFixedRate(new Runnable()
        {
            @Override
            public void run()
            {
                    File file = new File(fileName);
                    if (file.exists())
                    {
                        Log.debug("creating new file");
                        openFileWriter(file);
                    }

            }
        }, fileIntervalInSeconds, fileIntervalInSeconds, TimeUnit.SECONDS);
    }
private void openFileWriter() throws FileSystemNotificationException
{

        // 1 - close exist writer
        writer.close();
        // 2 - rename to backup file name
          ...
        // 3 - create new file      
        FileWriter writerFile = new FileWriter(fileName, true);
        writer = new PrintWriter(writerFile);

}

我一直在向文件写入警报消息:

private synchronized void writeLine(String line) throws InterruptedException
{
    writer.println(line);
}

我的问题是:

  1. 我如何确保在未关闭时使用 writer?(writer.close())
  2. 在开始写入之前,我如何等待 ScheduledThreadPoolExecutor 完成创建文件
4

4 回答 4

4

如何在写入文件之前检查文件是否存在。无需后台线程或同步

private synchronized void writeLine(String line) {
    if (!file.exists())
       reopenWritingFile();
    writer.println(line);
}
于 2013-11-11T14:11:38.967 回答
0

您有两种选择:

  1. 在关闭旧作家之前创建新作家。
  2. 在关闭写入时检查的写入器之前建立一个锁。

例子:

volatile PrintWriter writer;
ReadWriteLock lock = new ReentrantReadWriteLock();
Lock writeLock = lock.writeLock();
Lock readLock = lock.readLock();

private void openFileWriterWithLock() throws IOException {

  if (writeLock.tryLock()) {
    try {
      // 1 - close exist writer
      writer.close();
      // 2 - rename to backup file name
      //...
      // 3 - create new file      
      FileWriter writerFile = new FileWriter(fileName, true);
      writer = new PrintWriter(writerFile);
    } finally {
      writeLock.unlock();
    }
  }

}

private synchronized void writeLineWithLock(String line) throws InterruptedException {
  readLock.lock();
  try {
    writer.println(line);
  } finally {
    readLock.unlock();
  }
}

private void openFileWriterWithoutLock() throws IOException {
  // 0. Note old file.
  PrintWriter oldWriter = writer;
  // 1. Create new file.
  FileWriter writerFile = new FileWriter(fileName, true);
  // 2. Swap the new one in.
  writer = new PrintWriter(writerFile);
  // 3 - close old writer
  oldWriter.close();
}

private synchronized void writeLineWithoutLock(String line) throws InterruptedException {
  writer.println(line);
}
于 2013-11-11T14:40:15.483 回答
0

您可以简单地在您的 write 方法中每小时创建一个新文件。时间检查会产生一些轻微的开销,但这应该可以忽略不计。下面的示例将每小时创建一个新的日志文件,并将时间(以毫秒为单位)添加到文件名的前面。您可以根据自己的需要格式化时间。

public class LogWriter {
    private long lastCreationTime;
    PrintWriter writer;
    String logFileName;

    public LogWriter(String logFileName) {
        this.logFileName = logFileName;
        createLogFile(logFileName);
    }

    private void createLogFile(String fileName) {
        if(writer != null) {
            writer.close();
        }
        lastCreationTime = System.currentTimeMillis();
        FileWriter writerFile;
        try {
            writerFile = new FileWriter(lastCreationTime + "_" + fileName, true);
            writer = new PrintWriter(writerFile);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private synchronized void writeLine(String line) {
        if(lastCreationTime < System.currentTimeMillis() - 3600000) {
            createLogFile(logFileName);
        }
        writer.write(line);
    }
}
于 2013-11-11T14:59:30.783 回答
0

有一个单独的线程来处理日志记录而不是那个相当复杂的结构怎么样?

public class Logger extends Thread {

private final LinkedBlockingQueue<String> linesToWrite = new LinkedBlockingQueue<>();
private final String filename;

private Logger(String filename) {
  super("Logging thread");
  this.filename = filename;
  this.setDaemon(true);
  this.setPriority(Thread.MIN_PRIORITY);
}

@Override
public void run() {
  try (BufferedWriter out = new BufferedWriter(new FileWriter(filename, true))) {

    String line;
    while (this.isInterrupted() == false) {
      line = linesToWrite.take();
      out.write(line);
      out.newLine();
      out.flush();
    }
  } catch (InterruptedException e) {
  } catch (IOException ex) {
    System.out.println("Failed to access log file: " + ex);
  }
}

public void log(final String line) {
  this.linesToWrite.add(line);
}

然后初始化记录器一次:

final Logger logger = new Logger("test.log");
logger.start();

然后你可以在任何地方以这样的线程安全方式使用它:

logger.log("Test message");

您不需要停止记录器,因为 Java 将使用 try 构造确保文件已正确关闭。但是,如果你愿意,你可以像这样停止它:

logger.interrupt();

现在您可以以单线程方式进行所有文件操作,因为任何时候都只有一个线程访问日志文件。

于 2013-11-11T16:08:25.023 回答