是否有必要使用 FileLock 来避免同时出现读写或写入问题?

Is using FileLock necessary to avoid issues with Reading & Writing or Writing & Writing at the same time?

我正在设计一个应用程序,其主线程通过读写 .txt 文件与它进行交互。

此应用程序还有一个后台 IntentService 将读取和写入此文件。

我需要能够读入一个文件,并用新数据将其写回,同时确保另一个线程没有在这两个步骤之间更改文件数据。

我认为 FileLock 是我想要的,但是当我开始读取文件时无法锁定文件,因为 InputFileStream.getChannel().lock() 给出了一个异常。 (NonWritableChannelException).

我希望代码像这样:

File theFile = new File(file.txt);
FileInputStream in = new FileInputStream(theFile);

//should block here if it can't immediately lock
FileLock fileLock = in.getChannel().lock(); 

String inString = "";

int content;
while((content = in.read()) != -1){
    inString += Character.toString(((char) content));
 }
in.close();

inString += "new data";

out = new FileOutputStream(file);

out.write(finalString.getBytes());

 out.flush();
 out.close();

//releases the lock
fileLock.release();

我意识到可能可行的一个方案是使用 RandomAccessFile。因为在读取这些内容时,你可以声明它们 "rw" 权限(读写),所以你可以使用 .getChannel().lock() 但我想在深入研究之前我会问社区。

使用随机访问文件可能会导致性能下降。

按照这个 link - http://docs.oracle.com/javase/6/docs/api/java/io/RandomAccessFile.html#RandomAccessFile%28java.io.File,%20java.lang.String%29

"rws"   Open for reading and writing, as with "rw", and also require that every update to the file's content or metadata be written synchronously to the underlying storage device.
"rwd"   Open for reading and writing, as with "rw", and also require that every update to the file's content be written synchronously to the underlying storage device. 

如果将文件内容写入设备,将比其他方法慢得多。

此外,就您的 NonWritableChannelException 而言,它的发生是因为您试图锁定输入流。如果要加锁,需要打开文件进行写入。

希望对您有所帮助。

一般来说,对于单进程应用程序(大多数 Android 应用程序都是),线程同步是可行的方法,而不是文件系统级锁定。

除此之外,一般来说,您希望最小化磁盘 I/O,因为那样很慢。

特别是对于小文件,使用由文件支持的内存缓存。您的服务更新文件并使用进程内事件总线(LocalBroadcastManager、greenrobot 的 EventBus、Square 的 Otto)让 UI 层知道数据已更改(如果它当前存在)。 UI 层侧重于为数据使用内存缓存。

您唯一需要读取文件的时间是您的进程重新启动时,如果您在执行写入的同一个 IntentService 中执行此操作,I/O 会自动序列化。如果您的 UI 在启动时检测到进程内缓存为空,它只会发送一条命令来启动服务以读取该缓存。该服务再次使用事件总线让 UI 层知道数据现在可以使用了。

通过这种方式,您可以将磁盘读取减少到所需的最低限度,并且可以同步磁盘 I/O(IntentService 仅使用一个线程,如果有多个命令进入,则有一个工作队列同时),因此您不必担心您的应用程序的一部分会破坏应用程序其余部分的功能。