
1.Linux常用的文件IO API
open、close、write、read、lseek。
2.文件操作的一般步骤
(1)open 打开一个文件,得到一个文件描述符,然后对文件进行读写操作(或其他操作),最后 close 关闭文件即可。
(2)文件平时是存放在文件系统中的块设备,我们把这种文件叫静态文件。当我们去 open打开一个文件时, Linux 的内核操作包括:在进程中建立一个打开文件的数据结构,记录下打开的这个文件;然后申请一段内存,将静态文件的内容从块设备读取到内存中的特定地址管理存放,称为动态文件。
(3)文件打开后,针对这份文件的读写操作,都是针对这份动态文件的。当我们 close 关闭动态文件时,内核就将内存中的动态文件更新到块设备中的静态文件。
(4)常见现象:打开一个大文件时比较慢;写了一半的文件如果没保存直接关机,重启后文件内容丢失。
3.文件描述符
1.open函数原型
#includeint open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 返回值:成功返回新分配的文件描述符,出错返回-1并设置errno。
flag的常用选项(前面三个常数中必须指定一个,且仅允许指定一个)有:
| flag选项 | 功能 |
|---|---|
| O_RDONLY | 只读 |
| O_WRONLY | 只写 |
| O_RDWR | 读写 |
| O_CREAT | 创建一个文件 |
| O_EXCL | 检测文件是否存在,对于文件已经存在的情况下,会报错而不是重新创建 |
| O_TRUNC | 打开文件覆盖 |
| O_APPEND | 打开文件追加 |
写阻塞等待( O_SYNC)与非阻塞(O_NONBLOCK)方式打开设备文件:
open()创建文件的权限:mode &(~umask)
比如:
umask=0022 —>0777-0022=0755
所以,设置权限之前要将默认权限关闭umask(0);。
2.close函数原型
#includeint close(int fd) 返回值:成功返回0,出错返回-1并设置errno。
需要说明的是,当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在进程终止时内核也会自动关闭它打开的所有文件。
3.write函数原型
#includessize_t write(int fd, const void * buf, size_t count); 函数说明:write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。 返回值:如果顺利write()会返回实际写入的字节数(len)。当有错误发生时则返回-1,错误代码存入errno中。
附加说明:
4.read函数原型
#includessize_t read(int fd, void * buf, size_t count); 函数说明:read()会把参数fd所指的文件传送count 个字节到buf 指针所指的内存中。 返回值:返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据。若参数count 为0, 则read()不会有作用并返回0。另外,以下情况返回值小于count。 (1)读常规文件时,在读到count个字节之前已到达文件末尾。例如,距文件末尾还有50个字节而请求读100个字节,则read返回50,下次read将返回0; (2)对于网络套接字接口,返回值可能小于count,但这不是错误,详细解释参考这篇文章https://blog.csdn.net/hhhlizhao/article/details/73912578
注意:读位置指针,也不会自动移动。但是如果读之前写过文件,指针会在后面,此时读不到写的内容,这时需配合lseek函数使用。
5.lseek函数原型
函数目的:调整读写的位置指针。
#include#include off_t lseek(int fd, off_t offset, int whence); 参数说明: fd - 当前文件的文件inode; offfset - 偏移量,每读写操作所移动的距离,单位是字节的数量。可正负; whence - 当前位置的基点,有三个标志: ①SEEK_SET:文件的开头; ②SEEK_CUR:文件指针的当前位置; ③SEEK_END:文件的结尾。 返回值:-1时出错;成功时,文件指针的当前位置
如果先对一个文件写入若干字节的内容后立即去读取的话, 是读不到刚写入的内容的,因为此时文件指针已经被 write 移动到了该内容后面。
三、文件IO例子实现cp命令的实现例子
#include第二章 Linux中的标准IO 一、标准IO基本介绍#include #include #include int main(int argc, char *argv[]) { int rd_fd, wr_fd; char read_buf[128] = {0}; char write_buf[128] = {0}; int rd_ret = 0; if(argc <3) { printf("please input src file and des file n"); return -1; } rd_fd = open(argv[1],O_RDONLY); if(rd_fd < 0 ) { printf("open src file %s failuren",argv[1]) return -2; } wr_fd = open (argv[2],O_WRONLY); if(wr_fd <0) { printf("open des file %s failuren",argv[2]) return -3; } while(1) { rd_ret = read(rd_fd,read_buf,128); if(rd_ret < 128) break; write(wr_rd,read_buf,rd_ret); memset(wr_fd,read_buf,re_ret); } write(wr_rd,read_buf,rd_ret); close(rd_fd); close(wr_fd); }
1.文件IO与标准IO的区别
(1)概念
区别
2.Linux常用的标准IO API
| 类型 | 文件IO函数 | 标准IO函数 |
|---|---|---|
| 打开 | open | fopen |
| 关闭 | close | fclose |
| 移位 | lseek | fseek、rewind |
| 读写 | read、write | 比较多,分为全缓存、航缓存和无缓存 |
| 读写类型 | 文件IO函数 | 标准IO函数 |
|---|---|---|
| 读 | read | getc,fgetc,getchar, |
| 写 | write | putc,fputc,putchar,fputs,puts,fwrite |
3.标准IO缓存机制
全缓冲
只有在写满缓存时再进行I/O操作。注意,对于驻留在磁盘上的文件来说通常是由标准IO库实施全缓冲。
读:fread 写:fwrite
行缓冲
在遇到新换行符n或写满缓存时,才会进行I/O操作。注意,当流涉及终端的时候,通常使用的是行缓冲。
遇到换行符(n)或写满缓存时,调用系统调用函数:stdout
读:fgets,gets,printf,fprintf,sprintf
写:fputs,puts,scanf
无缓冲
无缓冲指的是标准IO库不对字符进行缓冲存储。注意,标准出错流stderr通常是无缓冲的。
无缓存 stderr
1.fopen、fclose函数原型
头文件:#include函数原型: FILE *fopen(const char *path, const char *mode); 返回值: 成功 返回FILE * 类型的指针指向你要打开文件; 失败 返回NULL。 函数参数:const char *path ----> 打开文件的位置 const char *mode ----> 文件权限 "b" 以二进制模式打开文件 "r" 以只读的方式打开文件,文件必须存在 "r+" 以可读可写的方式打开文件,文件必须存在 "w" 以只写的方式打开文件,如果文件存在就清空,如果文件不存在就创建 "w+" 以可读可写的方式打开文件,如果文件存在就清空,如果文件不存在就创建 "a" 追加方式,如果文件不存在就新建 "a+" 以读取和追加(文件末尾的写入),如果文件不存在,则创建它。
补充:
fopen()函数创建的文件权限(umask=0)是666,和umask有关。默认情况下umask为022,666-022=644。
函数原型: int fclose(FILE *fp); 返回值: 成功 返回0 失败 返回feof()监测 函数参数:FILE *fp 文件描述符
注意: fclose会将缓存中的内容强制写入文件中,包含了fflush的功能。
2.fputs、fgets、fflush函数原型
//从文件stream读取size个字节的数据放到指针s中 char *fgets(char *s, int size, FILE *stream); 返回值:如果成功返回读到的字符串的首地址指针s;否则,如果已处在文件尾端或出错为null int puts(const char *s, FILE *stream); 返回值:如果成功返回非负值;否则,出错则为EROF -1
int fflush(FILE *stream);
fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃[非标准],一般用不到;
fflush(stdout) 是行缓存,刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上;
stderr 是无缓存,会直接写到内核。
注意: 读写操作同样存在位置指针
3.gets、puts函数原型
gets、puts函数参考链接
gets、puts:行缓存的读写函数。
char *gets(char *s); int puts(const char *s);
gets和fgets的区别:
puts和fputs的区别:
4.fseek、rewind、ftell函数原型
fseek、rewind、ftell函数参考链接
调整文件的读写位置。
int fseek(FILE *stream, long offset, int whence); 返回值:成功 返回0 失败 返回-1 注意:lseek和fseek函数输入参数相同,但返回值不一样 参数:FILE *stream FILE * 文件 long offset 偏移量 int whence 偏移的位置 SEEK_SET 文件的开头 SEEK_CUR 当前的位置 SEEK_END 文件的末尾 long ftell(FILE *stream); 返回值:成功 返回文件当前位置距离文件开头的字节数 失败 返回-1 void rewind(FILE *stream);//将文件的偏移设置为起始位置,函数没有返回值
例子:
fseek(filep1,0,SEEK_SET);//将文件的偏移设置为起始位置 long ftell(filep1);相当于fseek(filep1,0,SEEK_END); void rewind(filp1)//等价于fseek(filep1,0,SEEK_SET)
5.fprintf、fscanf、sprintf、sscanf、printf函数原型
printf 只能输出到显示器中。
1) fprintf:可以输出到文件中,也可输出到显示器。 int fprintf(FILE *stream, const char *format, ...); 参数: FILE *stream FILE * 文件名 const char *format 字符串 ... 例子:fprintf(filep,"hello%s%d%.2fn",buf,year,d); 2) sprintf:输出内容到一个字符串中。 int sprintf(char *str, const char *format, ...); //按照你指定的格式拼接字符串,比strcat要厉害 参数: char *str 字符串拼接指定位置 const char *format 字符串格式 ... 例子:sprintf(buf0,"%sworld-%d-%d-%d",buf,year,month,day); 3) int fscanf(FILE *stream, const char *format, ...); 参数:FILE *stream FILE * 文件名 const char *format 字符串 ... 往文件里面添加内容 4) int sscanf(const char *str, const char *format, ...); //按照你指定的格式拆分字符串 参数: char *str 字符串拆分指定位置 const char *format 字符串格式 ... 例子:sscanf(time,"%d-%d-%d",&year,&month,&day);//访问的是地址 &
6.fputc、fgetc、getc、putc函数原型
fgets,fputs,fputc,fgetc总结
fputc fgetc:一个字符读写函数。
int fgetc(FILE *stream);//从文件中读取一个字符,等价于fread(buf,1,1,stream); 返回值:你读取到的那个字符的ASCII码 int fputc(int c, FILE *stream);//往文件中写入一个字符 参数说明:第一个参数为要写的字符,第二个参数为文件流。 返回值:成功则返回输入的字符,出错EOF。 int getc(FILE *stream);//从文件当中读取一个字符 返回值:你读取到的那个字符的ASCII码 int putc(int c, FILE *stream);//往文件中写入一个字符
注意:
fputc对于换行符也是可以读入的;fputc有缓存,但不是行缓存函数。
思考怎么通过代码验证???
7.getchar、putchar函数原型
调用getchar()相当于调用fgetc(stdin)。
调用putchar©相当于调用fputc(c, stdout)
#includeint getchar(void);//监测缓冲区的回车字符 int putchar(int c); //打印字符
8.feof、ferror、clearerr函数原型
feof、ferror、clearerr函数参考链接
feof 判断是否已经到文件结束;
ferror 判断是否读写错误;
clearerr 清除流错误。
int feof(FILE *stream); 函数功能:判断是否已经到文件结束。 返回值:到达文件结束,返回非0;没有则0 int ferror(FILE *stream); 函数功能:判断是否读写错误。 int clearerr(FILE *stream); 函数功能:清除流错误。
9.fstat函数原型
获取文件属性。
头文件:#includeint fstat(int fildes, struct stat *buf); 返回值:成功 返回0 失败 返回-1 参数: int fildes 你要获取属性的那个文件的文件描述符 struct stat *buf 存放你获取到的文件属性
10.fread、fwrite函数原型
文件的全缓存读写。
头文件:#include函数原型: size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 函数参数:void *ptr ----> 存储空间名 size_t size ---->每一个数据块的大小 单位:字节 size_t nmemb ---->打算读取多少个数据块 FILE *stream ---->文件类型的FELE *的文件指针 返回值: 成功 返回读取到完整的数据块的个数 失败 返回0或者小于的数 判断文件是否读完不要在用返回值判断,新方式feof()判断 size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
fwrite有缓存,不是行缓存,是全缓存。
三、标准IO例子1.实现cat
#include "stdio.h"
#include "fcntl.h"
#include "unistd.h"
#include "string.h"
int main(int argc, char** argv)
{
FILE *src_fp;
int read_ret;
if(argc < 2)
{
printf("please input src filen");
return -1;
}
src_fp=fopen(argv[1],"r");
if(src_fp ==NULL)
{
printf("open src file %s failuren",argv[1]);
return -1;
}
printf("open drc file %s sucessn",argv[1]);
// start read write
while(1)
{
read_ret = fgetc(src_fp);
if(feof(src_fp))
{
printf("read file %s endn",argv[1]);
break;
}
fputc(read_ret,stdout);
}
fclose(src_fp);
return 0;
}
2.比较read/write,fgetc/fputc效率
文件io
// read.c #include#include #include #include int main(int argc,char **argv) { int src_fd,des_fd; int read_ret=0; char buf[128]={0}; if(argc <3) { printf("please input src and des filen"); return -1; } src_fd = open(argv[1],O_RDONLY); if(src_fd<0) { printf("open src file %s failuren",argv[1]); return -2; } printf("open src file %s sucessn",argv[1]); des_fd=open(argv[2],O_CREAT | O_WRONLY,0777); if(des_fd<0) { printf("open des file %s failuren",argv[2]); return -3; } printf("open des file %s sucessn",argv[2]); //start resd write while(1) { read_ret=read(src_fd,buf,128); write(des_fd,buf,read_ret); if(read_ret<128) { printf("raed file %s end!n",argv[1]); break; } } write(des_fd,buf,read_ret); close(src_fd); close(des_fd); return 0; }
标准io函数
//fgetc.c #include#include #include #include int main(int argc,char **argv) { FILE *src_fp,*des_fp; int read_ret=0; if(argc <3) { printf("please input src and des filen"); return -1; } src_fp = fopen(argv[1],"r"); if(src_fp==NULL) { printf("open src file %s failuren",argv[1]); return -2; } printf("open src file %s sucessn",argv[1]); des_fp=fopen(argv[2],"w"); if(des_fp==NULL) { printf("open des file %s failuren",argv[2]); return -3; } printf("open des file %s sucessn",argv[2]); //start resd write while(1) { read_ret=fgetc(src_fp); fputc(read_ret,des_fp); if(feof(src_fp)) { printf("raed file %s end!n",argv[1]); break; } } fclose(src_fp); fclose(des_fp); return 0; }
| 类型 | read/write | fgetc/fputc |
|---|---|---|
| real | 0.131s | 0.533s |
| user | 0.016s | 0.366s |
| sys | 0.115s | 0.134s |
3.比较fgets/fputs、fread/fwrite效率
//fgets.c #include#include #include #include int main(int argc,char **argv) { FILE *src_fp,*des_fp; int read_ret=0; char readbuf[128]={0}; if(argc <3) { printf("please input src and des filen"); return -1; } src_fp = fopen(argv[1],"r"); if(src_fp==NULL) { printf("open src file %s failuren",argv[1]); return -2; } printf("open src file %s sucessn",argv[1]); des_fp=fopen(argv[2],"w"); if(des_fp==NULL) { printf("open des file %s failuren",argv[2]); return -3; } printf("open des file %s sucessn",argv[2]); //start resd write while(1) { fgets(readbuf,128,src_fp); fputs(readbuf,des_fp); if(feof(src_fp)) { printf("raed file %s end!n",argv[1]); break; } } fclose(src_fp); fclose(des_fp); return 0; }
//fread.c #include#include #include #include int main(int argc,char **argv) { FILE *src_fp,*des_fp; int read_ret=0; char readbuf[128]={0}; if(argc <3) { printf("please input src and des filen"); return -1; } src_fp = fopen(argv[1],"r"); if(src_fp==NULL) { printf("open src file %s failuren",argv[1]); return -2; } printf("open src file %s sucessn",argv[1]); des_fp=fopen(argv[2],"w"); if(des_fp==NULL) { printf("open des file %s failuren",argv[2]); return -3; } printf("open des file %s sucessn",argv[2]); //start resd write while(1) { read_ret=fread(readbuf,1,128,src_fp); fwrite(readbuf,1,read_ret,des_fp); if(read_ret<128) { printf("raed file %s end!n",argv[1]); break; } } fwrite(readbuf,1,read_ret,des_fp); fclose(src_fp); fclose(des_fp); return 0; }
| 类型 | read/write(上一节例子) | fgetc/fputc(上一节例子) | fgets/fputs | fread/fwrite |
|---|---|---|---|---|
| real | 0.131s | 0.533s | 0.059s | 0.049s |
| user | 0.045s | 0.366s | 0.006s | 0.011s |
| sys | 0.087s | 0.134s | 0.052s | 0.008s |
故效率,fread/fwrite > fgets/fputs > fgetc/fputc。
第三章 目录IO 一、目录IO基本介绍1.头文件及常用的IO API
#include#include
1.mkdir函数原型
新建目录。
#include函数原型: int mkdir(const char *path, mode_t mode); 参数: const char *path ----》欲创建的目录文件路径 mode_t mode ----》新建文件的权限 0777
注意:生成的目录权限仍和umask有关系,默认umask=0022.
2.opendir、closedir函数原型
目录的打开、关闭。
#include#include 函数原型: DIR *opendir(const char *name); 返回值: 成功 返回DIR类型的指针指向你打开的目录 失败 返回NULL 参数: const char *name 完整的目录路径 返回值: 成功返回目录流指针,出错返回NULL。 int closedir(DIR *dirp);//结构体指针
3.readdir函数原型
目录的读取。
#includestruct dirent *readdir(DIR *dirp); 返回值:成功则为struct dirent指针,若在目录尾或出错则返回NULL。 dirent结构体定义在头文件dirent.h中: struct dirent { ino_t d_ino; off_t d_off; unsigned short d_reclen; unsigned char d_type; char d_name[256]; };//存放的是目录当中的每个文件的相关信息 文件类型d_type判断: DT_BLK This is a block device. //块设备文件 DT_CHR This is a character device.//字符设备文件 DT_DIR This is a directory.//目录文件 DT_FIFO This is a named pipe (FIFO).//管道文件 DT_LNK This is a symbolic link.//软连接文件 DT_REG This is a regular file.//普通问价 DT_SOCK This is a UNIX domain socket.//套接字文件 DT_UNKNOWN The file type is unknown.//不认识类型
4.rewinddir函数原型
重置读取目录流的位置为开头
void rewinddir(DIR *dr); 参数:目录流指针
5.telldir函数原型
获取当前位置指针的位置
long telldir(DIR *dirp) 函数说明:telldir()返回参数dir 目录流目前的读取位置. 此返回值代表距离目录文件开头的偏移量返回值返回下个读取位置, 有错误发生时返回-1.
6.seekdir函数原型
可以定位到任意位置。类似于文件定位函数fseek(),在目录流上设置下一个readdir()操作的位置。
void seekdir(DIR *dirp , long loc) 函数说明:seekdir()用来设置参数dir 目录流目前的读取位置, 在调用readdir()时便从此新位置开始读取. 参数offset 代表距离目录文件开头的偏移量三、目录IO例子
#include综合例子#include #include int main() { DIR * dir; struct dirent * ptr; int i; dir = opendir("/etc/rc.d"); while((ptr = readdir(dir))!= NULL)//链表遍历 { printf("d_name : %sn", ptr->d_name); } closedir(dir); return 0; }
单机模式下的文件上传与下载
(1) 输入服务器的地址: 路径和目录名
(2) 列出服务器中有哪些文件: opendir readdir
(3) 输入从服务器下载的文件名 或 上传文件到服务器的文件名
(4) 文件下载 或 文件上传送
文件IO: open read write close
标准IO fopen fputs fgets fputc fgetc fread fwrite fclose
#include#include #include #include #include #include int main(int argc,char **argv) { DIR *dp; struct dirent * dir; char server[128]={0}; int fd; char file[128]={0}; int src_fd,des_fd; char buf[128]={0}; int ret; start: printf("please input server PATH and Directory namen"); scanf("%s",server); //list server fildes dp = opendir(server); if(dp==NULL) { printf("open server %s errorn",server); goto start; } printf("open server %s successn",server); //read server dir while(1) { dir = readdir(dp); if(dir==NULL) { break; } else { printf("inode=%ld name =%sn",dir->d_ino,dir->d_name); } } printf("please input download file namen"); scanf("%s",file); //open server file src_fd = open(strcat(strcat(server,"/"),file),O_RDONLY); if(src_fd<0) { printf("open download file %s failuren",file); return -1; } printf("open download file %s successn",file); des_fd=open(file,O_CREAT | O_WRONLY); if(des_fd < 0) { printf("create file %s errorn",file); return -2; } printf("create file %s successn",file); while(1) { ret=read(src_fd,buf,128); write(des_fd,buf,ret); if(ret < 128){ break; } } write(des_fd,buf,ret); close(des_fd); close(src_fd); closedir(dp); return 0; }