如何在写入未完成时检测到我正在读取文件?

时间:2012-07-04 16:39:23

标签: java multithreading file-io concurrency java-io

我们有一个多线程程序,它执行以下操作:

thread_1是硬盘的侦听器,用于检测创建的​​新文件。我们在Java 7中使用WatchService api。当另一个程序创建一个新文件时,thread_1检测并获取它并将其放到PriorityBlockingQueue ex:

priorityBlockingQueue.add(FileObject)

FileObjComparator是一个自定义对象实现比较器。它按照fileCreatedTime中创建的时间和FileObject字段进行排序。检测到此文件时,我从系统时间得到:

 public int compare(FileObject o1, FileObject o2) {
        return o1.getFileCreatedTime().compareTo(o2.getFileCreatedTime());
    }

priorityBlockingQueue初始化为:

DataFileQueue.priorityBlockingQueue = new PriorityBlockingQueue<FileObject>(100000, new FileObjComparator());

Thread_2将在此priorityBlockingQueue

中的最后一个文件旁边处理此问题
if(priorityBlockingQueue.size) > 1)
   process(priorityBlockingQueue.poll());

2个线程并行运行,但是当我处理大量文件时,有时Thread_2处理文件正在编写。我检测到这一点是因为重新检查内容文件和处理结果。

此程序在Centos 6.2上运行,此硬盘分区以异步模式安装。谢谢你的帮助。

4 个答案:

答案 0 :(得分:2)

如果你真的正在处理倒数第二个文件,那么我很惊讶它的大小正在增长,除非多个进程或线程正在生成输入文件。确保创建文件的其他进程刷新并在编写下一个文件之前关闭每个文件

  • 您可以在块中读取文件,然后返回一段时间以查看是否有任何其他数据已添加到文件中,并使用RandomAccessFile进行处理。如果您逐行读取文件,则不幸的是您需要自己进行分页。如果文件是基于行的,那么您应该确保行终止字符关闭文件。

  • 您可以尝试的另一件事是延迟文件处理,让文件系统刷新其缓冲区。丑陋和不可靠但可能是必要的。

  • 如果您可以调整输出过程,那么您可以使用魔术字符串结束文件,然后在看到魔术字符串之前不处理该文件。

  • 您可以让进程写入文件,将文件大小写入带有“.size”扩展名(或其他内容)的单独文件中。大小文件可以帮助您验证您是否正在读取正确数量的字符。

  • 如果您在~unix系统上运行,则在开始从文件读取以同步文件系统之前,尝试另一件事是Runtime.exec("/bin/sync");。问题是对此的支持高度依赖于操作系统。它也可以成为真正的性能杀手。他是我Mac上的手册页:

      

    可以调用同步实用程序以确保所有磁盘写入都已完成

答案 1 :(得分:1)

您可以尝试使用信号量来组织对每个文件的访问,这样就不会有文件 一次由多个线程写入。我认为每个文件对象都应该有它 拥有自己的信号量,每个线程都应该在写入之前尝试获取信号量 文件。

答案 2 :(得分:0)

您的比较者应按上次修改时间排序,而不是创建时间。我不知道你怎么知道例如在ordr A,B中打开的两个文件将以相同的顺序完全写入,除非你肯定知道文件生成是严格顺序的。你没有这么说。

答案 3 :(得分:-2)

编辑更详细的答案。

问题是......

你写了

它按FileObject中的创建时间和fileCreatedTime字段排序,检测到此文件时从系统时间得到: ....

thread_1是硬盘的侦听器,用于检测创建的​​新文件。我们在Java 7中使用WatchService api。当另一个程序创建新文件时。 ... thread_1检测并获取将其置于PriorityBlockingQueue ex

  • 创建时间和“文件写入完成时间”可能会有很大差异。 (取决于文件大小)。

例如:

打开文件管理器。开始下载大约60 MB的文件。请注意创建时间。大约3分钟后看最后一次。

检测新文件,查看创建时间是错误时刻到“将其置于PriorityBlockingQueue ex :”

thraed_1必须等到文件写入完成。然后他可以把它“一个PriorityBlockingQueue ex :”

如何检测文件上的写入已完成?

3没有太复杂的选项

  • a。)比较文件已创建且文件已准备好。
  • b。)观察文件大小稳定增长。如果 文件完成后停止增长。
  • c。)尝试将其移至临时文件夹。

您更喜欢什么?

我更喜欢解决方案c。

无法移动为写入而打开的文件。 第三方程序关闭文件后,可以移动它。

必要的步骤。

  • thread_1正在通过第三方程序来查看创建的文件。
  • thread_1尝试将其移动到xyztmp文件夹(每10或20或......秒)。
  • thread_1在中寻找新的传入文件 xyztmp文件夹并将其放入PriorityBlockingQueue ex。

解决方案b。更复杂。

thread_1将传入的文件名和大小放在控件数组中,比较3-5次。(每5秒或更长时间)。

阵列

(filenamexyz.dat, size1, size2, size3, ...).
(filenameabc.dat, size1, size2, size3, ...).
(filenamefgh.dat, size1, size2, size3, ...).
....

如果按名称标识的文件每5个比较尺寸相同,则第三方程序已完成对此文件的写入。

现在可以将它放到PriorityBlockingQueue ex:

让我们一步一步看

我们假设thread.size为2时启动了thread_2!

  • 第三方程序逐个开始写文件。
  • 第三方程序开始编写FILE_1。
  • thread_1检测创建的​​FILE_1,将其放入列表中。
  • 第三方程序写完了FILE_1。
  • 第三方程序开始编写FILE_2。
  • thread_1检测到创建的FILE_2,将其放入列表中。
  • if(priorityBlockingQueue.size)&gt; 1)TRUE
  • thread_2以读取和处理列表FILE_1中的第一个文件开始。

  • 第三方程序写完了FILE_2。
  • 第三方程序开始编写FILE_3。
  • thread_1检测到创建的FILE_3,将其放入列表中。
  • thread_2 finshed处理FILE_1。
  • thread_2以列表FILE_2中的下一个文件开始。

  • 第三方程序写完了FILE_3。
  • 第三方程序开始编写FILE_4。
  • thread_1检测到创建的FILE_4,将其放入列表中。
  • thread_2 finshed处理FILE_2。
  • thread_2以列表FILE_3中的下一个文件开始。

    现在发生故障


  • 第三方程序写完了FILE_4。
  • 第三方程序开始编写FILE_5。 (FILE_5大于FILE_4)。
  • thread_1检测到创建的FILE_5,将其放入列表中。
  • thread_2 finshed处理FILE_3。
  • thread_2以列表FILE_4中的下一个文件开始。
  • thread_2 finshed处理FILE_4。
  • thread_2从列表FILE_5中的下一个文件开始。
  • thread_2 finshed处理FILE_5。
  • 第三方程序写完了FILE_5。

如果第三方程序写入的文件较大且需要更多时间来编写,则thread_2已完成读取较小的FILE_4。

thread_2从列表中取出下一个文件--FILE_5,无论文件是否可以读取。

FILE_5是第三方程序仍然写入的文件。 FILE_5是thread_2正在读取和处理的文件。字节thread_2 读取仅 第三方程序已写入的字节