主题
文件存储作为数据持久化存储方式之一,很多程序中会将结果数据保存在文件中的情况,如xml文件。而文件写完成才代表一个完整的数据结构生成。
- 你是否遇到过通过ftp传输文件,接收端需要对文件进行解析处理。结果文件未上传完毕,接收端软件就对文件进行解析,造成解析失败的问题?
- 你是否遇到过通过文件方式进行数据交互的程序,文件还未完全生成就开始解析,造成交互失败的问题?
如果有,那么这篇文章或许会有一点帮助。
文件存储过程
文件的生成过程主要遵循以下几个步骤:
- 创建文件,即在硬盘内创建一个带有文件名、文件类型、创建时间等信息戳的文件。
- 打开文件,文件创建后打开获取到文件输出流。
- 向文件输出流写入文件内容的字节数据。输出流拥有固定大小的缓冲区,写入的内容先存储在这个缓冲区内,当缓冲区溢出、输出流flush()或者文件close()的时候,输出流将会把缓冲区的内容写入到磁盘内
- 关闭文件,即在写入文件内容后关闭文件。
原理
利用MS 的ReadDirectoryChangesW函数,监听文件目录。当文件创建、变化和重命名的时候,该函数会触发对应的消息,客户端只需要做对应消息的响应即可。
BOOL WINAPI ReadDirectoryChangesW(
__in HANDLE hDirectory,//指向监控目录的句柄,可以用CreatFile生成
__in_out LPVOID lpBuffer,//存储修改信息的首地址
__in DWORD nBufferLength,//分配的存储修改信息的空间的长度
__in BOOL bWatchSubtree,//TRUE则监控子目录,FALSE则不监控
__in DWORD dwNotifyFilter,//通知条件
__out LPDWORD lpBytesReturned,//该函数返回信息的字节数,也就是存到lpBuffer中的内容的字节数
__in LPOVERLAPPED lpOverlapped,//一个指向OVERLAPPED结构的指针,他在同步调用时提供数据供使用,否则他就为NULL
__in LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine//当操作结束或被取消或者线程进入等待状态时的一个指向将被调用操作的指针
)
如何知道一个文件是否已经写完成
文件写入完成后close()才会触发FILE_NOTIFY_CHANGE_LAST_WRITE消息,因此只要监听此消息即可监控到文件是否完成。1. 当文件输出流写入的时候,数据只会写到输出流缓冲区,当缓冲区溢出、flush()、close()或crash的时候数据会写入到硬盘缓冲区。操作系统写入磁盘的时候,先写入到硬盘缓冲区内,硬盘缓冲区flush()后写入磁盘。因此,当输出流flush的时候并不会触发到FILE_NOTIFY_CHANGE_LAST_WRITE。
2. 只有硬盘缓冲区flush()之后数据才会被写入到硬盘,进而触发文件内容变化的消息。这一点和大部分人想象输出流flush()之后数据就会写入硬盘,进而触发文件内容变化消息的想法有点不一样。
3. FILE_NOTIFY_CHANGE_LAST_WRITE消息的触发并不能保证,因为这一个步骤是由操作系统的特性所决定。已知当文件close()或crash的时候会触发OnFileChange事件,其它像操作系统检测到输出流缓冲区内容为空的时候也会触发。而一般文件写入具有连续性,除非文件close()掉不会出现这种输出流缓冲区内容为空的情况。
因此,只需要利用ReadDirectoryChangesW监听FILE_NOTIFY_CHANGE_LAST_WRITE消息即可监听文件是否已经写完成,而不必担心输出流flush()时多次触发文件内容发生变化消息的问题。
Filter Value | Meaning |
---|---|
FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 | Any change to the last write-time of files in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change to the last write-time only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed. |