标准IO、文件IO
定义:
标准IO:标准IO是库函数,库函数:针对系统调用的封装,使用方便灵活
文件IO:文件IO是系统调用,系统调用:功能强大,应对复杂场景不够灵活区别:
1.标准IO是库函数,是对系统调用的封装
2.文件IO是系统调用,是Linux内核中的函数接口
3.标准IO是有缓存的
4.文件IO是没有缓存的
5.标准IO可以在Windows或者Linux平台使用
6.文件IO只能在Linux系统平台使用标准IO和文件IO分别可操作的文件:
标准IO可操作的文件(-)
文件IO可操作的文件(b、c、d、l、s、p)标准IO函数:
getchar、putchar、scanf、printf、gets、puts ---> 标准IO
fopen、fclose、fgetc、fputc、fgets、fputs、fread、fwrite、fprintf、fscanf --> 标准IO
得使用头文件 :#include <stdio.h>
文件IO函数:
open、close、read、write -->文件IO
从文件中读写数据的流程:
打开文件 -> 读写文件 -> 关闭文件
fopen fclose
fgetc/fputc 单个字符的读写
fgets/fputs 字符串的读写
fscanf/fprintf 格式化字符串的读写
fread/fwrite 二进制文件的读写
1.fputc
格式:
int fputc(int c, FILE *stream);功能:
向流中写入一个字符参数:
c:写入字符的ASCII码值
stream:文件流指针返回值:
成功返回写入字符的ASCII码值
失败返回EOF注意:
1.fputc只能写入一个字符,写入多个字符需要多次调用fputc
2.fputc只能写入字符
练习: 1.利用fputc向文件file.txt中写入字符串"hello world"
2.搜索fgetc的功能,参数,返回值含义,实现读取文件中所有的内容并显示在界面上
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
char tmpbuff[32] = {"hello world"};
char *pstr = NULL;
fp = fopen("file.txt", "w");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
pstr = tmpbuff;
while (*pstr != '\0')
{
fputc(*pstr, fp);
pstr++;
}
fclose(fp);
return 0;
}
2.fgetc
格式:
int fgetc(FILE *stream);
功能:
从流中读取下一个字符
参数:
stream:文件流指针
返回值:
成功返回读到字符的ASCII码值
失败返回EOF
读到文件末尾返回EOF
练习:
1.用fgetc从一文件中读取一个字符
2.编写程序统计文件的行数
//练习1
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
char ch = 0;
fp = fopen("file.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)
{
ch = fgetc(fp); //要读取第二个字符还是用该语句,第几个都是,遵循顺序原则
if (EOF == ch)
{
break;
}
printf("ch = %c\n", ch);
}
fclose(fp);
return 0;
}
//练习2
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
char ch = 0;
int cnt = 0;
fp = fopen("file.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)
{
ch = fgetc(fp);
if (EOF == ch)
{
break;
}
if ('\n' == ch)
{
cnt++;
}
}
fclose(fp);
printf("cnt = %d\n", cnt);
return 0;
}
2.fgetc/fputc与getchar/putchar的区别(基本无区别)
char ch = 0;
ch = getchar();
ch = fgetc(stdin);char ch = 'a'
putchar(ch);
fputc(ch, stdout);
练习:实现将一个文件中的内容拷贝到另一个文件中
#include <stdio.h>
int main(void)
{
FILE *fsrc = NULL;
FILE *fdst = NULL;
char tmp = 0;
fsrc = fopen("src.txt", "r");
if (NULL == fsrc)
{
perror("fail to fopen");
return -1;
}
fdst = fopen("dst.txt", "w");
if (NULL == fdst)
{
perror("fail to fopen");
return -1;
}
while (1)
{
tmp = fgetc(fsrc);
if (EOF == tmp)
{
break;
}
fputc(tmp, fdst);
}
fclose(fsrc);
fclose(fdst);
return 0;
}
3.fputs
格式:
int fputs(const char *s, FILE *stream);
功能:
向流中写入一个字符串
参数:
s:字符串首地址
stream:文件流指针
返回值:
成功返回非负数
失败返回EOF
练习:向一文件中写入一个字符串
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
char str[32] = {"hello world"};
fp = fopen("file.txt", "w");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fputs(str, fp);
fclose(fp);
return 0;
}
4.fgets
格式:
char *fgets(char *s, int size, FILE *stream);
功能:
从流中读取一个字符串
参数:
s:存放字符串空间首地址
size:最多读取字符的个数(包括函数自己最后在末尾自己添加的'\0')
stream:文件流指针
返回值:
成功返回存放字符串空间的首地址
失败返回NULL
读到文件末尾返回NULL
结束标志:
1.遇到'\n'读取后结束,并在结尾处增加'\0'
2.读满size个满结束
练习:从一文件中获取字符串
#include <stdio.h>
int main(void)
{
FILE *fp = NULL;
char tmpbuff[3] = {0};
fp = fopen("file.txt", "r"); //假设此时文件存在,里边有一串字符hello world
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fgets(tmpbuff, sizeof(tmpbuff), fp); //因为sizeof()结果是3,且函数自带在文件末尾输入'\0'
printf("tmpbuff = %s\n", tmpbuff); //所以打印结果是he
fclose(fp);
return 0;
}
5.fwrite
格式:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:
向流中写入nmemb个对象,每个对象size字节大小,在ptr指向的空间中
参数:
ptr:存放数据空间的首地址
size:每个数据对象的大小
nmemb:数据对象的个数
stream:文件流指针
返回值:
成功返回写入对象的个数
失败返回0
读到文件末尾返回0
练习:使用fwrite向文件中写入一个、多个对象
#include<stdio.h>
typedef struct student
{
char name[20];
char sex;
int age;
int score;
}stu_t;
int main()
{
FILE *fp = NULL;
// stu_t a = {"zhangsan",'m',13,66};
stu_t arr[] = {{"zhangsan",'m',13,66},{"lisi",'w',34,66},{"wangwu",'m',34,44},{"maliu",'w',23,43}};
fp = fopen("file.txt","w");
if(fp == NULL)
{
perror("fail open");
return -1;
}
// fwrite(&a,sizeof(stu_t),1,fp); //写入一个对象
fwrite(&arr,sizeof(stu_t),4,fp); //写入多个对象
//&arr取到了首元素地址,arr也是
fclose(fp);
return 0;
}
6.fread
格式:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:
从流中读取nmemb个对象,每个对象size个字节,存放到ptr指向的空间中
参数:
ptr:存放读取内容空间首地址
size:读取对象的大小
nmemb:读取对象的个数
stream:文件流指针
返回值:
成功返回读到对象个数
失败返回0
读到文件末尾返回0注意:
当文件中有n个对象的时候,用fread读取n+1个对象,此时fread(s,sizeof(stu_t),n+1,fp)这个语句没问题,此时fread读到的对象个数不是n+1个是n个
练习:
以结构体学生作为对象,使用fread进行读取
#include<stdio.h>
typedef struct student
{
char name[20];
char sex;
int age;
int score;
}stu_t;
#if 0
void showstu(stu_t tmpstu) //传值
{
printf("姓名:%s\n",tmpstu.name);
printf("性别:%c\n",tmpstu.sex);
printf("年龄:%d\n",tmpstu.age);
printf("分数:%d\n",tmpstu.score);
}
#endif
void showstu(stu_t* tmpstu) //传址
{
printf("姓名:%s\n",tmpstu->name);
printf("性别:%c\n",tmpstu->sex);
printf("年龄:%d\n",tmpstu->age);
printf("分数:%d\n",tmpstu->score);
}
int main()
{
int i = 0;
stu_t a;
stu_t s[4];
FILE *fp = NULL;
fp = fopen("file.txt","r");
if(fp == NULL)
{
perror("fail to opened!\n");
return -1;
}
#if 0
//读取一个对象
fread(&a,sizeof(stu_t),1,fp);
showstu(a);
#endif
#if 0
//读取多个对象(传值)
fread(s,sizeof(stu_t),4,fp);
for(i= 0;i < 4;i++)
{
showstu(s[i]);
}
#endif
#if 0
//读取多个对象(传址)
fread(s,sizeof(stu_t),4,fp);
for(i= 0;i < 4;i++)
{
showstu(s+i);
}
#endif
fclose(fp);
return 0;
}
练习:
利用fread和fwrite完成将src.jpg图片内容拷贝到dst.jpg图片中
char tmpbuff[4096];
#include<stdio.h>
int main()
{
char arr[4096] = {0};
FILE* fsrc = NULL;
FILE* fdest = NULL;
int r = 0;
fsrc = fopen("src.jpg","r");
if(fsrc == NULL)
{
perror("fail to fsrc\n");
return -1;
}
fdest = fopen("dest.jpg","w");
if(fdest == NULL)
{
perror("fail to fdest\n");
return -1;
}
#if 0
while(1)
{
r = fread(arr,sizeof(arr),1,fsrc); //读取1个对象,每个对象4096个字节
if(r == 0)
{
break;
}
fwrite(arr,sizeof(arr),1,fdest); //写1个对象,每个对象4096个字节
}
#endif
#if 0
//确保dest.jog文件和src.jog相比一个字节不多一个字节不少
while(1)
{
r = fread(arr,1,sizeof(arr),fsrc); //读取4096个对象,每个对象1个字节
if(r == 0)
{
break;
}
fwrite(arr,1,r,fdest); //写r个对象,每个对象1个字节
}
#endif
fclose(fsrc);
fclose(fdest);
return 0;
}
7.fprintf
格式:
int fprintf(FILE *stream, const char *format, ...);
功能:
将格式化字符串输出到stream指向的流中
注释:
fprintf的用法只是在printf的基础上在""(双引号)前边添加文件流指针,使要输出的内容输出在对应文件中
printf("hello world\n");
fprintf(stdout,"hello world\n");
printf("%d",a);
fprintf(fp,"%d",a);
8.fsancf
格式:
int fscanf(FILE *stream, const char *format, ...);
功能:
从流中读取格式化的字符串
注释:
fscanf的用法只是在scanf的基础上在""(双引号)前边添加文件流指针,从文件中读取原本要在键盘上输入的内容
练习:fscanf 具体功能的练习
#include<stdio.h>
int main()
{
FILE* fp = NULL;
int NUM1 = 0;
int NUM2 = 0;
fp = fopen("file.txt","r");
if(fp == NULL)
{
perror("fail to open file.txt");
return -1;
}
fscanf(fp,"NUM1 = %d NUM2 = %d",&NUM1,&NUM2); //此时fp所指的文件中的内容是NUM1 = 100 NUM2 = 200(除此以外的内容编译的时候均会报错)
fclose(fp);
printf("NUM1 = %d NUM2 = %d",NUM1,NUM2);
return 0;
}
9.fopen
格式:
FILE *fopen(const char *pathname, const char *mode);
功能:
打开pathname对应的文件并与其建立一个文件流
参数:
pathname:要打开文件路径的字符串
mode:
r 只读 文件不存在报错,文件存在只读打开
r+ 读写 文件不存在报错,文件存在读写打开
w 只写 文件不存在创建,文件存在将文件内容清空,只写打开
w+ 写读 文件不存在创建,文件存在将文件内容清空,写读打开
a 追加只写 文件不存在创建,文件存在追加只写打开
a+ 追加写读 文件不存在创建,文件存在追加写读打开
返回值:
成功返回打开的文件流指针
失败返回NULL
10.fclose
格式:
int fclose(FILE *stream);
功能:
关闭文件,释放文件流指针
参数:
stream:文件流指针
返回值:
成功返回0
失败返回EOF(-1)
11.open
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:
打开文件并且获得文件描述符
参数:
pathname: 要打开的文件名
flags: 标志位
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_APPEND 追加
O_ASYNC 异步IO
O_CREAT 文件不存在创建
O_TRUNC 文件存在截断(清0)mode: 当flags中出现O_CEEAT时需要加这个参数,用来给文件赋予权限
rwx:创建该文件的用户对文件是否拥有读写执行的权限
rwx:创建该文件用户同组的用户对文件是否拥有读写执行的权限
rwx:其余人是否对文件拥有读写执行的权限
rwx:7
rw-:6
r-x:5
r--:4
-wx:3
-w-:2
--x:1
---:0
返回值:
成功返回文件描述符(很小的非负整数)
失败返回-1新生成的文件描述符总是为尚未被使用的最小的非负整数,一般在stdin、stdout、stderr没有用close关闭的时候最小数是3,关闭那个后最小的便是那个
0: stdin
1: stdout
2: stderr
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int fd = 0;
// 0664
// rw-rw-r--
// fd = open("a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664); //w
// fd = open("a.txt", O_RDONLY); //r
// fd = open("a.txt", O_RDWR); //r+
// fd = open("a.txt", O_RDWR | O_CREAT | O_TRUNC, 0664); //w+
// fd = open("a.txt", O_WRONLY | O_CREAT | O_APPEND, 0664); //a
while (1)
{
fd = open("a.txt", O_RDWR | O_CREAT | O_APPEND, 0664); //a+
if (-1 == fd)
{
perror("fail to open");
return -1;
}
printf("fd = %d\n", fd);
}
return 0;
}
12.close
int close(int fd);
功能:
将fd对应的文件描述符关闭,关闭文件
参数:
fd:open的返回值
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int fd = 0;
char tmpbuff[4096] = {"hello world"};
fd = open("a.txt", O_WRONLY | O_TRUNC | O_CREAT, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
write(fd, tmpbuff, strlen(tmpbuff));
close(fd);
return 0;
}
13.write
ssize_t write(int fd, const void *buf, size_t count);
功能:
向fd对应的文件中写入buf指向的count个字节
参数:
fd:文件描述符
buf:写入数据空间首地址
count:写入的字节数
返回值:
成功返回实际写入字节数
失败返回-1
14.read
ssize_t read(int fd, void *buf, size_t count);
功能:
从文件描述符fd对应的文件中读取count个字节存放到buf开始的空间中
参数:
fd:文件描述符
buf:存放数据空间的首地址
count:想要读取数据字节数
返回值:
成功返回实际读到的字节数
失败返回-1
读到文件末尾返回0
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd = 0;
ssize_t nret = 0;
char tmpbuff[4096] = {0};
fd = open("a.txt", O_RDONLY);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
nret = read(fd, tmpbuff, sizeof(tmpbuff));
printf("nret = %ld\n", nret);
printf("tmpbuff = %s\n", tmpbuff);
close(fd);
return 0;
}
目录IO
1、opendir
man 3 opendir
DIR *opendir(const char *name);
功能:
打开目录获得目录流指针
参数:
name:要打开文件的名称
返回值:
成功返回目录流指针
失败返回NULL
DIR *dp = NULL;
dp = opendir(".");
if (NULL == dp)
{
ERR_MSG("fail to opendir");
return -1;
}
2、closedir
man 3 closedir
int closedir(DIR *dirp);
功能: 关闭目录流指针
closedir("."); //关闭当前目录
3、readdir
man 3 readdir
struct dirent *readdir(DIR *dirp);
功能:
遍历指定目录下的所有文件和子目录
参数:
dirp:目录流指针
返回值:
成功返回读到目录项信息的结构体指针
失败或者读到末尾返回NULL
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};d_ino:通过这个inode能够找到该文件在磁盘中存放的位置
d_off:当前目录项在整个目录流中的偏移量
d_reclen:这条记录的大小
d_type:文件类型
d_name:文件名
DIR *dp = NULL;
struct dirent *pp = NULL;
dp = opendir(".");
if (NULL == dp)
{
ERR_MSG("fail to opendir");
return -1;
}
while (1)
{
pp = readdir(dp); //readdir可以遍历指定目录下的所有文件和子目录
if (NULL == pp)
{
break;
}
if ('.' == pp->d_name[0])
{
continue;
}
printf("%s\n", pp->d_name); //打印当前目录下的所有目录名和文件名(除隐藏目录"."和"..")
}
closedir(dp);
4、mkdir
man 3 mkdir
int mkdir(const char *pathname, mode_t mode);
使用方法: mkdir(filename, 0777); //0代表八进制 7代表111
//777代表 所有者、所属组和其他用户都具有xwr权限
目录中
x:用户是否能够进入目录中
w:用户是否能在目录中新建文件
r:用户是否能够读取目录中的信息
5、rmdir
man 2 rmdir
int rmdir(const char *pathname);
功能: 删除空目录文件
使用方法: rmdir(filename);
6、chdir
man 3 chdir
int chdir(const char *path);
功能:
修改程序当前的工作路径
参数:
path:要切换的路径
返回值:
成功返回0
失败返回-1
7、getcwd
man 3 getcwd
char *getcwd(char *buf, size_t size);
功能:
获得当前工作路径
参数:
buf:将工作路径放入buf对应的空间
size:最多存放字符的个数
返回值:
成功返回存放字符串空间首地址
失败返回NULL