PersonalCorpus 版 (精华区)

发信人: seaboy (浪小), 信区: C_and_CPP
标  题: 重定向
发信站: 哈工大紫丁香 (2003年06月18日09:11:53 星期三), 站内信件

重定向 
csdnfriend 翻译

-------------------------------------------------------------------------------
-

  我开始并没太在意,但过了第三天还没见到珍妮,才感到不妙。一阵犹豫与绝望之后,
我去找弗奈尔。找她是很自然的,因为我和珍妮当时都向她汇报工作。 

  当我敲第二下门的时候,房门打开了。“啊,是你,”她说。“什么事?” 

  “正在找珍妮,好几天没见她了。”我解释道。 

  弗奈尔扫了我一眼,说:“啊,是的。她最近分配了新的任务。” 

  “是吗,她在哪里呢?” 

“在圆屋,那里和发掘现场都需要添加人手。她一旦去了就必须呆在那里了。去那儿是受
限制的,因为门锁和地道情况不太好,进出那儿要穿特制的服装,真是痛苦。” 

  “是不是很多人都重新分配了任务?这里好像以后要搬空的样子。”我所知道的就是自
从几周前的爆炸事件后,主圆屋那边显然还是一直在装修。表面上我们在外边的楼层里继
续自己部门的工作,实际上与内部失去了联系,圆屋内大范围的通讯设施都有故障而在维
修。 

  “有一些,”她说着靠在了门口边上。“为什么?如果需要你这样的,要我给你介绍进
去吗?” 

  “当然,”我脱口而出然而又奇怪自己反应这么快。我这么惦记珍妮吗?或者我急着再
见到她?不管怎样,感觉自己有点奇怪。 

  如果珍妮被转移到圆屋,我想如果有机会我也会去。忽然想起了很多年以前的一天,当
时我学习处理另一种形式的转移。有意思的是,当时我也遇到了访问限制的问题。 


-------------------------------------------------------------------------------
-

  正当温迪走过我的小卧室时,我正在大叫:“啊!我恨死非法访问了!” 

  挫折感太强烈了,我只想大喊大叫。然而我的声音终于烧焦般地减弱下去,最后变得和
老鼠叫差不多了。 

  这一切已经足够使温迪停了来看我了。“你还好吧,怎么回事,年轻人?”她的语调里
带有一点爱尔兰口音。随着圣.帕特里克节的临近,她的一举一动越来越象爱尔兰人。 

  “温迪,快帮我一个忙,”我叹了口气,“你用不着扮这副怪相,这里有一个怪人已经
足够了。” 

“喂,你还好吧?”她平静温和地说,“伙计,什么东西把你惹你这样?” 

“啊呀,就是这些代码,我想可能和Guru有点关系。”我承认,“一开始我就被她吓得六
神无主。我肯定她是从疯人院跑出来的。后来,我又有点喜欢她把我称作她的徒弟。是有
点怪异,但也没什么大不了。但当我给朋友提起此事时,他们认为这是故意贬我。我再仔
细回想一下,觉得他们说得没错。” 

  温迪笑了。“噢,”她说,“我明白了,事实上你没有从正确的着眼点去看待她。你应
该去了解一下工作之外的她。”我试着想象她的家:架子上堆满了满是灰尘的电脑书和杂
志;祭坛里烧着拜祭各位计算机科学家的香……我的神情一定出卖了我的想法—温迪大笑
起来,“她摆Guru的架子,主要是为了气气鲍勃,吓唬一下新手。我喜欢她这样子,否则
她就活象一具僵尸了。” 

  “哦。”我并没有被说服。我不置可否,我觉得Guru的举动还是有点出格。,但我不想
跟温迪争,于是叹了口气静下来回到那个问题上:“我矛盾了几个小时了。任务很简单—
实际上就是重定向cout和cerr,把它们输出到文件中。” 

  “好,把你做的再跟我说一下。” 

  “我正在整合另一个组开发的库。这个库是以命令行(接口)的思路写出来的,所以所
有的调试、诊断信息送到了cout与cerr。更糟的是我认为鲍勃在那个组,因为没有一个规
则及原因说明何时信息送到cout何时送到cerr。实际上,有些信息分开送到两个流上!所
以我要跟踪它们并把它们凑在一个log文件里。”

  “总之,正如我说的,我在把它们整合到我们的图形用户界面(GUI)应用程序里。不
幸的是,GUI直接扔掉了cout和cerr的输出。所以,我正做的就是将输出转向到一个文件里
,实际上,简单吧,简单得我不知该怎么做,我对问题进行分析过滤后,写了下面的小程序
。”我拉了把椅子让温迪在电脑旁坐下。 

#include <iostream>
#include <fstream>
int main()
{
    std::ofstream logFile("out.txt");
    std::cout = logFile;
    std::cerr = logFile;
    std::cout << "This goes to cout\n";
    std::cerr << "This goes to cerr\n";
}

  “程序在一个编译器上编译及运行没有问题,但换了个编译器就出了非法读取的错误。
” 

  温迪看了看屏幕。“嗯…我不能确定你是不是可以那样重新分配数据流。” 

  “实际上,孩子,这样做显然极不自然明确地被神圣的标准所禁止。” 

  我们差点跳起来。不过怎么说,我得承认Guru总是神秘地在最恰当的时间出现。“所以
,我这样做不行?”我叹道。 

  “不,” Guru微笑道,“,实际上很简单,徒弟,你在大学里用什么编译器?” 

 “噢,是一种很老的编译器,不支持标准的很多特性。” 

  Guru点点头。“我明白了。你的编译器应该在使用一种先知Langer 和 Kreft所谓的 经
典输入输出流[1]。你肯定很熟悉标准输入输出流—尤其是流缓冲类。流缓冲不再是低级的
实现上的细节;它现在是一个…完整的类。输入输出流的设计者,Jerry Schwarz 早就看
到了流缓冲类将会成为一个极其有用的特性。然而它的价值和功能常常被忽略。” 

  “好吧。那我该怎么做呢?” 

  Guru拿起一枝干擦笔飞快地在白书写板上写下了如下的代码: 

#include <iostream>
#include <fstream>
int main()
{
    std::ofstream logFile("out.txt");
    std::streambuf *outbuf = std::cout.rdbuf(logFile.rdbuf());
    std::streambuf *errbuf = std::cerr.rdbuf(logFile.rdbuf());

    // do the actual work of the program;
    // GUI code and event loop would go here
    std::cout << "This would normally go to cout but goes to the log file\n";
    std::cerr << "This would normally go to cerr but goes to the log file \n";
    logFile << "This goes to the log file\n";
    // end of program body

    // restore the buffers
    std::cout.rdbuf(outbuf);
    std::cerr.rdbuf(errbuf);
}

“rdbuf函数返回一个由基类basic_ios管理的流缓冲区的指针。重载版本允许你替换流缓
冲区,返回值是原始的流缓冲区。解决方法很简单—用你的log文件的流缓冲区替换cout和
cerr的流缓冲区。程序结束时,改回原来的流缓冲区。你可以看到,你仍能用logFile作为
常规的输出文件。” 

 “酷毙了!”终于看到了流缓冲区的威力。“嘿,如果我只想重定向一个流,比如cerr
,我是不是可以简单地交换这两个缓冲区,这样就无须担心怎样恢复它们了,象下面那样 
:” 

int main()
{
    std::ofstream logFile("out.txt");
    std::streambuf *saveBuf=cerr.rdbuf(logFile.rdbuf());
    logFile.rdbuf(saveBuf);
    // remainder of program...
}

  “诶,并不这么简单,” Guru叹了口气 “这样的代码过不了编译关。basic_ios::rdb
uf函数并不是虚拟函数。ofstream只提供了一个rdbuf函数,此函数没有参数,返回指向对
象内部的文件缓冲流。也就是说std::ofstream::rdbuf(void) 隐藏了 
std::ostream::rdbuf(std::streambuf *)。 

“你可以通过一个指向std::ostream的指针操纵你的log文件,如下:” 

int main()
{
    std::ofstream logFile("err.log");
    std::ostream * baseManipulator = &logFile;
    baseManipulator->rdbuf(std::cerr.rdbuf(baseManipulator->rdbuf()));
}

  这些代码能通过编译,但无法正常工作。神圣的标准并没有规定ofstream的具体实现方
法。有可能某种编译器实现了ofstream的功能而忽略了ostream::rdbuf函数,直接操作文
件缓冲流。标准没有要求ofstream::close调用ostream:: rdbuf来决定闭哪个缓冲。因为
此函数总是返回指向ofstream对象内部的filebuf,ofstream总会关闭自己内部的filebuf
对象,于是cerr就没有了有效的缓冲区。所以,你还是要恢复原来cerr的流缓冲区,main
退出前加入如下: 

std::cerr.rdbuf(baseManipulator->rdbuf());

“如果你想重定向cin的输入,你必须预防类似的事情,ifstream也是这样的。” 

  Guru转身准备离开了,又停住了说:“这周六我想请人到我家来。没什么特殊的,一个
交际晚会。欢迎你和温迪,及你们各自的朋友前来。” 

  我开口正准备优雅的谢绝。“啊!” 

“他的意思是他很乐意过去,”温迪笑得很甜。我的小腿被她踹了一下,痛得厉害,只能
含泪无助地点点头。Guru微笑着飘然而去。 

  我等Guru和疼痛都消失以后,对温迪大叫起来:“早晚修理你。” 


-------------------------------------------------------------------------------
-

  “好啊,”我对弗奈尔说,“别忘了通知我一声。” 

“好的” 

  我就要走了,又问了一句:“诶,林格没却那儿吗,我的意思是她和珍妮是搭档。” 

  “不,”弗奈尔说。“我们这里需要她。” 

  “谢谢。明天见。” 

在下一个值班时,我核查了一下我允许看的职责花名册。名单很长,上面的名字各式各样
。象Jupiter(木星)这样的名字归联合国管啊,所以这次任务肯定是联合国发起的。各个
地方的人员都有,主要来自美利坚联合体和亚洲联盟,因为它们投入的科研经费最多。没
有谁的名字被打个记号,表明已被重新分配任务。但我能看出哪些名字已不在花名册的日
常值勤中了,他们肯定去别的地方了。 

  我慢慢看下去,看得很安静。 

  我终于发现了怪事:没有一个亚洲人被再分配到发掘现场或是圆屋。 


-------------------------------------------------------------------------------
-

[感谢]
感谢Angelika Langer和Klaus Kreft在他们的著作Standard C++ IOStreams and 
Locales: Advanced Programmer's Guide and Reference [1]中对这方面以及其它与流相
关的话题作了清楚的讨论。 


-------------------------------------------------------------------------------
-

[注释]
[1] Angelika Langer and Klaus Kreft. Standard C++ IOStreams and Locales: 
Advanced Programmer's Guide and Reference (Addison-Wesley, 2000). 
 
--
才知道   
原来
自己需要的是   
100万
份勇气。。。

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.239.80]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.758毫秒