【问题标题】:How to check whether there's enough space before WriteFile in c in windows?如何检查Windows中c中WriteFile之前是否有足够的空间?
【发布时间】:2010-09-11 04:41:01
【问题描述】:
  hPipe = CreateNamedPipe( 
     lpszPipename,             // pipe name 
     PIPE_ACCESS_DUPLEX,       // read/write access 
     PIPE_TYPE_MESSAGE |       // message type pipe 
     PIPE_READMODE_MESSAGE |   // message-read mode 
     PIPE_WAIT,                // blocking mode 
     PIPE_UNLIMITED_INSTANCES, // max. instances  
     100,                  // output buffer size 
     100,                  // input buffer size 
     0,                        // client time-out 
     NULL);                    // default security attribute 

  DWORD totalBytesAvailable; 
  PeekNamedPipe( 
    hPipe ,                // __in       HANDLE hNamedPipe, 
    NULL,                  // __out_opt  LPVOID lpBuffer, 
    0,                     // __in       DWORD nBufferSize, 
    NULL,                  // __out_opt  LPDWORD lpBytesRead, 
    &totalBytesAvailable,  // __out_opt  LPDWORD lpTotalBytesAvail, 
    NULL                   // __out_opt  LPDWORD lpBytesLeftThisMessage 
  ); 
    if(totalBytesAvailable allows)
    WriteFile( tmp_pipe, pBuffer, BufferLen, &dwWritten, NULL );

如您所见,我使用PeekNamedPipe 来获取可用空间,但事实证明totalBytesAvailable 始终是0,如何正确操作?

【问题讨论】:

  • @Frerich - 当然,我在 SO 度过的时间。它知道它对 Alan 没有任何价值,但我当然在乎。考虑到它的价格,懒惰标记答案是愚蠢的。
  • 我猜你正在写信给hPipe,而不是一些未知的tmp_pipe

标签: c windows writefile


【解决方案1】:

恕我直言,这种在实际写入之前检查可用空间的方法是有缺陷的。

在实际写入执行时,可能会发生其他一些并行运行的进程会填满可用磁盘空间的最后一位,从而导致您的 WriteFile 失败。

我只会依赖 WriteFile 返回的内容。

【讨论】:

  • 我不能依赖WriteFile,它会挂掉的!而且我的情况下不用担心多线程的情况。
  • 不,这是正确的做法。其他进程共享磁盘,您不能保证它们不会填满您假定声称的空白空间。如果发生错误(例如没有磁盘空间),调用将不会挂起。通话后您应该会收到类似GetLastError() == ERROR_DISK_FULL 的信息。
  • 如果WriteFile 没有剩余空间,通话将挂起,这是我要避免的。
【解决方案2】:

lpTotalBytesAvail 参数中返回的值是可以从管道读取,而不是写入 到管道的字节数。为您提供信息以分配从管道读取数据的缓冲区。

在写入管道(或任何 NT Krenel 句柄)时处理错误的正确方法是简单地执行对 WriteFile() 的调用并处理返回的任何错误。

检查然后写入模式无效,并且会产生错误 *永远不会在你的测试中发生 *有时会在现场发生 * ...因此很难诊断和调试 * 最重要的是,此类错误会惹恼您的用户。

原因是目标的状态可以在检查和实际写入之间发生变化。这意味着调用 WriteFile() 的代码无论如何都必须检查错误。这意味着在调用 WriteFile() 之前检查前置条件只是没有提供任何价值的额外代码。

这种模式无效的原因是 Windows(以及所有其他操作系统 - 这不仅仅是 Windows 的东西) - 不能将“检查”和“写入”视为原子操作。底层操作系统是完全异步,调用之间可能会发生很多事情。

因此,如果您简单地调用 WriteFile() 并做好错误处理,您的代码会更简单并且更可靠。

-Foredecker

【讨论】:

    【解决方案3】:

    您无法以自己的方式确定可用空间。

    虽然这个问题是关于管道的,但人们可能会在寻找有关发现可用磁盘空间的一般信息时遇到它,如果管道最终是一个文件,这可能仍然有用:

    知识库文章"Understanding and Using GetDiskFreeSpace and GetDiskFreeSpaceEx" 提供了有关确定可用磁盘空间的相关 Win32 API 的信息,或直接转到此处的 API 文档:

    【讨论】:

    • 我意识到,将编辑澄清。不过,这个问题的表述方式可能会引导那些正在寻找一种方法来找到可用磁盘空间的人,所以我认为它仍然很有用。
    【解决方案4】:

    设置 PIPE_NOWAIT 而不是 PIPE_WAIT。如果管道中没有足够的空间,WriteFile 将立即返回。
    对于 I/O 缓冲区大小来说,100 似乎相当小!你的烟斗是干什么用的?

    【讨论】:

    • 我是这么说的,不是吗?
    • 那你就不知道WriteFile是否成功了。
    • 如果 WriteFile 不成功,它会返回一个错误代码,而不是挂起。这就是OP想要的。 (如果我理解这个问题,这里似乎没有涉及实际文件。)
    【解决方案5】:

    关于 check then write 的脆弱性的 cmets 是正确的。

    微软不推荐PIPE_NOWAIT的建议。

    使用重叠的 I/O。然后 WriteFile() 将始终立即返回,如果数据没有立即写入管道,将返回 FALSE 和 ERROR_IO_PENDING。在这种情况下,您调用 CancelIo() 来取消尝试的 WriteFile()。请记住,在调用 CancelIo() 之后,您必须调用 GetOverlappedResult(),因为重叠的 WriteFile() 仍然需要完成 - 即使它会失败并且如果在它之前释放 OVERLAPPED 结构,您将有堆栈损坏。

    顺便说一句,你应该接受这个问题的答案。一年多了!

    【讨论】:

      【解决方案6】:

      创建一个线程来处理写入管道,这样写入器挂起,等待客户端清空管道不是问题?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-29
        • 1970-01-01
        相关资源
        最近更新 更多