C++编程思想 第2卷 第4章 输入输出流 为什么引入输入输出流

以前的C库不好,不把C库封装成新的类
stdio中定义的FILE为指向文件的指针,假定需要安全地打开文件并且不依赖用户
调用close()来关闭它

//: C04:FileClass.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// stdio files wrapped.
#ifndef FILECLASS_H
#define FILECLASS_H
#include <cstdio>
#include <stdexcept>

class FileClass {
  std::FILE* f;
public:
  struct FileClassError : std::runtime_error {
    FileClassError(const char* msg)
    : std::runtime_error(msg) {}
  };
  FileClass(const char* fname, const char* mode = "r");
  ~FileClass();
  std::FILE* fp();
};
#endif // FILECLASS_H ///:~

在C语言中进行文件I/O时,是使用无保护的指向FILE struct的指针来完成有关
操作,但这个类封装了文件结构指针,并且用构造函数和析构函数来确保指针
被正确地初始化和清理

为了在文件I/O函数中使用这个指针的值,可以用存取访问函数 access function
fp()取得它

//: C04:FileClass.cpp {O}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// FileClass Implementation.
#include "FileClass.h"
#include <cstdlib>
#include <cstdio>
using namespace std;

FileClass::FileClass(const char* fname, const char* mode) {
  if((f = fopen(fname, mode)) == 0)
    throw FileClassError("Error opening file");
}

FileClass::~FileClass() { fclose(f); }

FILE* FileClass::fp() { return f; } ///:~

构造函数调用fopen(),而且要确保返回结果不为零,结果为零说明打开文件失败
如果文件不能正常打开,则抛出异常

析构函数用来关闭文件,而存取访问函数fp()返回指针f
使用FileClass

//: C04:FileClassTest.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
//{L} FileClass
#include <cstdlib>
#include <iostream>
#include "FileClass.h"
using namespace std;

int main() {
  try {
    FileClass f("FileClassTest.cpp");
    const int BSIZE = 100;
    char buf[BSIZE];
    while(fgets(buf, BSIZE, f.fp()))
      fputs(buf, stdout);
  } catch(FileClass::FileClassError& e) {
    cout << e.what() << endl;
    return EXIT_FAILURE;
  }
  getchar();
  return EXIT_SUCCESS;
} // File automatically closed by destructor
///:~


输出
//: C04:FileClassTest.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
//{L} FileClass
#include <cstdlib>
#include <iostream>
#include "FileClass.h"
using namespace std;

int main() {
  try {
    FileClass f("FileClassTest.cpp");
    const int BSIZE = 100;
    char buf[BSIZE];
    while(fgets(buf, BSIZE, f.fp()))
      fputs(buf, stdout);
  } catch(FileClass::FileClassError& e) {
    cout << e.what() << endl;
    return EXIT_FAILURE;
  }
  getchar();
  return EXIT_SUCCESS;
} // File automatically closed by destructor
///:~

创建一个FileClass对象并在普通的 C文件I/O函数中通过调用fp()使用它

虽然FILE指针是私有的,但它并不是特别安全,因为成员函数fp()可以检索它

如果需要得到完全的安全,就必须防止客户直接存取FILE指针
所有的I/O函数都必须作为成员函数封装在类中,使得借助于C语言能做到的每
一件事,在C++类中均可做到:

//: C04:Fullwrap.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Completely hidden file IO.
#ifndef FULLWRAP_H
#define FULLWRAP_H
#include <cstddef>
#include <cstdio>
#undef getc
#undef putc
#undef ungetc
using std::size_t;
using std::fpos_t;

class File {
  std::FILE* f;
  std::FILE* F(); // Produces checked pointer to f
public:
  File(); // Create object but don't open file
  File(const char* path, const char* mode = "r");
  ~File();
  int open(const char* path, const char* mode = "r");
  int reopen(const char* path, const char* mode);
  int getc();
  int ungetc(int c);
  int putc(int c);
  int puts(const char* s);
  char* gets(char* s, int n);
  int printf(const char* format, ...);
  size_t read(void* ptr, size_t size, size_t n);
  size_t write(const void* ptr, size_t size, size_t n);
  int eof();
  int close();
  int flush();
  int seek(long offset, int whence);
  int getpos(fpos_t* pos);
  int setpos(const fpos_t* pos);
  long tell();
  void rewind();
  void setbuf(char* buf);
  int setvbuf(char* buf, int type, size_t sz);
  int error();
  void clearErr();
};
#endif // FULLWRAP_H ///:~

无输出 只是一个头文件
 
这个类几乎包含了<cstdio>中所有的文件I/O函数

类File的构造函数有一个默认的构造函数

默认构造函数将私有FILE指针f设为0

能设想为标准 控制台 I/O和内核格式化 in-core formatting 读/写一个内存块,
而不是文件或控制台 构造相似的类

在这里遇到的绊脚石是用于可变参数列表函数 variable argument list function
的运行时解释程序

猜你喜欢

转载自blog.csdn.net/eyetired/article/details/81806732