Input/Output with files

C++提供了以下类来将字符输出到文件、从文件读取字符:

ofstream: 写文件流类
ifstream: 读文件流类
fstream: 读写文件流类

上面三个类继承或间接继承于istream\ostream因此使用的方法类似cin\cout
1. 写入text file

#include 
#include 

int main()
{
    std::ofstream output_file;
    /* std::ofstream默认mode是ios::out */
    output_file.open("test.txt", std::ios::out);
    /* 判断是否正确打开文件 */
    if (output_file.is_open())
    {
        /* 输出到文件 */
        output_file << "Writing to a file. The first line.\n";
        output_file << "Writing to a file. The second line.\n";
        output_file << "Writing to a file. The third line.\n";  
    }
    else
    {
        std::cout << "Unable to open a file." << std::endl;
    }
    output_file.close();

    system("pause");
}

上面的代码会在当前工作目录创建test.txt,并将字符串Writing to a file.\n写入其中。
文件读、写的mode如图1所示:

Input/Output with files_第1张图片
图1 Input\Output mode

对于std::ifstream默认的mode是std::ios::in,如果附加了其它mode则会和std::ios::in叠加;对于std::ofstream默认的mode是std::ios::out,如果附加了其它mode则会和std::ios::out叠加;对于std::fstream默认的mode是std::ios::in | std::ios::out,如果附加了其它mode则std::ios::in | std::ios::out不会进行叠加,因此必须明确指定是进行读还是写,否则会出错。

2. 读取text file

#include    /* std::ifstream */
#include   /* std::cout */
#include     /* std::getline() */

int main()
{
    /* 读取text file的每行到line */
    std::string line;
    std::ifstream in_file;
    /* std::ifstream的mode默认是std::ios::in */
    in_file.open("test.txt");
    if (in_file.is_open())
    {
        /* 逐行读取test.txt里的内容到line */
        while (std::getline(in_file,line))
        {
            std::cout << line << std::endl;
        }
        /* 关闭文件 */
        in_file.close();
    }
    else
    {
        std::cout << "File open failed." << std::endl;
    }
    system("pause");
}

输出如图2所示:

ellipse
图2 读取text file

3. 逐字符读取text file并获取当前读取位置

#include 
#include 
#include 

int main()
{
    /* 保存读取的当前字符 */
    char c;
    std::ifstream input_file("test.txt");
    if (input_file.is_open())
    {
        /* 逐字符读取text file */
        while (input_file.get(c))
        {
            std::cout << "当前字符位置: " << input_file.tellg() << std::endl;
            std::cout << "当前字符: " << c << std::endl;
        }
    }

    system("pause");
}

如果test.txt中的内容是The first line.,则该程序输出的结果如图3所示:

Input/Output with files_第2张图片
图3 逐字符读取text file并获取当前读取的位置

4. 逐字符写入text file并获取当前所写字符位置

#include     /* std::ofstream */
#include    /* std::cout */
#include 

int main()
{
    std::string line("The first line.");
    std::ofstream output("test.txt");
    if (output.is_open())
    {
        /* 将line中字符串逐字符输出到test.txt */
        for (auto it = line.cbegin(); it != line.cend(); ++it)
        {
            output << *it;
            /* 显示当前输出字符的位置 */
            std::cout << output.tellp() << std::endl;
        }
    }

    system("pause");
}

上面的代码会在当前工作目录创建test.txt,并将字符串Writing to a file.\n写入其中,控制台的输出如图4所示:

Input/Output with files_第3张图片
图4 逐字符写入text file并获取当前所写字符的位置

5. 对输入流指针进行偏移

#include 
#include 
#include 

int main()
{
    /* 保存std::ifstream重定向到line的字符 */
    std::string line;
    std::ifstream infile("test.txt",std::ios::binary);
    /* 从test.txt的起始位置偏移3个字符 */
    infile.seekg(3, std::ios::beg);
    infile >> line;
    std::cout << line << std::endl;
    infile.close();

    system("pause");
}

如果test.txt中的内容是The_first_line.,则上面代码的输出是_first_line.
6. 对输出流指针进行偏移
有时可能想从已有text file的某个位置开始写入字符,但是企图用seekp进行偏移直接重定向到输出文件是无法达到的。

#include 
#include 
#include 

int main()
{
    std::string line("The_first_line.");
    std::ofstream output("test.txt");
    /* 输出流指针从起始位置向后偏移2个字节 */
    output.seekp(2, std::ios::beg);
    std::cout << output.tellp() << std::endl;
    output << line;
    output.close();

    system("pause");
}

而实际在test.txt中的内容会被清空,新写入的内容见图5:

ellipse
图5 对输出流指针进行偏移

如果将偏移量改为负数,则原有内容会被清空,不会有任何新内容写入。如果不想清空原有内容可加入std::ios::app但是后面seekp不管怎么操作将数据流重定向到文件的时候都是追加在原有内容后面。

7. 修改原有text file内容

#include 

int main()
{
    std::ofstream outfile;
    outfile.open("test.txt");

    /* 下面这句也可用outfile << "This is an apple."; */
    outfile.write("This is an apple.", 17);
    /* tellp()永远指在输出流末尾位置 */
    long pos = outfile.tellp();
    outfile.seekp(pos - 8);
    outfile.write(" sam", 4);

    outfile.close();
}

运行上面程序会在当前目录下创建test.txt,其中的内容是This is a sample.
8. ofstream之write

#include       // std::ifstream, std::ofstream
#include 

int main() {
	std::ofstream outfile("test.txt", std::ofstream::binary);

	std::string astr("Just a test.");

	// write to outfile
	outfile.write(astr.c_str(), astr.size());

	outfile.close();
	return 0;
}

9. ifstream之read

#include 
#include 
#include 

int main()
{
	std::ifstream infile("test.txt", std::ios::binary | std::ios::ate);
	if (infile.is_open())
	{
		/* 由于打开的mode是std::ios::ate,因此输入流指针定位在文件末尾,
		   所以不再需要下面这句;如果没加std::ios::ate则需要加上下面这
		   句使输入流指针定位在文件末尾 */
		/* infile.seekg(0, std::ios::end); */
		/* size是文件的大小 */
		int size = static_cast<int>(infile.tellg());
        /* 将输入流指针重新置到文件头位置 */
		infile.seekg(0, std::ios::beg);
		/* 申请内存,存入读入的内容 */
		char *buffer = new char[size];
		/* 读取size字节存入buffer中 */
		infile.read(buffer, size);
		/* 关闭打开的文件 */
		infile.close();
		std::cout << buffer << std::endl;
		/* 释放内存 */
		delete[] buffer;
	}
	else
	{
		std::cout << "Unable to open file." << std::endl;
	}
	system("pause");
}

10. std::getline

#include 
#include     /* std::getline() */

int main()
{
	std::string line("");
	while (std::getline(std::cin,line))
	{
		std::cout << line << std::endl;
	}

	system("pause");
}

11. std::istream::getline

// istream::getline example
#include      // std::cin, std::cout, std::cin.getline()

int main() {
	char name[256], title[256];

	std::cout << "Please, enter your name: ";
	std::cin.getline(name, 256);

	std::cout << "Please, enter your favourite movie: ";
	std::cin.getline(title, 256);

	std::cout << name << "'s favourite movie is " << title;

	system("pause");
}

12. 刷新输出缓冲区
有时候需要及时的刷新输出缓冲区得到输出的结果。

Input/Output with files_第4张图片
图6 刷新输出缓冲区
比较两种刷新缓冲区方式的差异:
#include          // std::unitbuf
#include      // std::ofstream

int main() {
	std::ofstream outfile("test.txt");
	outfile << std::unitbuf << "Test " << "file" << '\n';  // flushed three times
	outfile.close();  // 在此处加断点
	return 0;
}

在断点处输出的结果是,“test.txt"中的内容是"Test file”。

#include          // std::unitbuf
#include      // std::ofstream

int main() {
	std::ofstream outfile("test.txt");
	outfile << "Test " << std::flush << "file" << '\n';  // flushed only one time
	outfile.close();  // 在此处加断点
	return 0;
}

在断点处输出的结果是,"test.txt"中的内容是"Test "。
比较std::unitbufstd::flush的用法可知前者是将其后的缓冲区进行刷新,后者是将其之前的缓冲区进行刷新。
13. fseek()、fputs()
fseek原型int fseek ( FILE * stream, long int offset, int origin );
fseek()函数的作用是Reposition stream position indicator. Sets the position indicator associated with the stream to a new position.
fputs原型int fputs ( const char * str, FILE * stream );
fputs()函数的作用是Write string to stream. Writes the C string pointed by str to the stream.

#include 

int main()
{
	FILE * pFile;
	pFile = fopen("example.txt", "wb");
	fputs("This is an apple.", pFile);
	/* 将文件流指针从起始位置偏移9位 */
	fseek(pFile, 9, SEEK_SET);
	fputs(" sam", pFile);
	fclose(pFile);

	return 0;
}

运行程序后example.txt中的内容是:“This is a sample.”
14. ftell()
原型long int ftell ( FILE * stream );
ftell()函数的作用是Get current position in stream. Returns the current value of the position indicator of the stream.

/* ftell example : getting size of a file */
#include 

int main ()
{
  FILE * pFile;
  long size;

  pFile = fopen ("example.txt","rb");
  if (pFile==NULL) perror ("Error opening file");
  else
  {
  	/* 将文件流指针从结束位置偏移0位 */
    fseek (pFile, 0, SEEK_END);   // non-portable
    size=ftell (pFile);
    fclose (pFile);
    printf ("Size of example.txt: %ld bytes.\n",size);
  }
  return 0;
}

输出结果是:“Size of example.txt: 17 bytes.”
15. fread()、rewind()
fread原型size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
fread()函数作用是Read block of data from stream. Reads an array of count elements, each one with a size of size bytes, from the stream and stores them in the block of memory specified by ptr.
rewind原型void rewind ( FILE * stream );
rewind()函数作用是Set position of stream to the beginning. Sets the position indicator associated with stream to the beginning of the file.

/* fread example: read an entire file */
#include 
#include 

int main() {
	FILE * pFile;
	long lSize;
	char * buffer;
	size_t result;

	pFile = fopen("example.txt", "rb");
	if (pFile == NULL) { fputs("File error", stderr); exit(1); }

	// obtain file size:
	fseek(pFile, 0, SEEK_END);
	lSize = ftell(pFile);
	rewind(pFile);

	// allocate memory to contain the whole file:
	buffer = (char*)malloc(sizeof(char)*lSize);
	if (buffer == NULL) { fputs("Memory error", stderr); exit(2); }

	// copy the file into the buffer:
	result = fread(buffer, 1, lSize, pFile);
	/* 读取成功则返回值应该和文件大小相同 */
	if (result != lSize) { fputs("Reading error", stderr); exit(3); }

	/* the whole file is now loaded in the memory buffer. */

	// terminate
	fclose(pFile);
	free(buffer);
	return 0;
}

16. fgets()、puts()
fgets()函数原型char * fgets ( char * str, int num, FILE * stream );
作用:Get string from stream. Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
puts()函数原型int puts ( const char * str );
作用:Write string to stdout. Writes the C string pointed by str to the standard output (stdout) and appends a newline character (’\n’).

#include 

int main()
{
	FILE * pFile;
	char mystring[100];

	pFile = fopen("example.txt", "r");
	if (pFile == NULL) perror("Error opening file");
	else {
		if (fgets(mystring, 100, pFile) != NULL)
			puts(mystring); /* 输出到控制台,会在字符串末尾自动添加换行符 */
		fclose(pFile);
	}
	return 0;
}

如果"example.txt"中的内容是两行:

The First line.
The Second line.

则控制台的输出结果为:The First line.
17. gets()
gets()函数原型char * gets ( char * str );
作用:Get string from stdin. Reads characters from the standard input (stdin) and stores them as a C string into str until a newline character or the end-of-file is reached.

#include 

int main()
{
	char string[256];
	printf("Insert your full address: ");
	gets(string);     // warning: unsafe (see fgets instead)
	printf("Your address is: %s\n", string);
	return 0;
}

运行此段程序输入什么,就会相应的在控制台打印什么,类似std::cin的作用。

18. C语言判断文件(夹)是否存在、创建文件夹

#include      // access
#include  // _mkdir

/* int _access(char const* _FileName,  int _AccessMode);
   filename:文件夹路径或者文件路径
   mode:
   0 (F_OK) 只判断是否存在
   2 (R_OK) 判断写入权限
   4 (W_OK) 判断读取权限
   6 (X_OK) 判断执行权限
   当 mode=0 时,可用于判断目录(文件夹)/ 文件是否存在;
   当 mode=2,4,6,时,只适用于文件的判断。 */
/* int _mkdir(char const* _Path); */
int main()
{
	char root_path[200] = "C:/folder";
	if (_access(root_path, 0) == -1) // 返回值是-1说明文件(夹)不存在
	{
		_mkdir(root_path);
	}

	return 0;
}

你可能感兴趣的:(C++,Input/Output)