I : input 输入。 数据从外部存储设备到主存中 。
O : output 输出 。数据从主存输出到外部存储设备中。
注意点:
举个栗子:
类似于:
scanf()
if(OS == windows)
{
file_read(); //windows的文件IO函数
}
else if(OS == Linux)
{
read(); //Linux的文件IO函数;
}
注意:
FILE结构体成员:
```c
vi -t 命令
这个命令可以查看系统定义好的 系统定义好的变量、宏、数据类型。
格式:
vi -t FILE
安装ctags软件后才能使用vi -t
1)sudo apt-get install ctags
2)cd /usr/include/
3)sudo ctags -R
4)vim ~/.vimrc中添加 set tags+=/usr/include/tags
```
```c
1.vi -t FILE
若有出现选项界面,就输入数字按回车,typedef struct _IO_FILE FILE;
2.追入struct _IO_FILE
追代码:
方法1:将光标停留在要追的字符上, 按下ctrl + ]
方法2:ctrl + 鼠标左键点击要追的内容
返回上层:
方法1:ctrl + t
方法2:ctrl + 鼠标右键
```
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
FILE* stdin
标准输入(读),对应终端文件。即从终端读取数据。
scanf getchar gets等函数,默认封装的就是stdin流指针;
FILE* stdout
标准输出(写),对应终端文件,行缓冲。即将数据输出到终端。
printf putchar puts等函数,默认封装的就是stdout流指针;
FILE* stderr
标准错误输出,对应的终端文件。即将数据输出到终端。无缓冲。
perror,默认封装的就是stderr流指针;
fopen / fclose 打开/关闭文件
fprintf / fscanf 写/读
fputc / fgetc
fputs / fgets
fwrite / fread
fseek 修改文件偏移(理解为:修改光标位置)
ftell 获取文件偏移量。
功能:
打开一个文件;
原型:
#include
FILE *fopen(const char *pathname, const char *mode);
参数:
char *pathname:指定要打开的文件路径以及名字;
char *mode:打开方式;
返回值:
成功,返回FILE*类型指针;
失败,返回NULL; 更新errno;
mode:
r 以只读的方式打开文件;若要读文件,则从文件开头开始读取;
若文件不存在,则文件打开失败;
r+ 以读写的方式打开文件,若要读写数据,则从文件开头开始;
若文件不存在,则文件打开失败;
w 以写的方式打开文件,若要写入数据,则从文件开头开始;
若文件不存在,会创建文件;
若文件存在,则清空文件;
w+ 以读写的方式打开文件,若要读写数据,则从文件开头开始;
若文件不存在,会创建文件;
若文件存在,则清空文件;
a 以写的方式打开文件,
若文件不存在,会创建文件;
若文件存在,若要写入数据,则从文件结尾开始(追加写入);
a+ 以读写的方式打开文件,
若文件不存在,会创建文件;
若文件存在,则初始位置根据操作来决定:
读操作:则初始位置在文件开头
写操作:则初始位置文件结尾;
功能:
关闭文件,释放内存空间
原型:
#include
int fclose(FILE *stream);
参数;
FILE *stream:指定要关闭的文件对应的流指针;
返回值:
成功,返回0;
失败,返回EOF,更新errno;
# define EOF (-1)
errno
错误码,不同的错误,会对应不同的错误码;
errno
是包含在stdio.h中的函数的一个返回值;
若要使用errno,需要包含stdio.h的头文件;
errno中有133种错误。
sudo vim /usr/include/asm-generic/errno-base.h
sudo vim /usr/include/asm-generic/errno.h
功能:
根据errno打印对应的错误信息;
原型:
#include
void perror(const char *s);
参数:
char *s:用于提示的字符串;
功能:
将数据格式化输出到指定文件中; (写)
原型:
#include
int fprintf(FILE *stream, const char *format, ...);
参数:
FILE *stream:指定要将数据写到哪个文件中,就填哪个文件对应的流指针;
char *format:格式化输出字符串:字符串,转义字符,占位符;
...:不定参数,不定数据类型,不定数据个数;
返回值:
成功,返回成功被打印的数据字符数;
失败,返回负数;
功能:
从指定文件中格式化获取数据(读);
fscanf、scanf,使用%s, %d, %f等占位符,默认不获取空格,\n,\t字符
若想获取上述字符,可以使用%c获取;
原型:
#include
int fscanf(FILE *stream, const char *format, ...);
参数:
FILE *stream:指定从哪个文件中读取数据,就填哪个文件对应的流指针;
char *format:格式化输入字符串:字符串,转义字符,占位符;
...:不定参数,不定数据类型,不定数据个数;
返回值:
>0, 成功读取到的数据个数;
=-1,不更新errno,文件读取完毕
=-1,更新errno,函数运行失败;
功能:
向指定文件输出单个字符;(写)
原型:
#include
int fputc(int c, FILE *stream);
参数:
int c:指定要输出的字符对应的整型形式,或者字符形式;例如‘a’ 或者97
FILE *stream:指定要输出到哪个文件中,就文件对应的流指针;
返回值:
成功,返回成功输出的字符对应的整型形式;
失败,返回EOF;
Linux操作系统:
当用编辑器打开文件保存退出后,会检测文件结尾是否是\n结尾,
若不是\n结尾,则会自动添加一个\n
Unix :\r\n结尾
Linux :\n结尾
windows :\r结尾
\r:回车,将光标移动到该行的起始位置
\b:回退,将光标往前移动一格。
功能:
从指定文件中读取单个字符;
原型:
#include
int fgetc(FILE *stream);
参数:
FILE *stream:指定要从哪个文件中获取数据;
返回值:
成功,返回成功获取到的字符对应的整型形式;
失败或者文件读取完毕,返回EOF
// 计算缓冲区大小
//当只申请不使用的时候,由于操作系统优化,此时不会真正申请缓冲区
fputc('a', fp);
printf("%ld\n", fp->_IO_buf_end - fp->_IO_buf_base);
功能:
刷新输出流指针;
原型:
#include
int fflush(FILE *stream);
功能:
退出进程,只要运行到这个函数,就能让程序结束;
原型:
#include
void exit(int status);
参数:
int status:目前随便填一个整数,0, 1,100,1000等
printf("%ld\n", stdout->_IO_buf_end - stdout->_IO_buf_base);
功能:
刷新输出流指针;
原型:
#include
int fflush(FILE *stream);
fflush(stdout);
功能:
退出进程,目前大家理解为只要运行到这个函数,就能让程序结束;
原型:
#include
void exit(int status);
参数:
int status:目前随便填一个整数,0, 1,100,1000等
功能:
将字符串输出到指定文件中; 不会自动换行
原型:
#include
int fputs(const char *s, FILE *stream); 不会自动换行
int puts(const char *s); 会自动换行
char str[20]="hello"; puts(str);
参数:
char *s:指定要输出的字符串的首地址;
FILE *stream:指定要将数据输出到哪个文件中,填对应的流指针变量;
返回值:
成功,返回非负数;
失败,返回EOF
功能:
从指定文件中获取字符串,
1. 该函数当停止获取后,会自动在最后一个字符后面补充'\0',确保获取到的是字符串;
哪怕越界了也会在后面补充'\0'
3. 会获取空格,且获取空格后,该函数不会停止。
4. 会获取\n,且获取\n后,该函数停止读取;
原型:
#include
char *fgets(char *s, int size, FILE *stream);
参数:
char *s:将获取到的数据存储到该指针指向的内存空间中;
int size:最多获取size-1个字节;
FILE *stream:从哪个文件中获取,填对应的流指针;
返回值:
成功,返回char*s存储的地址;
失败或者文件读取完毕,返回NULL,且没有数据被读取出来;
有下列代码,若从终端输入12345后按下回车。请问下列可能出现的结果为:B D_。
char buf[6];
fgets(buf, 7, stdin);
printf("%s\n", buf);
A. 12345 B. 12345\n C.12345\n乱码 D. 段错误
ps: 该函数当停止获取后,会自动在最后一个字符后面补充'\0',确保获取到的是字符串;越界也会补充
功能:
向指定文件中输出数据,(写); 会将数据转换成二进制输出输出。
二进制数据:
将数据拆成一个一个的字节,将对应的字符形式写入到文件中
原型:
#include
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
void *ptr:指定要输出的数据首地址,void*:可以输出任意类型数据;
size_t size:每个数据的字节数
size_t nmemb:指定要输出的数据个数;
注意点:
真实输出的数据总大小为:size*nmemb
例如要输出int arr[3]这个数组: size nmemb
4 3
12 1
1 12
FILE *stream:指定要将数据输出到哪个文件,就填哪个文件对应的流指针;
返回值:
成功,返回成功输出的数据个数;
失败,返回小于指定要输出的数据个数或者等于0;
是0的话,则会以^@的形式表示,有些编辑器可能会以NULL形式表示
功能:
从指定的文件中读取二进制数据,转换成对应的数据类型;(以什么形式写入,就以什么形式读取)
注意:
fread函数不会自动补充\0字符,若要\0字符,则需要手动添加。
原型:
#include
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
void *ptr:指定用于存储读取到的数据的内存空间首地址,void*:可以读取任意类型数据;
size_t size:每个数据的字节数
size_t nmemb:指定要读取的数据个数;
注意点:
真实读取的数据总大小为:size*nmemb
FILE *stream:指定要从哪个文件中读取数据,就填哪个文件对应的流指针;
返回值:
成功,返回成功读取的数据个数;
失败获取读取到文件结尾,返回小于指定要读取的数据个数或者等于0;
功能:
修改文件偏移量;
原型:
#include
int fseek(FILE *stream, long offset, int whence);
参数:
FILE *stream:指定要修改哪个文件的偏移量,填对应的流指针;
long offset :距离whence的偏移量,
若想要往文件开头方向偏移,填负数,
若想往文件结尾方向偏移,填正数.
int whence:
SEEK_SET 文件开始位置,
SEEK_CUR 文件当前位置,
SEEK_END 文件结尾位置;
返回值:
成功,返回0;
失败,返回-1,更新errno;
将偏移量修改到文件开头:
void rewind(FILE *stream); ===>等价于fseek(fp, 0, SEEK_SET);
当偏移量在文件开头的时候,能否继续往前偏移。 不能
当偏移量在文件结尾的时候,能否继续往后偏移。 能
以w或者w+形式打开文件,在文件结尾往后偏移n个字节后,写入数据,此时操作系统会自动给这个n个字节补充0,即补充^@
以a或者a+形式打开文件,在文件结尾往后偏移n个字节后,写入数据。此时会找到文件最后一个非0数据,在该数据后面写入数据
功能:
获取文件当前位置到文件开头的偏移量(字节为单位);
原型:
#include
long ftell(FILE *stream);
参数:
FILE *stream:指定要获取哪个文件的偏移量;
返回值:
文件当前位置到文件开头的偏移量(字节为单位);
//将偏移量修改到文件结尾
fseek(fp, 0, SEEK_END);
//获取文件结尾位置到文件开头的偏移量,即文件大小
long size = ftell(fp);
printf("size = %ld\n", size);
手动创建一个usr.txt文件,其中存储用户的账户密码,
一行一个账户密码,中间用空格隔开。
例如:
zhangsan aaaa
lisi bbbb
wangwu cccc
需求如下:
从终端获取一个账户,密码。判断该账户密码是否正确
若账户不存在,则输出账户不存在
若账户存在,密码错误,则输出密码错误
若账户密码均正确,则输出登录成功。
计算一个文件的大小
计算一个文件有几行。
封装成函数
我写的:
1.
#include
#include
#include
int main(int argc, const char *argv[])
{
FILE *fp1 = fopen("lalala.txt", "r");
if (NULL == fp1)
{
perror("fopen fp1:");
}
FILE *fp2 = fopen("2.txt", "w");
if (NULL == fp2)
{
perror("fopen fp2:");
}
char c;
while (1)
{
c = fgetc(fp1);
if (EOF == c)
{
break;
}
fputc(c, fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
#include
#include
#include
#include
int main(int argc, const char *argv[])
{
/*
FILE *fp =fopen("usr.txt","w+");
fprintf(fp,"zhangsan aaaa\n");
fprintf(fp,"lisi bbbb\n");
fprintf(fp,"wangwu cccc\n");
fclose(fp);
*/
FILE *fp = fopen("usr.txt", "r");
if (NULL == fp)
perror("fopen");
char input_name[64] = "";
char input_pwd[64] = "";
printf("请输入用户名:");
scanf("%s", input_name);
printf("请输入密码:");
scanf("%s", input_pwd);
char name[64] = "", pwd[64] = "", temp[64];
int flag_name = 1, flag_pwd = 1;
while (1)
{
memset(name, 0, 64);
memset(pwd, 0, 64);
// 获取name
fscanf(fp, "%s", temp);
strcpy(name, temp);
// 获取pwd
memset(temp, 0, 64);
fscanf(fp, "%s", temp);
strcpy(pwd, temp);
// 比较
if (!strcmp(input_name, name))
{
flag_name = 0;
if (!strcmp(input_pwd, pwd))
{
flag_pwd = 0;
break;
}
}
if (0 == *temp)
break;
}
if (flag_name)
{
printf("账户不存在\n");
return 0;
}
else if (flag_pwd)
{
printf("密码错误\n");
return 0;
}
printf("登录成功\n");
fclose(fp);
return 0;
}
#include
#include
#include
int get_size(char *s);
int get_line(char *s);
int main(int argc, const char *argv[])
{
char *s = "usr.txt";
printf("size = %d\n", get_size(s));
printf("line = %d\n", get_line(s));
return 0;
}
int get_size(char *s)
{
FILE *fp = fopen(s, "r");
if (NULL == fp)
perror("fopen");
char c;
int count = 0;
while (1)
{
c = fgetc(fp);
if (EOF == c)
{
break;
}
++count;
}
fclose(fp);
return count;
}
int get_line(char *s)
{
FILE *fp = fopen(s, "r");
if (NULL == fp)
perror("fopen");
char c;
int count = 0;
while (1)
{
c = fgetc(fp);
if ('\n' == c)
{
++count;
}
else if (EOF == c)
{
++count;
break;
}
}
fclose(fp);
return count;
}