Java中的并发读/写文件
Posted
技术标签:
【中文标题】Java中的并发读/写文件【英文标题】:Concurrent read/write file in Java 【发布时间】:2016-12-10 19:27:33 【问题描述】:我必须从我的 Java 应用程序中读取一个文本文件。
该文件包含许多行,并且该文件每 X 分钟从外部未知应用程序更新一次,该应用程序将新行附加到文件中。
我必须从文件中读取所有行,然后我必须删除我刚刚读取的所有记录。
是否可以让我逐行读取文件,删除我读取的每一行,同时允许外部应用程序将其他行附加到文件中?
此文件位于 Samba 共享文件夹中,因此我使用 jCIFS 来读取/写入文件和 BufferedReader Java 类。
提前致谢
【问题讨论】:
更改由不受您控制的应用程序写入的文件是个坏主意。为什么需要删除?也许只保留一个标记来记录您到目前为止已阅读的行数就足够了,而无需更改文件? 这就是Socket Writing
和 RESTful POST
命令的用途。
@RealSkeptic 我需要删除或更新我刚刚阅读的行,因为我认为这是将行标记为“已处理”的最简单方法。处理完一行后,我必须存储在 mysql 表中,这样我就不需要再将行留在文件中了。
@SusannahPotts 我知道,但不幸的是外部应用程序不在我的控制之下:)
@RobertoMilani 这是真的,我只是无法自拔。
【参考方案1】:
问题是我们不知道外部应用程序如何写入和/或重用此文件。如果您在外部应用程序使用计数器正确运行时删除行,则可能会出现问题...
除非您知道其他应用的工作原理,否则没有好的解决方案。
【讨论】:
【参考方案2】:我不知道你的问题的完美解决方案,但我会以不同的方式解决它:
重命名文件(给它一个带有时间戳的唯一名称) appender 作业随后会自动重新创建它 处理您的时间戳文件(无需删除它们,将它们保留在原处,以便您以后检查发生了什么)【讨论】:
"appender 作业将自动重新创建它" -> 不确定,例如它是否仅在启动时执行。 @N0un 不确定,是的,但值得一试。 @SeanPatrickFloyd 除非客户希望他们的应用程序在生产环境中以非常特定的方式执行此操作。 @SusannahPotts 好吧,归根结底,互相交谈可以挽救生命【参考方案3】:是否可以让我逐行读取文件,删除我读取的每一行,同时允许外部应用程序将其他行附加到文件中?
是的,您可以打开同一个文件以从多个进程读取和写入。例如,在 Linux 中,您将为同一个文件获得两个单独的 file descriptors。对于小于PIPE_BUF, or 4096 bytes in Linux, 的文件写入,可以安全地假设操作是原子的,这意味着内核正在处理锁定和解锁以防止出现竞争条件。
假设进程 A 正在写入文件并以 APPEND 的形式打开它,那么每次进程 A 告诉内核 write()
它都会首先查找文件的大小(文件末尾)。这意味着您可以安全地从进程 B 中删除文件中的数据,只要它是在进程 A 的写操作之间完成的。只要进程 A 的写操作不超过 PIPE_BUF,Linux 就保证它们是原子的,即进程 A 可以进行垃圾写操作,进程 B 可以不断删除/写入数据,不会产生任何奇怪的行为。
Java 为您提供implemented File Locks。但重要的是要理解这只是“建议”,而不是“强制性”。 Java 不强制执行此限制,两个进程必须执行检查以查看另一个进程是否持有锁。
【讨论】:
锁定? Linux会处理吗?你能出示证实这一断言的文件吗? @RealSkeptic 我找不到来自 Linus Torvald 的官方帖子。但如果你用谷歌搜索,你会在书籍、网站和操作系统课程中找到大量证据。 Here is one example。另外,更多*** support。 对于 PIPE_BUF 大小或 Linux 中 4096 字节以下的文件写入,可以安全地假设操作是原子的,这意味着内核正在处理锁定和解锁以防止竞争条件。 通常是正确的 - 但在这种情况下,它是一个共享文件系统,显然正在通过网络连接进行更新。从正在写入的文件中读取数据很难可靠地使用本地文件上的低级 C 代码进行 - 在 Java 中通过网络和在写入过程中同时修改文件将充其量是极其困难的。 尤其是输入通常被缓冲到一个未知的大小,很可能在这个限制之后。 @RealSkeptic 输入在高级缓存,如编程语言或网络协议。内核并不是那么无忧无虑,因为准确性和原子性非常重要。内核不会缓冲这些写入,它要么阻塞直到解锁,要么返回一个 errno,这取决于是否设置了 O_NONBLOCK 标志。以上是关于Java中的并发读/写文件的主要内容,如果未能解决你的问题,请参考以下文章