C语言 检查使用 fopen 打开的文件是否已关闭
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17941244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Check if a file that has been opened with fopen has been closed
提问by ant2009
gcc (GCC) 4.7.2
c89
Is it possible for check if a file has already closed?
是否可以检查文件是否已经关闭?
I have opened a file using fopen()and closed using fclose(fd).
我已经使用打开了一个文件fopen()并使用了关闭fclose(fd)。
This file gets opened and closed during the running of the program. However, the user can terminate the program by doing a ctrl-c.
该文件在程序运行期间被打开和关闭。但是,用户可以通过执行ctrl-c.
When I go to my cleanup routine, I don't know if the file is in a open or closed state. So if I try and do a fclose(fd)twice, it will stack dump.
当我进入我的清理程序时,我不知道文件是处于打开状态还是关闭状态。因此,如果我尝试执行fclose(fd)两次,它将堆栈转储。
Some ideas I have been throwing around:
我一直在抛出的一些想法:
- Add a state to the file to be either opened or closed, and then check that state, means more work for such a simple job.
- Don't do anything as the OS will cleanup automatially when the program ends.
- Is there is the access function, but that will just checks the mode.
- 向要打开或关闭的文件添加状态,然后检查该状态,对于这样一个简单的工作来说意味着更多的工作。
- 不要做任何事情,因为操作系统会在程序结束时自动清理。
- 是否有访问功能,但这只会检查模式。
Many thanks in advance,
提前谢谢了,
采纳答案by nullptr
AFAIK, glibc doesn't provide a method to validate a FILE*variable.
AFAIK,glibc 不提供验证FILE*变量的方法。
Keeping some kind of state or just setting fdto NULLworks, but you have to be careful not to get into your cleanup routine just after closing the file, but before resetting fd. As Ctrl+C sends a signal (SIGINT) to a program, you can just block the signal while the file is being closed and fd is being reset. So, your fclosein the main program should look like:
保持某种状态或只是设置fd为NULL有效,但您必须小心不要在关闭文件后但在重置fd. 当 Ctrl+C 向程序发送信号 (SIGINT) 时,您可以在关闭文件和重置 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);
And in your clean-up routine you should just check fd:
在您的清理程序中,您应该检查fd:
if (fd != NULL) fclose(fd);
If your program is multithreaded, you should use pthread_sigmaskinstead.
如果您的程序是多线程的,则应pthread_sigmask改用。
In your case, simple call of fcloseall()in the cleanup routine would be much easier.
在您的情况下,fcloseall()在清理例程中简单调用 of会容易得多。
As for the second option meant in your question, about doing nothing - well, the OS will clean-up everything for your program. Then only drawback is that if there were opened write streams, some data may be not written to disk. But maybe in case of Ctrl+C it's just ok.
至于您的问题中的第二个选项,即什么都不做 - 好吧,操作系统将为您的程序清理所有内容。那么唯一的缺点是,如果有打开的写入流,一些数据可能不会写入磁盘。但也许在 Ctrl+C 的情况下,它就可以了。
回答by LS_???
It seams to me that there is a little confusion in your mind.
我觉得你脑子里有点混乱。
File handlers, used with fopen, fclose, f...functions are process scope. I.e., they are valid within application (normally).
与fopen、fclose、f...函数一起使用的文件处理程序是进程作用域。即,它们在应用程序内有效(通常)。
Two things can happen when you open a file: you succeed or not. If you succeed, you may be using file exclusively or shared with other processes. If you fail, maybe another process is already using file. Search _fsopen.
打开文件时可能会发生两件事:成功与否。如果成功,您可能正在独占使用文件或与其他进程共享。如果失败,可能另一个进程已经在使用文件。搜索_fsopen。
When process ends, normallyor interrupted (as with Ctrl+C), OS releases resources associated with process, sooner or later. This applies to file handlers, memory, ...
当进程结束时,正常或中断(如Ctrl+C),操作系统迟早会释放与进程相关的资源。这适用于文件处理程序、内存、...
Regarding your question, whether your application end normally or with Ctrl+C, unclosed file handlers will be released by OS.
关于您的问题,您的应用程序是否正常结束或以Ctrl+C,未关闭的文件处理程序将由操作系统释放。
Whenever your application starts, you need to open file handlers you need. OS will not keep them open for you.
每当您的应用程序启动时,您都需要打开所需的文件处理程序。操作系统不会让它们为您打开。
回答by msebas
I got a similar problem in a different situation (no race condition). So this solution covers both the question in the title and the one asked by ant.
我在不同的情况下遇到了类似的问题(没有竞争条件)。所以这个解决方案涵盖了标题中的问题和蚂蚁提出的问题。
When fclose(fd)is called the internal fd->_filenolow level I/O-file descriptor is set to -1 (or an other invalid unix file descriptor). So one could check using fileno(fd)>=0to verify if fdis still a valid stream (my original problem).
当fclose(fd)被调用时,内部fd->_fileno低级 I/O 文件描述符被设置为 -1(或其他无效的 unix 文件描述符)。所以可以检查使用fileno(fd)>=0来验证是否fd仍然是一个有效的流(我原来的问题)。
When CTRL-Cis pressed the process receives a signal refereed as SIGINTand executes the corresponding signal handler (e.g. a predefined function). One should never try to do anything involving the program state (except for atomic settable variables, e.g. flags) in a signal handler, because the signal might arrive in any situation, so even while fclose(fd)is executed in glibc (so fd->_filenois undefined during the execution of the handler). Because of this the canonical way here is to set a flag triggering the shutdown and return. The main application then needs to check this flag sufficiently often, and, if it is set, cleans up and exit.
当CTRL-C被按下时,进程接收到一个信号SIGINT并执行相应的信号处理程序(例如一个预定义的函数)。永远不要尝试在信号处理程序中做任何涉及程序状态的事情(除了原子可设置变量,例如标志),因为信号可能会在任何情况下到达,所以即使fclose(fd)在 glibc 中执行时(所以fd->_fileno在执行过程中是未定义的)处理程序)。因此,这里的规范方法是设置触发关闭和返回的标志。然后主应用程序需要足够频繁地检查这个标志,如果它被设置,清理并退出。
This program finishes after CTRL-Cis pressed, without leading to any fd cleaned up by the system.
该程序在CTRL-C按下后结束,不会导致系统清理任何文件。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
char interrupted=0;
void exit_handler(int sig){
interrupted=1;
}
int main(char** argc, int argv)
{
FILE *fd;
signal(SIGINT, exit_handler);
signal(SIGTERM, exit_handler);
while(1){
fd=fopen("filepath.file","w");
char *tst_str="Test String";
if(fwrite(tst_str,1,11,fd)!=11)
printf("Writing Error occured\n");
if (fileno(fd)>=0){
printf("FD Closed. (1)\n");
fclose(fd);
}
if (fileno(fd)>=0){
printf("FD Closed. (2)\n");
fclose(fd);
}
if(interrupted)
exit(0);
}
printf("Done.");
}
回答by Grijesh Chauhan
May be it help you, just some suggestions:
也许它对你有帮助,只是一些建议:
You can check file open by your process using process id.
您可以使用进程 ID 检查进程打开的文件。
pid_t getpid(void);, return the process ID of the calling process.- Next pass this PID to
pfilescommand.
pid_t getpid(void);,返回调用进程的进程ID。- 接下来将此PID传递给
pfiles命令。
Second:
第二:
You can call int fcloseall (void);before program terminates.
您可以int fcloseall (void);在程序终止之前调用 。
This function causes all open streams of the process to be closed and the connection to corresponding files to be broken. All buffered data is written and any buffered input is discarded. The fcloseall function returns a value of 0 if all the files were closed successfully, and EOF if an error was detected.
该函数会导致进程的所有打开流被关闭,并且与相应文件的连接被中断。写入所有缓冲数据并丢弃任何缓冲输入。如果所有文件都成功关闭,则 fcloseall 函数返回值 0,如果检测到错误,则返回值 EOF。
回答by Lidong Guo
int sig_int(int signo)
{
if(fdOpen)
fclose(fd);
abort();
}
Then add this to main:
然后将其添加到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;
Do this before fcolse:
在 fcolse 之前执行此操作:
sigset_t newmask,oldmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);//BLOCK SIGINT
And set fdOpen = 0 ;after you close file normally//SIGINT will not interrupt us now.
并fdOpen = 0 ;在您正常关闭文件后设置//SIGINT will not interrupt us now.
Then
然后
sigprocmask(SIG_SETMASK,&oldmask,NULL);//RESET signal mask
So we do some clean jobs and then exit the program at sig_int.
所以我们做一些干净的工作,然后在sig_int.

