文件流操作

目前主要介绍使用C函数操作文件流,之后待续。。。

读取单个字符操作:

int fgetc (FILE * stream);    // 从文件流中读取一个字符。可将标准输入stdin作为参数。
_Check_return_opt_ _CRTIMP int __cdecl fgetc(_Inout_ FILE * _File);
int fputc (int character,  FILE * stream);
_Check_return_opt_ _CRTIMP int __cdecl fputc(_In_ int _Ch, _Inout_ FILE * _File);
int getc (FILE* stream);    // 与fgetc等效
_Check_return_ _CRTIMP int __cdecl getc(_Inout_ FILE * _File);
int putc (int character, FILE * stream);
_Check_return_opt_ _CRTIMP int __cdecl putc(_In_ int _Ch, _Inout_ FILE * _File);
int getchar ();                   // 从标准输入stdin读入一个字符。相当于fgetc(stdin)。
_Check_return_ _CRTIMP int __cdecl getchar(void);
int putchar(int character);
_Check_return_opt_ _CRTIMP int __cdecl putchar(_In_ int _Ch);

读取字符串操作:

char * fgets (char * str, int num, FILE * stream); 
// 从文件流中读取最多num个字符到字符数组str中,
// 当遇到结束符(如换行符)或者读到num - 1个字符时停止。
// 函数自动在末尾添加 '' 空字符。
_Check_return_opt_ _CRTIMP char * __cdecl fgets(_Out_z_cap_(_MaxCount) char * _Buf, _In_ int _MaxCount, _Inout_ FILE * _File);
int fputs(const char * str, FILE * stream);
_Check_return_opt_ _CRTIMP int __cdecl fputs(_In_z_ const char * _Str, _Inout_ FILE * _File);
char* gets (char * str);    // no commend!!!
// 从标准输入stdin中读取字符串,直到遇到结束符为止。
// 该函数未指定大小,所以一定要注意字符数组的大小。
_Check_return_ _CRTIMP char * __cdecl gets(char * _Buffer);
int puts(const char * str);  // no commend!!!
_Check_return_opt_ _CRTIMP int __cdecl puts(_In_z_ const char * _Str);

早期的Internet蠕虫病毒的实现其中就用到了gets函数。该函数的任务是从文件流中读入一个字符串。调用者将提供读入的字符串存放的位置。但是,该函数并不能检测缓冲区的大小。若调用者提供了一个指向堆栈的指针,并且gets()函数读入的字符串数量超过了缓冲区的大小,该函数会将多出来的字符串继续写入堆栈中,从而覆盖了堆栈中原始内容(缓冲区溢出攻击)。

main ()
{
    char buffer[512];    // 在程序堆栈上申请并分配512个字符空间
    // ... ...
    gets(buffer);        // 病毒执行入口,可将恶意代码通过溢出覆盖堆栈中原始数据
}

文件结束符:EOF

EOF是在stdio.h文件中定义的常量,值为-1。

fputc函数返回值:执行成功返回值就是输出的字符;失败则返回EOF。

fgetc函数读字符时遇到文件结束符,返回文件结束符EOF。

若从磁盘文件中顺序读取字符并在屏幕上显示:

ch = fgetc(fp);
while (ch != EOF) {
    putchar(ch);
    ch = fgetc(fp);
}

EOF是控制字符,不能在屏幕上显示。由于ASCII编码中不可能出现-1,因此EOF这样定义是合适的。当读入的字符值为-1时,表示读入的已经不是正常的ASCII字符了,这样就可以将-1作为文件结束符。

但这种情况只适用于读取文本文件,目前ASCII已经允许使用缓冲文件系统处理二进制文件,而读入某个字节中的二进制数据时有可能是-1。这样就出现了读取数据却提前结束的情况。

正确的做法是我们要使用feof()函数来测试文件的当前状态是否已经结束。

int feof (FILE * stream);
_Check_return_ _CRTIMP int __cdecl feof(_In_ FILE * _File);
ch = fgetc(fp);
while (!feof(fp)) {
    putchar(ch);
    ch = fgetc(fp);
}

参考链接:

http://www.cnblogs.com/duzouzhe/archive/2009/10/24/1589348.html

http://www.jb51.net/article/37688.htm

http://www.blogjava.net/tinysun/archive/2010/07/26/327155.html

原文地址:https://www.cnblogs.com/yooyoo/p/4717924.html