Java 保持文件句柄打开,或根据需要重新打开?

Java 保持文件句柄打开,或根据需要重新打开?,java,Java,我有一个处理特定二进制协议的TCP服务器。有些请求包含要写入文件的大量数据。服务器使用NIO框架(netty),并在其中包含逻辑来处理已分解为多个框架的消息 当一个单独的帧进入时,如果该帧中的数据要写入一个文件,那么我打开该文件并写入数据。即使流尚未完成,并且我希望将另一个包含数据的帧附加到同一文件中,我当前也会关闭该文件,直到收到下一个帧,此时我会重新打开它并附加附加数据 我之所以选择这种方法,是因为它似乎是避免留下打开的文件句柄的最安全的方法,并且由于一些错误而没有关闭它们,但是,我担心这会

我有一个处理特定二进制协议的TCP服务器。有些请求包含要写入文件的大量数据。服务器使用NIO框架(netty),并在其中包含逻辑来处理已分解为多个框架的消息

当一个单独的帧进入时,如果该帧中的数据要写入一个文件,那么我打开该文件并写入数据。即使流尚未完成,并且我希望将另一个包含数据的帧附加到同一文件中,我当前也会关闭该文件,直到收到下一个帧,此时我会重新打开它并附加附加数据


我之所以选择这种方法,是因为它似乎是避免留下打开的文件句柄的最安全的方法,并且由于一些错误而没有关闭它们,但是,我担心这会对性能产生负面影响。让filehandles保持打开状态(因此保留对打开的fileOutStream或通道的引用)是更好的做法(在本例中是最佳做法)?打开文件句柄的数量是否存在资源限制问题?

建立TCP连接握手等需要10到100毫秒,因此理想情况下您不会经常这样做。看看你的解释,我肯定会保持连接打开,因为如果你继续创建一个新的连接,你的有效带宽将非常有限

请记住,无论如何,连接都将在关闭时关闭,如果对象离开定义的范围,连接将在gc时关闭。看看你是否能把连接放在一个作用域中去利用它

更新


刚才看到评论说你指的是磁盘。不过,同样的论点也适用,虽然不太适用,因为打开一个文件通常只需要几毫秒——但可能仍在10毫秒左右。

IMHO,我认为最好让文件句柄保持打开状态

多年来,我一直在寻找通过套接字传输文件的程序,我还从未见过一个程序反复关闭和打开目标文件

此外,我可能会将传入流写入一个临时文件名,并仅在完成时将其重命名为正确的文件名。

答案:

  • 创建处理以下内容的factory类:
    • 如果给定文件仍处于打开状态,则从池返回打开的filehandle
    • 如果没有可用的文件句柄,请关闭最旧的(最近使用最少的)文件句柄 (对于您的系统来说,某些可调上限似乎是合理的)
    • 在相对较长的时间内(30秒?一分钟?)触发计时器以关闭文件句柄 已经有一段时间没用了
差不多

    /* initialize once */
    FilePool.setLimit (maxFiles);

    /* called often */
    FilePool.getFile(ident);
    FilePool.closeFile(handle);

    /* protected/internal/… */
    boolean FilePool.reachedLimit ();
    FilePool.closeLeastRecentlyUsed (number);
    OnTimer → FilePool.closeIdleFiles (duration);
当然,这只有在文件打开/关闭实际上是在浪费时间的情况下才有意义

如果您可以对现有系统进行负载测试,并尝试分析两者所需的时间
当然,您可以更好地处理您的特定需求。

您考虑的是哪种卷(同时打开的文件)?您多久接收一次帧-或多或少是流式/实时的?还是长时间耽搁?在这方面,扮演角色的Rlimit往往有数百(或数千)人。打开/关闭文件与帧间延迟的时间可能是一个值得考虑的问题。所有这些都是很好的点@ BrPoCoCK:在大多数此类问题中,真正需要考虑的是工作量。@ BrpCoCK卷有望不断增加,所以我只是想找到一个能提供最佳可扩展性的最佳点。帧是流式/实时的(所讨论的帧只是单个TCP数据包)。我试图在我认为最安全、最可扩展的(关闭文件)和可能表现最好的(保持打开)之间取得平衡。他打开的是磁盘文件,而不是TCP流。那些程序服务器是处理多个连接还是单连接/低容量?谢谢,我想这就是我要做的,经过一些小的修改(或者可能只是不同的命名)。我将使它成为一个非静态池对象,它根据文件键返回一个OutputStream(这里可能有一些匹配文件对象的问题,我将忽略..)。然后,它可以返回缓存的流或您实际指示的新打开的流,以及其他池管理功能。