检查已使用fopen打开的文件是否已关闭

时间:2013-07-30 07:51:35

标签: c fopen fclose

gcc (GCC) 4.7.2
c89

是否可以检查文件是否已关闭?

我使用fopen()打开了一个文件,并使用fclose(fd)关闭了。

在程序运行期间打开和关闭此文件。但是,用户可以通过执行ctrl-c来终止程序。

当我进入清理程序时,我不知道文件是处于打开还是关闭状态。因此,如果我尝试两次fclose(fd),它将堆叠转储。

我一直在撒谎的一些想法:

  
      
  1. 向文件添加要打开或关闭的状态,然后检查该状态,意味着为这么简单的工作做更多的工作。
  2.   
  3. 不要做任何事情,因为操作系统会在程序结束时自动清理。
  4.   
  5. 是否有访问功能,但这只会检查模式。
  6.   

非常感谢,

5 个答案:

答案 0 :(得分:6)

AFAIK,glibc没有提供验证FILE*变量的方法。

保持某种状态或仅将fd设置为NULL有效,但是在关闭文件之后但在重置{{1}之前,必须小心不要进入清理例程}。当Ctrl + C向程序发送信号(SIGINT)时,您可以在文件关闭和fd重置时阻止信号。因此,主程序中的fd应如下所示:

fclose

在你的清理程序中,你应该检查// 1. Block SIGINT sigset_t old_mask, to_block; sigemptyset(&to_block); sigaddset(&to_block, SIGINT); sigprocmask(SIG_BLOCK, &to_block, &old_mask); // 2. Close the file and reset fd fclose(fd); fd = NULL; // 3. Restore signal handling sigprocmask(SIG_SETMASK, &old_mask, NULL);

fd

如果您的程序是多线程的,则应使用if (fd != NULL) fclose(fd); 代替。

在您的情况下,在清理例程中简单调用pthread_sigmask会更容易。

关于你问题中的第二个选项,关于什么都不做 - 好吧,操作系统会为你的程序清理一切。然后唯一的缺点是,如果有打开的写入流,某些数据可能不会写入磁盘。但也许在Ctrl + C的情况下它就可以了。

答案 1 :(得分:4)

我觉得你脑子里有一点混乱。

fopenfclosef...函数一起使用的文件处理程序是进程范围。即,它们在申请中是有效的(通常)。

打开文件时可能会发生两件事:你成功与否。如果成功,您可能只使用文件或与其他进程共享。如果失败,可能另一个进程已经在使用文件。搜索_fsopen

当进程结束时,通常或中断(与Ctrl+C一样),OS迟早会释放与进程相关的资源。这适用于文件处理程序,内存,......

关于您的问题,无论您的应用程序是正常结束还是Ctrl+C结束,操作系统都会发布未关闭的文件处理程序。

每当您的应用程序启动时,您都需要打开所需的文件处理程序。操作系统不会为您打开它们。

答案 2 :(得分:2)

我在不同的情况下遇到了类似的问题(没有竞争条件)。所以这个解决方案既包括标题中的问题,也包括蚂蚁提出的问题。

调用fclose(fd)时,内部fd->_fileno低级I / O文件描述符设置为-1(或其他无效的unix文件描述符)。因此,可以使用fileno(fd)>=0检查fd是否仍然是有效的流(我的原始问题)。

当按下CTRL-C时,该过程接收被称为SIGINT的信号并执行相应的信号处理程序(例如预定义的函数)。在信号处理程序中,不应该尝试做任何涉及程序状态的任何事情(除了原子可设置变量,例如标志),因为信号可能在任何情况下到达,所以即使在glibc中执行fclose(fd)(所以{在执行处理程序期间未定义{1}}。因此,这里的规范方法是设置触发关闭和返回的标志。然后主应用程序需要经常检查此标志,如果已设置,则清理并退出。

此程序在按下fd->_fileno后结束,而不会导致系统清除任何fd。

CTRL-C

答案 3 :(得分:1)

可能对你有所帮助,只是一些建议:

您可以使用进程ID检查进程打开的文件。

  1. pid_t getpid(void);,返回调用进程的进程ID。
  2. 接下来将此PID传递给pfiles命令。
  3. 第二:

    您可以在程序终止前致电int fcloseall (void);

      

    此函数会导致关闭进程的所有打开流   与要破解的相应文件的连接。所有缓冲数据   写入并丢弃任何缓冲的输入。 fcloseall函数   如果所有文件都成功关闭,则返回值0   如果检测到错误,则为EOF。

答案 4 :(得分:0)

int sig_int(int signo)
{
    if(fdOpen)
       fclose(fd);
    abort();
}

然后将其添加到main

static volatile fdOpen = 0;
static FILE *fd;//I guess
if(signal(SIGINT,sig_int) == SIG_ERR)
    printf("signal(SIGINT) error\n");

if((fd =fopen("your_file_name","flag_you_need")) != NULL)
    fdOpen = 1;

在fcolse之前执行此操作:

sigset_t newmask,oldmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);//BLOCK SIGINT

在正常关闭文件fdOpen = 0 ;

后设置//SIGINT will not interrupt us now.

然后

sigprocmask(SIG_SETMASK,&oldmask,NULL);//RESET signal mask

所以我们做了一些干净的工作,然后在sig_int退出该计划。