【问题标题】:read from a file that is actively being written to using Java [Improvement]从使用 Java 主动写入的文件中读取 [改进]
【发布时间】:2017-12-25 20:41:59
【问题描述】:

我想读取另一个应用程序/进程正在写入的文件。

我在另一个问题中找到的这段代码可以完成这项工作:它在写入文件时读取文件,并且只读取新内容。

即使没有数据添加到文件中也消耗大量CPU的问题。如何优化这段代码?

  • 使用计时器?或 thread.sleep 暂停?

要补充一点,我正在尝试编写的整个程序会实时读取文件并处理其内容。所以这意味着 thread.sleep 或计时器将暂停我的整个程序。我正在寻找的理想改进不是等待几秒钟,而是等待某个事件发生 => 添加了新数据。这可能吗?

public class FileReader {

    public static void main(String args[]) throws Exception {
        if(args.length>0){
            File file = new File(args[0]);
            System.out.println(file.getAbsolutePath());
            if(file.exists() && file.canRead()){
                long fileLength = file.length();
                readFile(file,0L);
                while(true){

                    if(fileLength<file.length()){
                        readFile(file,fileLength);
                        fileLength=file.length();
                    }
                }
            }
        }else{
            System.out.println("no file to read");
        }
    }

    public static void readFile(File file,Long fileLength) throws IOException {
        String line = null;

        BufferedReader in = new BufferedReader(new java.io.FileReader(file));
        in.skip(fileLength);
        while((line = in.readLine()) != null)
        {
            System.out.println(line);
        }
        in.close();
    }
}

【问题讨论】:

    标签: java multithreading file


    【解决方案1】:

    我正在寻找的理想改进不是等待几秒钟,而是 发生某个事件 => 添加新数据。这可能吗?

    最佳解决方案:数据推送

    生成内容的应用程序应通知其他应用程序,因为它可能会读取内容。

    您可以使用任何可以在两个不同应用程序之间传递信息的渠道。

    例如,通过使用编写器更新的特定文件来通知要读取的新内容。
    写入器可以在此文件中写入/覆盖更新日期,而读取器只有在自该日期以来未读取任何内容时才会读取数据文件。

    一种更强大但开销更大的方法可能是从阅读器端公开通知服务。
    为什么不是 REST 服务。
    这样,当新内容准备好时,作者可以通过服务通知读者。

    还要补充一点,我正在尝试编写的整个程序读取一个 实时文件并处理其内容。所以这意味着 thread.sleep 否则计时器将暂停我的整个程序。

    解决方法:由特定线程执行数据拉取

    您可能有一个多核 CPU。
    因此,请创建一个单独的线程来读取生成的文件,以允许您的应用程序的其他线程可以运行。
    此外,您还可以执行一些定期暂停:Thread.sleep() 以优化读取线程完成的核心使用。

    它可能看起来像:

    Thread readingThread = new Thread(new MyReadingProcessing());
    readingThread.start();
    

    其中MyReadingProcessingRunnable

    public class MyReadingProcessing implements Runnable{
    
         public void run(){
              while (true){
                   readFile(...);
                   try{
                      Thread.sleep(1000); // 1 second here but choose the deemed reasonable time according the metrics of your producer application
                   }  
                   catch(InterruptedException e){
                      Thread.currentThread().interrupt();
                   }
                   if (isAllReadFile()){ // condition to stop the reading process
                       return;
                   }
              }
         }
    }
    

    【讨论】:

    • 感谢您的回答。我不想专注于这两个应用程序。正如我之前提到的,上面的代码完成了发送通知的工作。我要解决的问题是减少应用程序的开销,因为线程永远不会暂停。
    • 不客气。我明白。我更新了。让我看看有没有用
    • 感谢您的回答:)。
    【解决方案2】:

    在目录条目更改时使用WatchService 代替繁忙的等待循环。

    Path path = Paths.get("...");
    try (WatchService watchService =
                path.getFileSystem().newWatchService()) {
        WatchKey watchKey = path.register(watchService,
                StandardWatchEventKinds.ENTRY_MODIFY);
        for (;;) { // watchKey.poll with timeout, or take, blocking
            WatchKey taken = watchService.take();
            for (WatchEvent<?> event : taken.pollEvents()) {
                Path changedPath = (Path) event.context();
                if (changedPath.equals(path)) {
                    ...
                }
            }
            boolean valid = taken.reset();
            if (!valid) {
                ... unregistered
            }
        }
    }
    

    请注意,以上内容必须适应使用 poll 或 take。

    【讨论】:

      猜你喜欢
      • 2011-12-18
      • 2010-09-05
      • 2018-09-06
      • 2011-07-27
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 2016-08-21
      • 1970-01-01
      相关资源
      最近更新 更多