如何关闭已打开的C语言文件

3
我正在编写一个读取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;
}

2
这个库没有提供一个单独的函数来关闭文件吗?当你完成它们时。 - Kyle Strand
是的,我在这个头文件中找到了,但是没有。这是主要问题。 - user2143123
看起来该库的源代码是可用的(ftp://ftp.erl.wustl.edu/pub/dicom/software/ctn/)。此外,当`DCM_OpenFile()`返回`DCM_FILEACCESSERROR`错误时,它可能会泄漏文件句柄,但只有在调用`fstat()`失败或者文件大小大于`INT_MAX`时才会发生(这是你遇到的问题吗?)。无关紧要的一点是:在我看来,`DCM_OpenFile()`的命名不太合适,因为它做的事情远不止打开文件(实际上,通常在完成后会关闭文件)。 - Michael Burr
2个回答

2
在您的 DICOMImage 类中,添加一个成员。
DCM_OBJECT *handle_;

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

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

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

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


1
您可以先测试所有文件描述符,以查看哪些正在使用,方法是在从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.h> fcntl(fd, F_GETFD) close(fd)。而Kdevelop会提示错误:‘fd’在此范围内未声明。 - user2143123
@user2143123:好的,我已经把它拼写出来了。 - Ben Jackson
谢谢。它运行良好。我只使用了 int guess = getLikelyFd(); close(guess); - user2143123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接