linux系统I/O函数
- linux系统I/O函数大体分两类:操作文件的和操作目录的
- 查看man文档:man 2 函数名 //2 -第二章
注意:调用系统函数注意返回值的判断对错误进行输出和形参的选择
文件
- open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
int main()
{
int fd;//保存open函数的返回值.
/*******************************************************
*函数:open()
*头文件: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> 三个
*格式:int open(const char *pathname, int flags);
* int open(const char *pathname, int flags, mode_t mode);
*1.打开已经存在的文件:fd=open("a.c",O_RDWR);
*2.创建文件:fd=open("h.c",O_RDWR|O_CREAT,777);
*3.判断文件是否存在:fd=open("h.c",O_RDWR|O_CREAT|O_EXCL,777); 此时O_CREAT|O_EXCL必须联合使用
*4.文件截断为0,清空文件:fd=open("a.c",O_RDWR|O_TRUNC);
*返回值: open(), openat(), and creat() return the new file descriptor(fd:记录在内核区的pcb进程控制块里,唯一的), or -1 if
* an error occurred (in which case, errno is set appropriately).
********************************************************/
//fd=open("a.c",O_RDWR);
//fd=open("h.c",O_RDWR|O_CREAT,777);
//fd=open("h.c",O_RDWR|O_CREAT|O_EXCL,777);
fd=open("a.c",O_RDWR|O_TRUNC);
printf("fd=%d\n",fd);
//系统函数返回值很重要,对他进行判断,如返回-1则发生错误.
if(fd==-1)
{
/*******************************************************
*函数:perror()
*头文件:#include<stdio.h>
*作用:输出open()函数对应的错误值
********************************************************/
perror("open file");//调用perror函数,open file是我们自己定义的错误名字:输出错误描述
exit(1);//退出进程,刷新缓存 头文件:#include<stdlib.h>
}
/*******************************************************
*函数:close()
*头文件: #include <unistd.h>
*格式:int close(int fd);
*返回值:close() returns zero on success. On error, -1 is returned, and errno
*is set appropriately.
********************************************************/
int ret=close(fd);//close函数需要传入fd值.
printf("ret=%d\n",ret);
return 0;
}
- read()和write()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
/*******************************************************
*
*使用read()和write()函数给文件test_open.c函数创建一个附件.
*
********************************************************/
int main2()
{
//fd=open("a.c",O_RDWR);
//fd=open("h.c",O_RDWR|O_CREAT,777);
//fd=open("h.c",O_RDWR|O_CREAT|O_EXCL,777);
//打开被读文件
int fd=open("./test_open.c",O_RDWR);
//系统函数返回值很重要,对他进行判断,如返回-1则发生错误.
if(fd==-1)
{
perror("open file error");//调用perror函数,open file是我们自己定义的错误名字:输出错误描述
exit(1);//退出进程,刷新缓存 头文件:#include<stdlib.h>
}
//创建一个新的文件副本
int fd1=open("./test_open.c(附件)",O_RDWR|O_CREAT,777);
if(fd1==-1)
{
perror("creat file error");
exit(1);
}
//读文件
/*******************************************************
*函数:read()
*头文件:#include <unistd.h>
*格式: ssize_t read(int fd, void *buf, size_t count); //fd:文件描述符-需要读取的文件;buf:读文件的buf;count:buf的大小(sizeof(buf))
*返回值:0-成功;-1-失败; >0:已经读取的大小.
********************************************************/
char buf[2048];
int count=read(fd,buf,sizeof(buf));
if(count==-1)
{
perror("read file error");
exit(1);
}
while(count) //只要count不返回0就表示读取没有完成;
{
//写文件
/*******************************************************
*函数:write()
*头文件:#include <unistd.h>
*格式: ssize_t write(int fd, const void *buf, size_t count); //fd:文件描述符-被写入的文件;buf:存储的需要写入的数据;count:buf的大小(sizeof(buf))
*返回值:0-成功;-1-失败; >0:已经写入的大小.
********************************************************/
int count1=write(fd1,buf,sizeof(buf));
if(count1==-1)
{
perror("write file error");
exit(1);
}
count=read(fd,buf,sizeof(buf));
if(count==-1)
{
perror("read file error");
exit(1);
}
}
//关闭文件
close(fd);
close(fd1);
return 0;
}
- lseek()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
int main()
{
int fd=open("./b.c",O_RDWR);
if(fd==-1)
{
perror("open file error");
exit(1);
}
/*******************************************************
*函数:lseek()
*头文件: #include <sys/types.h> #include <unistd.h>
*格式:off_t lseek(int fd, off_t offset, int whence); //offset:偏移量; whence:三个SEEK_SET(设置文件指针在offset的位置)、SEEK_CUR(设置偏移量从当前文件文件指针开始eg:当前位置为2,offset=3,所以指针位置为5)、SEEK_END(偏移量从结尾开始)可选
*1.移动文件指针
*2.查看文件大小:ret=lseek(fd,2000,SEEK_END) //返回值就是文件的大小
*3.拓展文件大小(只能向后拓展):ret =lseek(fd,2000,SEEK_END) //拓展之后一定要有一个写入的操作
*返回值:文件的大小(字节为单位)
********************************************************/
//读取文件大小
int ret =lseek(fd,0,SEEK_END);
printf("file length=%d\n",ret);
//拓展文件大小(最后一定要有一个写的操作)
ret =lseek(fd,2000,SEEK_END);
printf("file length=%d\n",ret);
write(fd,"a",1);//''不行
close(fd);
return 0;
}
- stat()
1>终端命令的方式:stat 文件名字
显示的内容比: ls test_lseek.c丰富.
2>实际运用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
int main(int argc,char* argv[])
{
if(argc<2)
{
printf("please cin ./b.c' filename");
}
/*******************************************************
*函数:stat()
*头文件: #include <sys/types.h> #include <unistd.h> #include <sys/stat.h> 三个
*格式: int stat(const char *pathname, struct stat *buf); //1.传入的是文件地址; 2.struct stat *buf:形参为结构体指针,则需要在外部准备空间(等价于传出参数)3.该函数是一个穿透函数(比如访问软链接文件时(ln -s 绝对地址 名字),其实访问的是源文件)
* int lstat(const char *pathname, struct stat *buf); //1,2同理,但该函数是一个不穿透函数(就是访问的文件自己)
* int fstat(int fd, struct stat *buf); //fd(需要以open()函数打开文件,不需要地址)
*返回值:On success, zero is returned. On error, -1 is returned, and errno is
set appropriately.
********************************************************/
struct stat buf;
//获取当前路径下a.c文件的大小
int ret=stat(argv[1],&buf); //argv[]已经是路径了,无需加"";
if(ret==-1)
{
perror("stat file erro");
exit(1);
}
//获取文件大小,可获取量细节可看下图(stat结构体)
int size_n=(int)buf.st_size; //off_t转换int
printf("argv[1]的大小是%d\n",size_n);
return 0;
}
- truncate
1>文件扩展
/*******************************************************
*函数:truncate()
*头文件: #include <sys/types.h> #include <unistd.h>
*格式: int truncate(const char *path, off_t length); //文件本身为100,当length为20时,执行完该函数后文件就为20,如果为lengrh为100,执行完后则为200,且无需写操作(区别lseek())
* int ftruncate(int fd, off_t length);
*返回值:0-成功;-1-失败;
********************************************************/
- 其他
1>
2>unlink
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
int main()
{
int fd=open("test_unlink.c",O_RDWR|O_CREAT,777);
if(fd==-1)
{
perror("open file error");
exit(1);
}
/*******************************************************
*函数:unlink()
*头文件:#include <unistd.h>
*格式:int unlink(const char *pathname);
*作用:创建临时文件
*返回值:0-成功;-1-失败;
********************************************************/
int ret=unlink("./test_unlink.c");//当文件fd存在时,不会删除,只有当文件关闭才会执行该操作.
if(ret==-1)
{
perror("unlink file error");
exit(1);
}
//证明该文件确实存在,我们写入hello,world!到文件里,然后再把它打印到显示屏.
write(fd,"hello,world!\n",13);
//重置文件指针
lseek(fd,0,SEEK_SET);
//读出内容
char buf[20];
int len=read(fd,buf,sizeof(buf));
//输出到屏幕
write(1,buf,len);
close(fd);
return 0;
}
目录
- chdir()和getcwd()
注意是修改当前进程的目录路径
- mkdir()和rmdir()
注意:创建目录时要给定执行权限,不然打不开. - opendir()和readdir()和closedir()
1> 查看man文档:man 3 函数名 //3 -第三章
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include <dirent.h>
//获取文件个数
int get_file_number(char * path,int file_total)
{
//打开目录
/*******************************************************
*函数:opendir()
*头文件:#include <sys/types.h> #include <dirent.h>
*格式:DIR *opendir(const char *name); //给定目录路径就可,返回一个DIR*
*作用:打开目录
*返回值:正确时,函数返回指向目录流的指针。 错误时,将返回NULL,并正确设置了errno。
********************************************************/
DIR * dir=NULL;
dir=opendir(path); //正确时,函数返回指向目录流的指针。指针指向结构体,包含目录的各种属性,相当于FILE* 一样.
if(dir==NULL)
{
perror("opendir error");
exit(1);
}
//遍历当前打开的目录
/*******************************************************
*函数:readdir()
*头文件:#include <dirent.h>
*格式:struct dirent *readdir(DIR *dirp); //返回指向dirent结构的指针,输入目录
*作用:打开目录
*返回值:readdir()函数返回一个指向dirent结构的指针,该结构表示dirp指向的目录流中的下一个目录条目。 在到达目录流的末尾时返回NULL
* struct dirent
* {
* ino_t d_ino; //inode number
* off_t d_off; //not an offset; see NOTES
* unsigned short d_reclen; //length of this record
* unsigned char d_type; //type of file; not supported by all filesystem types 文件类型6种,见下面的图片
* char d_name[256]; //filename
* };
********************************************************/
struct dirent *ptr=NULL;
char path_[1024]={0};
while((ptr=readdir(dir))!=NULL)//当前目录读完返回NULL.
{
//分别判断打开的目录还是文件
//过滤.和..
if(strcmp(ptr->d_name,".")==0||strcmp(ptr->d_name,"..")==0)
{
continue;
}
if(ptr->d_type==DT_DIR)
{
//连接新的目录地址
sprintf(path_,"%s/%s",path,ptr->d_name);
//递归目录
file_total=get_file_number(path_,file_total);
}
if(ptr->d_type==DT_REG)
{
file_total++;
}
}
closedir(dir);//要先关闭目录,再返回值.
return file_total;
}
/*******************************************************
*读取某个目录下文件个数(目录要递归,文件要遍历)
********************************************************/
int main(int argc,char *argv[])
{
if(argc<2)
{
printf("please cin a.out ");
exit(1);
}
int file_total=get_file_number(argv[1],0);
printf("%s该目录下的文件总数为%d\n",argv[1],file_total);
return 0;
}
d_type-文件类型
- dup()和dup2()
1>文件描述符的复制
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include <dirent.h>
int main()
{
int fd=open("a.c",O_RDWR);
int fd1=open("b.c",O_RDWR);
/*******************************************************
*函数:dup()
*头文件:#include <unistd.h>
*格式:int dup(int oldfd);//返回新的fd,于oldfd都可操作对应的文件(注意文件的指针,打开之后文件指针指向文件头部,如果写入内容旧的内容会被覆盖) (相当于文件描述符取别名,返回别名)
* int dup2(int oldfd, int newfd);//当newfd文件是打开时,先关闭newfd文件,然后 oldfd和newfd都指向原oldfd对应的文件
*返回值:On success, these system calls return the new descriptor. On error, -1 is returned, and errno is set appropriately.
********************************************************/
int newfd=dup2(fd1,fd);
char buf[10]="2222";
lseek(fd1,0,SEEK_END); //文件指针定位到文件末尾防止覆盖
write(fd,buf,sizeof(buf));//此时fd和fd1都指向b.c进行操作.a.c已经被关闭.
write(fd1,buf,sizeof(buf));
close(fd);
close(fd1);
return 0;
}
- fcntl()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
int main()
{
char *p="hao";
char *q="good";
int fd=open("a.c",O_WRONLY);//只写权限
if(fd==-1)
{
perror("open file error");
exit(1);
}
if(write(fd,p,strlen(p))==-1)//此时写,文件指针在头部,会进行覆盖.
{
perror("write file error");
exit(1);
}
/*******************************************************
*函数:fcntl()
*头文件:#include <unistd.h> #include <fcntl.h>
*格式: int fcntl(int fd,int cmd,long arg); //cmd有两种选择:F_GETFL时,获取文件状态,此时第三个参数设置为0;F_SETFL时,第三个参数只有两种选择,O_APPEND和O_NONBLOCX(分别实现文件在打开后改变属性,实现末尾追加写,或则非阻塞模式)
*返回值:-1-失败 ; >0 文件状态
********************************************************/
//使用fcntl()获取文件标记
int flag=fcntl(fd,F_GETFL,0);
if(flag==-1)
{
perror("fcntl getflag error");
exit(1);
}
flag|=O_APPEND;//更改flag的值,不能写成flag==O_APPEND;
//使用fcntl()改变当前文件的状态
if(fcntl(fd,F_SETFL,flag)==-1)
{
perror("fcntl settflag error");
exit(1);
}
if(write(fd,q,strlen(q))==-1)//此时写,文件指针在尾部,不会进行覆盖.
{
perror("write file error");
exit(1);
}
close(fd);
return 0;
}
/*******************************************************
*总结:将文件指针设置在末尾的方法如下:
*1.使用open函数:open("...",O_WRONLY|O_APPEND)//O_APPEND 以追加的方式打开,同理O_NONBLOCK: 打开时不阻塞
*2.使用lseek()函数:lseek(fd,0,SEEK_SET);
*3.使用fcntl()函数:先获取已经打开文件的文件状态,然后再设置.
********************************************************/