【问题标题】:How to close file in C that is already opened如何关闭已经打开的C文件
【发布时间】:2013-03-07 07:09:22
【问题描述】:

我正在编写应用程序来读取 DICOM 文件,我必须使用其他库来执行此操作。我发现库会打开文件,但完成后不会关闭文件。而且该库不是开源的。我知道在 Linux 中打开文件的限制是 1024,我可以更改这个数字。但我不想这样做。我喜欢关闭库打开的文件。如果我知道它正在打开,如何在 C 中关闭文件。我正在使用从http://cbi.nyu.edu/software/dinifti.php 获得的 DICOM2NII 库。 这是打开文件的代码,但它没有关闭

bool DICOMImage::OpenFile(const char *path)
{
    bool retValue = true;
    DCM_Objects handle_;
    unsigned long options = DCM_ORDERLITTLEENDIAN | DCM_FORMATCONVERSION | DCM_VRMASK;
    // Try opening as PART10, if it fails it's might be bcause it does not have
    // a preable and the try it that way
    if ( DCM_OpenFile(path, options | DCM_PART10FILE, &handle_) != DCM_NORMAL )
    {
        DCM_CloseObject(&handle_);
        COND_PopCondition(TRUE);
        if ( DCM_OpenFile(path, options, &handle_) != DCM_NORMAL )
        {    
          retValue = false;
        }
        else
          retValue=true;
    }

    return retValue;
}

【问题讨论】:

  • 库是否没有提供一个单独的函数来在你完成文件时关闭它们?
  • 是的。我在这个头文件中找到但没有。这是主要问题
  • 看起来该库的源代码可用 (ftp.erl.wustl.edu/pub/dicom/software/ctn)。看起来DCM_OpenFile() 在返回DCM_FILEACCESSERROR 错误时可能会泄漏文件句柄,但只有在调用fstat() 失败或文件大小大于INT_MAX 时才会发生这种情况(这就是你'遇到?)。顺便说一句:在我看来 DCM_OpenFile() 的名字很糟糕,因为它所做的不仅仅是打开文件(事实上,完成后通常会关闭文件)。

标签: c++ c


【解决方案1】:

在你的DICOMImage 类中,添加一个成员

DCM_OBJECT *handle_;

在你的析构函数中关闭文件

DICOMImage::DICOMImage() : handle_(0) { ... }

DICOMImage::~DICOMImage() {
    if (handle_ != 0)
        DCM_CloseObject(&handle_);
}

当然也可以在DICOMImage::OpenFile() 中使用这个成员handle_

【讨论】:

    【解决方案2】:

    您可以首先测试所有文件描述符,通过对从 0 到 getdtablesize() 的每个 fd 执行虚拟 fcntl(fd, F_GETFD) 来查看哪些文件描述符正在使用中。当库函数返回时,将再打开一个 fd,您可以使用 close() 关闭它。您也可以在之前未打开的所有内容上调用close(fd),其中一个会成功(您可以在搜索中停止该点)。

    很可能您可以对第一个未使用的 fd 进行初始探测,并且库最终会使用该 fd,前提是它不会做任何比打开一个文件更复杂的事情。如果它打开多个文件或使用dup(),它可能会在其他地方结束。

    拼出来:

    #include <iostream>
    #include <vector>
    #include <unistd.h>
    #include <fcntl.h>
    
    std::vector<bool> getOpenFileMap()
    {
        int limit = getdtablesize();
        std::vector<bool> result(limit);
    
        for (int fd = 0; fd < limit; ++fd)
            result[fd] = fcntl(fd, F_GETFD) != -1;
        return result;
    }
    
    void closeOpenedFiles(const std::vector<bool> &existing)
    {
        int limit = existing.size();
        for (int fd = 0; fd < limit; ++fd)
            if (!existing[fd])
                close(fd);
    }
    
    int getLikelyFd()
    {
        int limit = getdtablesize();
    
        for (int fd = 0; fd < limit; ++fd)
            if (fcntl(fd, F_GETFD) != -1)
                return fd;
    }
    
    int main()
    {
        std::vector<bool> existing = getOpenFileMap();
        int fd = open("/dev/null", O_RDONLY);
        closeOpenedFiles(existing);
        bool closed = write(fd, "test", 4) == -1;
        std::cout << "complex pass " << std::boolalpha << closed << std::endl;
    
        int guess = getLikelyFd();
        fd = open("/dev/null", O_RDONLY);
        bool match = fd == guess;
        std::cout << "simple pass " << std::boolalpha << match << std::endl;
    }
    

    【讨论】:

    • 什么是fd参数。因为在返回库中打开函数是不正常的。 #include fcntl(fd, F_GETFD) close(fd) 。并且 Kdevelop 通知错误:“fd”未在此范围内声明
    • @user2143123:好的,我拼出来了
    • 谢谢。它运作良好。我只使用 int guess = getLikelyFd();关闭(猜测);
    猜你喜欢
    • 2020-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 2018-05-15
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    相关资源
    最近更新 更多