我必须开发一个应用程序来解析日志文件并将特定数据发送到服务器。它必须在 Linux 和 Windows 上运行。

当我想测试日志滚动系统(它将 .1 附加到名称后会创建一个同名的新系统)时,就会出现问题。在 Windows 上(尚未在 Linux 上测试)我无法重命名使用 std::ifstream() (独占访问?)打开的文件,即使我在“输入模式”(ios::in)下打开它。

是否有跨平台方式以非独占方式打开文件?

有帮助吗?

解决方案

有没有一种方法以非独占方式打开文件,

是的,使用 Win32,将各种 FILE_SHARE_Xxxx 标志传递给 CreateFile。

是跨平台的吗?

不,它需要特定于平台的代码。

由于恼人的向后兼容性问题(DOS 应用程序是单任务的,假设没有任何东西可以从它们下面删除文件,即他们可以先 fclose() 然后 fopen() ,不会出现任何问题;Win16保留了这个假设是为了让移植DOS应用程序更容易,Win32保留这个假设是为了让移植Win16应用程序更容易,这很糟糕),Windows默认以独占方式打开文件。

底层操作系统基础设施支持删除/重命名打开的文件(尽管我相信它确实有内存映射文件无法删除的限制,我认为这不是 *nix 上的限制),但默认的打开语义不支持。

C++ 没有任何这些概念;C++操作环境与DOS操作环境非常相似——没有其他应用程序同时运行,因此不需要控制文件共享。

其他提示

需要独占模式的不是读取操作,而是重命名,因为这本质上与将文件移动到新位置相同。

我不确定,但我认为这是不可能的。请尝试复制该文件,然后在不再读取旧文件时删除/替换该文件。

Win32 文件系统语义要求您重命名的文件在重命名时不能打开(以任何模式)。您需要关闭该文件,重命名它,然后创建新的日志文件。

Unix 文件系统语义允许您重命名打开的文件,因为文件名只是指向 inode 的指针。

如果您只读取文件,我知道可以使用 windows api CreateFile 来完成。只需指定file_share_delete | file_share_read | file_share_write作为DWSHAREMODE的输入。

不幸的是,这不是跨平台的。但 Linux 可能也有类似的东西。

有关 CreateFile 的更多信息,请参阅 msdn.

编辑:简单说明一下 Greg Hewgill 的评论。我刚刚测试了 FILE_SHARE* 的东西(也100%确定)。如果您以只读方式打开并指定 FILE_SHARE* 参数,则可以在 Windows 中删除和重命名文件。

我会确保你不要让文件保持打开状态。例如,如果您的应用程序崩溃,这会导致奇怪的事情。我会做什么:

  1. 抽象(读/写/滚动到一个新文件)到一个类中,并在您想要滚动到该类中的新文件时安排关闭该文件。(这是最简洁的方法,因为您已经有了滚动代码,所以您已经成功了一半。)
  2. 如果您必须有多个读/写访问点,需要 fstreams 的所有功能并且不想编写完整的包装器,那么我能想到的唯一跨平台解决方案就是在不需要时始终关闭文件,并让翻转代码在需要翻转时尝试多次获取对该文件的独占访问权限,然后再放弃。
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top