Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1209433
  • 博文数量: 232
  • 博客积分: 7563
  • 博客等级: 少将
  • 技术积分: 1930
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-21 11:17
文章分类

全部博文(232)

文章存档

2011年(17)

2010年(90)

2009年(66)

2008年(59)

分类:

2010-09-18 10:52:43

#include;
#include;
int main(int argc, char *argv[])
{
        int fd;
        FILE  *fp;

        //to open a log file
        if((fp=fopen("/var/log/ftp","w"))==NULL)
        {
                printf("fopen error \n");
                exit(1);
        }

        fd=fileno(fp);
        if(dup2(fd,STDOUT_FILENO)==-1){

                fprintf(stderr,"Redirect Standard Out error");
                exit(1);
        }
        printf("have a test\n");
        fclose(fp);
        printf("The end!\n");
}
[color=red][/color]
为什么关掉文件后,还能把The end写进去?运行结果如下:
[root@localhost bxf]# ./a.out
[root@localhost bxf]# cat /var/log/ftp
have a test
The end!



  回复于:2004-02-05 18:32:46

fp是指向打开的/var/log/ftp,fclose(fp)也只是关闭这个文件。并没有关闭stdout。所以printf()仍然可以向stdout输出信息。由于stdout已经重定向为/var/log/ftp,信息自然输出到了/var/log/ftp中。


  回复于:2004-02-16 13:09:44

再问一个问题:我把想要的信息重定向到文件后,便于进行分析判断下一步的操作。等将重要信息截取完后,我如果再想把输出重定向回来的话,应该用哪一个函数呢?不知道不退出程序的话,能不能重定向回来?


  回复于:2004-02-16 13:45:35

你再close(fd)试试。


  回复于:2004-02-16 15:46:02

:em09: 看见你我就感觉有戏了。马上去测试 :mrgreen:


  回复于:2004-02-16 17:06:16

可惜。还是不行。


  回复于:2004-02-16 17:23:49

引用:原帖由 "flyingbxf"]再问一个问题:我把想要的信息重定向到文件后,便于进行分析判断下一步的操作。等将重要信息截取完后,我如果再想把输出重定向回来的话,应该用哪一个函数呢?不知道不退出程序的话,能不能重定向回来?
 发表:


如果要把输出重定向回来,就应该在重定向前先保存stdout,然后在重定向完成之后,再把保存的stdout用dup2()恢复回来。


  回复于:2004-02-16 20:13:57

引用:原帖由 "kj501" 发表:

如果要把输出重定向回来,就应该在重定向前先保存stdout,然后在重定向完成之后,再把保存的stdout用dup2()恢复回来。


怎么个保存法?压栈?还是用另外的指针指向STDOUT?


  回复于:2004-02-17 16:03:51

用unlink试试


  回复于:2004-02-17 16:37:06

unlink("/var/log/ftp");与 rm 命令 rm  /var/log/ftp 都是删除文件,其具体实现有什么区别吗?


  回复于:2004-02-17 18:31:38

dup2我没有用过,不过我知道freopen重定向输出到文件后如何恢复到终端上,不知和这个一样不一样。


  回复于:2004-02-17 20:03:28

引用:原帖由 "forest077"]dup2我没有用过,不过我知道freopen重定向输出到文件后如何恢复到终端上,不知和这个一样不一样。
 发表:


freopen怎么恢复??用fclose()吗?


  回复于:2004-02-17 21:24:40

引用:原帖由 "flyingbxf" 发表:

怎么个保存法?压栈?还是用另外的指针指向STDOUT?

 
int saved_fd ;
saved_fd = STDOUT_FILENO; /* 保存标准输出 */

dup2(saved_fd, STDOUT_FILENO); /* 恢复标准输出 */


  回复于:2004-02-17 21:44:12

freopen重定向后的恢复,基本原理是获得当前的tty,然后把输出流定向到当前tty即可,实现起来很简单,两三句话即可。范例如下:
//把stdout定向到文件aaa
fpout=freopen("aaa","w",stdout);
//现在printf会输出到文件aaa里面
fp=popen("tty","r");
fgets(str,sizeof(str),fp);
str[strlen(str)-1]=0;//当前tty保存在str里面了
fclose(fp);
//把fpout重定向到当前tty
freopen(str,"w",fpout);
//现在printf输出到当前终端
不知道这个功能适合不适合你。


  回复于:2004-02-17 21:45:11

kj501的方式我要试一试,如果可以,比我的方便多了。


  回复于:2004-02-17 23:04:12

kj501的方法我试过了不行呀


  回复于:2004-02-17 23:05:09

引用:原帖由 "flyingbxf"]alhost bxf 发表:
#为什么关掉文件后,还能把The end写进去?运行结果如下:
[root@localhost bxf]# ./a.out
[root@localhost bxf]# cat /var/log/ftp
have a test
The end!



这是因为你 dup2 后, stdout 和 fp 都指向文件 /var/log/ftp, 关掉其中一个后,另一个仍然可写。


  回复于:2004-02-17 23:08:32

引用:原帖由 "kj501" 发表:

int saved_fd ;
saved_fd = STDOUT_FILENO; /* 保存标准输出 */

dup2(saved_fd, STDOUT_FILENO); /* 恢复标准输出 */



你写错了吧?这几行程序一般相当于:

int saved_fd;
save_fd = 2;
dup2 (2, 2);

这怎么行?


  回复于:2004-02-17 23:12:18

这个估计行:


int sfd;
sfd = dup (STDOUT_FILENO);  /* save */
....

dup2 (sfd, STDOUT_FILENO); /* restore */




  回复于:2004-02-18 17:45:09

win_hate,你好!
如果我这么写:

int main(void)
{
        FILE *fp;
        int fd, id;
                                                                                
        id = dup(STDOUT_FILENO);
                                                                                
        fp = fopen("install.log", "w");
        if (fp == NULL) {
                printf("read error.\n");
                return 0;
        }
        fd = fileno(fp);
        dup2(fd, STDOUT_FILENO);
        printf("test\n");
        fclose(fp);
        printf("hello\n");
                                                                                
        dup2(id, STDOUT_FILENO);
        printf("world\n");
                                                                                
        return 0;
}

将在终端打印出
test
hello
world

如果我要做到在打开的文件install.log中写入
test
hello
而在终端输出
world
应该怎么作呢?

另外,在学习UNIX编程时我看的是APUE,感觉光看书中的例子还不够呀,那些例子功能比较单一,大多为了讲述一组函数的功能的,有没有那本书将大部分函数功能都用上,实现一个比较大的程序呢


  回复于:2004-02-18 17:53:30

你的要求很奇怪哦。
那样的话你用fprintf()吧。
也没这么麻烦了。


  回复于:2004-02-18 18:29:20

引用:原帖由 "converse" 发表:
 dup2(id, STDOUT_FILENO);
printf("world\n");

return 0; 



在 dup2 (id, STDOUT_FILENO); 之前加入


fflush (stdout);


就能达到你要求的效果了。该死的缓冲.....

对另一个问题, 我认为只有写过 ''真正的程序'' 后才能融会贯通。如果没有参加实际项目的机会,可以多看看代码。


  回复于:2004-02-18 21:55:22

我明白了,fflush函数把原来的test和hello强行写入打开的文件中,然后由于stdut被重新定位到屏幕上所以就在屏幕上输出world了,对吧??

我现在比较的郁闷,虽然找了一个作LINUX的公司,不过作的东西好象和我想像的有分别,暂时还用不上APUE里的知识,缺少了在实际中的锻炼学 起来自然慢的多,我看了一下APUE后面有几个实际的例子,不过好象是数据库的,然后是打印机的,我这些都没有学过呀,不知道看过这本书的朋友感觉怎么样 呢?

个人觉得APUE对于初学者来说太难了,很多基础的概念一带而过,还是lenovo推荐过的《UNIX程序设计教程》不错,把这两本书结合在一起看学的很快,就是可惜的是没有实践的锻炼,郁闷呀。。。。。。。。。


  回复于:2004-02-18 22:35:39

引用:原帖由 "converse" 发表:
我明白了,fflush函数把原来的test和hello强行写入打开的文件中,然后由于stdut被重新定位到屏幕上所以就在屏幕上输出world了,对吧??

我现在比较的郁闷,虽然找了一个作LINUX的公司,不过作的东西好象和我想像..........


我看APUE看的也很慢,现在看到进程高级通信那里了,
时间也不是很充足。不过感觉用处还是很大的,
很多不明白的地方,那本书都说了。


  回复于:2004-02-19 09:45:19

说来惭愧,虽然我一直向别人大力推荐APUE,但是自己从来没有从头到尾看过一遍。我把它当作一本开发手册,用到时再去翻翻,呵呵。


  回复于:2004-02-19 11:01:36

[quote="win_hate"]
在 dup2 (id, STDOUT_FILENO); 之前加入 

代码: 

[color=blue]fflush (stdout); [/color]
 

quote]

我没有加fflush (stdout); 也没有出现问题啊!为什么呢?我是在linux下运行的。


  回复于:2004-02-19 11:41:07

引用:原帖由 "flyingbxf" 发表:

 

quote]

我没有加fflush (stdout); 也没有出现问题啊!为什么呢?我是在linux下运行的。



我记得你是做嵌入式开发的,可能是环境不同。你换个台式机试一试可能就有这个问题。


  回复于:2004-02-19 18:32:59

dup2首先close标准输出,然后把标准输出的文件描述符1传到fd所代表的结构中?
close(fd)其实是close了一个没有用的数(3),fclose关闭的也是这个数字(3),可以通过fileno看到。所以还可以写道这个文件中。如果关闭了close(1),则不行了。
看来FILE和文件描述符最好不一起使用。不然一定要当心啊。


  回复于:2004-02-19 20:20:35

引用:原帖由 "win_hate" 发表:


你写错了吧?这几行程序一般相当于:

int saved_fd;
save_fd = 2;
dup2 (2, 2);

这怎么行?


说错了,stdout应该是1,2是stderr。


  回复于:2004-02-19 20:42:05

引用:原帖由 "kj501" 发表:

int saved_fd ;
saved_fd = STDOUT_FILENO; /* 保存标准输出 */

dup2(saved_fd, STDOUT_FILENO); /* 恢复标准输出 */


我来检讨一下,由于我对dup2的使用在概念有理解错误,我给出的例子是行不通的。
经过试验,我发现dup2(int oldfd, int newfd)其中的newfd必须是一个实际打开文件的文件描述符,不能只是一个不指向任何文件的整数。
这是我作试验的代码:

#include;
#include;
#include;
#include;
#include;

int main()
{
int sfd,testfd;

testfd = open("temp",O_CREAT | O_RDWR | O_APPEND);

if (-1 == testfd) {
printf("open file error.\n");
exit(1);
}

/* 先复制一个真实的文件描述符 */
sfd = dup(testfd);

/* 保存标准输出 */
if (-1 == dup2(STDOUT_FILENO,sfd) ) {
printf("can't save fd \n");
exit(1);
}

/* 重定向 */
if (-1 == dup2(testfd,STDOUT_FILENO) ) {
printf("can't redirect fd error\n");
exit(1);
}

/* 此时向stdout写入应该输出到文件 */
write(STDOUT_FILENO,"file\n",5);

/* 恢复stdout */
if (-1 != dup2(sfd,STDOUT_FILENO) ) {
printf("recover fd ok \n");

/* 恢复后,写入stdout应该向屏幕输出 */
write(STDOUT_FILENO,"stdout\n",7);
}
}

如果把其中的这一行注释掉:

sfd = dup(testfd);

dup2函数执行时肯定会失败。
但从代码中也可以看出,我前面提出的先保存文件描述符,然后在重定向之后再恢复回来的思路是行得能的。
有不当之处,还请大家多多指教!


  回复于:2004-02-19 20:48:40

引用:原帖由 "kj501" 发表:

说错了,stdout应该是1,2是stderr。



说得对,我写错了, 应该是1


  回复于:2004-02-19 21:16:51

引用:原帖由 "kj501" 发表:
dup2函数执行时肯定会失败。
但从代码中也可以看出,我前面提出的先保存文件描述符,然后在重定向之后再恢复回来的思路是行得能的。
有不当之处,还请大家多多指教!



你对 dup2 的理解仍然有误, dup2 (a, b) 把 a 复制到 指定的“数字”(文件描述)上, 如果 b 是已打开的文件描述符, 先把 b 关掉(取消关联)。

你可以试一试, 把

sfd = dup(testfd); 


注释掉,然后,很重要的一点,把 sfd 初始化为一个整数, 不要太大。我估计程序不会出错。

你试过后,请把结果告诉我。谢谢。


  回复于:2004-02-20 09:20:16

引用:原帖由 "win_hate" 发表:


我记得你是做嵌入式开发的,可能是环境不同。你换个台式机试一试可能就有这个问题。


我写错了,我的使用环境是uclinux,我在台式机上redhat8.0的环境下试了,不加fflush(stdout)果然全都输出到屏幕上了,文件里面没有写进去.不过我不明白能不能写进文件关缓冲什么事 呢?


  回复于:2004-02-20 14:36:36

我来谈谈我的看法吧,我对这个问题还有一些疑问的

                                                                                                                                             #include ;
#include ;
                                                                                                                                              
int main(void)
{
        FILE *fp;
        int fd, id;
                                                                                                                                              
        id = dup(STDOUT_FILENO);//这时id和STDOUT_FILENO一起指向stdout
        if ((fp = fopen("install.log", "w")) == NULL) {
                perror("read error.\n");
                exit(-1);
        }
        fd = fileno(fp);//得到fp的文件描述符
        dup2(fd, STDOUT_FILENO);//STDOUT_FILENO和stdout流断开,             //STDOUT_FILENO指向fd的对应文件,这样使输出到达fd的文件
                                //fd对应的是已经打开的文件install.log,//而stdout在这里指的是终端,现在任何的输入都输入到
                                //install.log中
        printf("hello\n");
                                                                                                                                              
        fflush(stdout);//刷新stdout上的缓冲区,这样前面的hello写入文件//install.log中
        dup2(id, STDOUT_FILENO);
        printf("world\n");
        fclose(fp);
                                                                                                                                              
        return 0;
}



以上的注释基本表达了我对这几个函数运用的了解,不过这里对fflush(stdout)的运用还有一点疑问,fflush(stream)刷新 的是流stream上的缓冲,是不是可以理解为不论文件描述符STDOUT_FILENO定位到了哪个文件,stdout都保存有未写入文件的缓冲区的内 容呢?按理来说,文件描述符比流更加底层才对呀


  回复于:2004-02-20 14:39:21

倒,我的代码怎么在这里变得这么乱呀


  回复于:2004-02-20 22:32:39

引用:原帖由 "converse" 发表:

fflush(stdout);//刷新stdout上的缓冲区,这样前面的hello写入文件 install.log中
        dup2(id, STDOUT_FILENO);
        printf("world\n");
        fclose(fp); 



引用:原帖由 "converse" 发表:

不过这里对fflush(stdout)的运用还有一点疑问,fflush(stream)刷新的是流 stream上的缓冲,是不是可以理解为 不论文件描述符STDOUT_FILENO定位到了哪个文件,stdout都保存有未写入文件的缓冲区的内容呢?按理来说,文件描述符比流更加底层才对呀



呵呵, 确实如此。 事实上,文件指针,比如说fp, 是根据fileno(fp)来对应文件的。你看上面的代 码,STDOUT_FILENO 已经对应到 install.log,所以,当fflush(stdout)后, 缓冲内容写入文 件 install.log。如果不fflush,执行
dup2 (id, STDOUT_FILENO), 这时 STDOUT_FILENO又对应回屏幕了, 然后缓冲中的内容和后来的数据都输到屏幕上了。


  回复于:2004-02-21 10:56:37

引用:原帖由 "win_hate" 发表:

注释掉,然后,很重要的一点,把 sfd 初始化为一个整数, 不要太大。我估计程序不会出错。

你试过后,请把结果告诉我。谢谢。


你的说法一点不错,我将

sfd = dup(testfd);

注释掉后,再将sfd初始化为0~1023之间的任何数,都可以执行成功。看来问题出在这一句:

dup2(STDOUT_FILENO,sfd);

我用的系统是linux(内核2.4.21),由于linux内核限制最大打开的文件总数为1024(这一点可能改进了,原来很多书上说的是最大 只能打开256个文件),因此,dup2在执行时肯定会进行文件描述符的合法性检查,如果大于1023,肯定导致失败。sfd没有初始化时的值是由系统任 意给出的(将sfd没有初始化的值打印出来,结果是1073817472),已经超出了1023的限制,从而导致dup2()执行失败。这才是问题的真正 原因。其实在man文档中对错误原因说得很清 楚:“oldfd  isn't  an  open  file  descriptor, or newfd is out of the allowed range for file descriptors.” 只 是我自己没有认真看。
经过这次讨论,感觉自己对dup2()的理解加深不少,APUE上对dup2()的介绍对于全面理解这两个函数的使用并不充分。以后man文档一定要仔细看。
最后,非常感谢win_hate,希望以后能和你多多交流。:)


  回复于:2004-02-21 11:22:35

这样针对一组函数功能的讨论真的可以提高很快,我也受益匪浅呀

建议斑竹加为精华


  回复于:2004-02-21 12:50:17

引用:原帖由 "kj501"]最后,非常感谢win_hate,希望以后能和你多多交流。
 发表:



kj501 兄客气了, 这里我常来,期待与大家交流,向各位学习。


  回复于:2004-02-21 16:02:53

我有一个不解的地方,就是freopen实现的功能也是把一个流重定向到另一个流去,它和dup、dup2的底层实现有什么不一样吗?


  回复于:2004-02-21 23:05:43

引用:原帖由 "forest077"]我有一个不解的地方,就是freopen实现的功能也是把一个流重定向到另一个流去,它和dup、dup2的底层实现有什么不一样吗?
 发表:



freopen 并不是把一个流定向到另一个流,而是把一个流对应到一个新的文件:

fd1 = dup (fd);   fd1, fd 对应同一个文件, 但不能指定 fd1 的值。

dup2 (fd, fd1);  fd1, fd 对应同一个文件,但可以指定 fd1的值,根据 kj501提供的资料, fd1 不能大于 1024

freopen ("xxx", "w", fp);  关掉 fp 对应的文件, 并打开文件 xxx, 指针 fp 的值不变。

在前两种情况中, 都有两个文件描述符出现, 但在第三种情况中, 只有一个文件指针。

使用 freopen (..., fp) 时, 原来 fp 对应的缓存写入, 关掉 fileno(fp), 寻找一个最小未用的文件描述 符, 在其上打开新文件。也就是说, fp 值不变, 其指向的 FILE 结构仍然使用, 但 fileno (fp) 则有可能改变。


  回复于:2004-02-21 23:42:35

引用:原帖由 "win_hate" 发表:


呵呵, 确实如此。 事实上,文件指针,比如说fp, 是根据fileno(fp)来对应文件的。你看上面的代 码,STDOUT_FILENO 已经对应到 install.log,所以,当fflush(stdout)后, 缓冲内容写入文 件 install.log。如果不fflus..........


可以理解为 dup2首先close标准输出,然后把标准输出的文件描述符STDOUT_FILENO 传到fd所代表的fp文件指针结构中

STDOUT_FILENO 指向install.log的文件表

文件指针stdout的文件描述符为STDOUT_FILENO

所以fflush(stdout)后, 缓冲内容写入文件 install.log


  回复于:2004-02-22 08:48:06

引用:原帖由 "Wangwen" 发表:

可以理解为 dup2首先close标准输出,然后把标准输出的文件描述符STDOUT_FILENO 传到fd所代表的fp文件指针结构中

STDOUT_FILENO 指向install.log的文件表

文件指针stdout的文件描述符为STDOUT_FILENO

所以f..........



说法有误,dup2 是低级 I/O 操作函数, 不会直接与 fp 指向的文件结构打交道。


  回复于:2004-02-23 09:24:54

引用:原帖由 "converse" 发表:

fflush(stream)刷新的是流stream上的缓冲,是不是可以理解为不论文件描述符STDOUT_FILENO定位到了哪个文件,stdout都保存有未写入文件的缓冲区的内容呢?........


不用fflush(stream)就写不进文件,但为什么不用fflush(stream)就能输出到屏幕上呢?


  回复于:2004-02-23 09:29:40

还有就是  dup2(STDOUT_FILENO,sfd); 和 
 dup2(sfd,STDOUT_FILENO); 起的作用是一样的?都是将两个文件描述符指向同一个文件是吗?


  回复于:2004-02-23 12:08:53

可以理解为 dup2首先close标准输出,

将STDOUT_FILENO 指向install.log的文件表 

文件指针stdout的文件描述符为STDOUT_FILENO 

所以fflush(stdout)后, 缓冲内容写入文件 install.log

使用fprintf(fp,"hello\n");fflush(fp);仍然可以将hello写入install.log

dup2(id, STDOUT_FILENO)使STDOUT_FILENO指向标准输出

printf("world\n");写入终端


  回复于:2004-02-23 12:11:24

引用:原帖由 "flyingbxf" 发表:

不用fflush(stream)就写不进文件,但为什么不用fflush(stream)就能输出到屏幕上呢?


程序结束是 执行了fflush(stream)


  回复于:2004-02-23 14:14:13

引用:原帖由 "Wangwen" 发表:
可以理解为 dup2首先close标准输出,

将STDOUT_FILENO 指向install.log的文件表

文件指针stdout的文件描述符为STDOUT_FILENO

所以fflush(stdout)后, 缓冲内容写入文件 install.log

使用fprintf(fp,"hello\n");fflush(fp);仍然可以将hello写入install.log

dup2(id, STDOUT_FILENO)使STDOUT_FILENO指向标准输出

printf("world\n");写入终端



Great!


  回复于:2004-02-23 14:25:49

xiexie


  回复于:2004-02-23 20:10:51

茅塞顿开,不错不错,强烈建议加精


  回复于:2006-07-07 16:50:01

#include
#include
int main(int argc, char *argv[])
{
        int fd;
        FILE  *fp;

        //to open a log file
        if((fp=fopen("nihao","w"))==NULL)
        {
                printf("fopen error \n");
                exit(1);
        }

        fd=fileno(fp);
        if(dup2(fd,STDOUT_FILENO)==-1){
                fprintf(stderr,"Redirect Standard Out error");
                exit(1);
        }
        printf("have a test\n");
        fclose(fp);
        printf("The end!\n");
}

  该程序屏幕没有输出,只是输出到文件了


阅读(1003) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~