Linux下IO编程(一)
Linux下IO编程
文件IO
open函数——打开or创建一个文件
#include <fcntl.h> //open函数在此头文件中声明
int open(const char *pathname, int flags, mode_t mode)
参数意义如下:
- pathname——文件路径
- flags ——打开文件的方式
- mode——创建文件的权限(可省略)
flags的内容如下:
flags | 功能 |
---|---|
O_RDONLY | 只读打开 |
O_WRONLY | 只写打开 |
O_RDWR | 读写打开 |
O_CREAT | 若路径中的文件不存在则自动建立该文件 |
O_APPEND | 读写文件从文件尾部开始移动,所写入 |
O_TRUNC | 打开文件,会把已经存在的内容删除 |
O_EXCL | O_CREAT |O_EXCL指令会去检查文件是否存在,文件若不存在则建立,否则返回-1 |
mode的表示方法1:
mode | 功能 |
---|---|
S_IRUSR | 所有者拥有读权限 |
S_IWUSR | 所有者拥有写权限 |
S_IXUSR | 所有者拥有执行权限 |
S_IRGRP | 群组拥有读权限 |
S_IWGRP | 群组拥有写权限 |
S_IXGRP | 群组拥有执行权限 |
S_IROTH | 其他用户拥有读权限 |
mode的表示方法2:——可以由3位数字组成(umask)
数值 | 第一位 | 第二位 | 第三位 |
---|---|---|---|
4(读) | 所有者 | 群组 | 其他用户 |
2(写) | |||
1(执行) |
函数返回值:
函数的返回值是文件描述符,如果打开文件成功返回一个正整数,否则返回-1。文件描述符,是一个非负的整数,相当于文件的ID号。
举例:通过open函数实现touch功能
#include <stdio.h> // 提供open()函数
#include <fcntl.h>
#include <unistd.h> // 提供close()函数
int main(int argc,char* argv[])
{
int fd;
fd =open(argv[1],O_CREAT | O_RDWR,0777);
if(fd<0)
{
printf("create file %s is failed\n",argv[1]);
return -1;
}
else
{
printf("create file %s is sucess,fd is %d\n",argv[1],fd);
}
close(fd);
return 0;
}
write函数
#include <unistd.h>
ssize_t write (int fd, const void * buf, size_t count);
参数:
- fd——文件描述符
- buf——写入内容
- cout——向文件中写多少(字节)
函数返回值:返回实际写入的字节数。
举例:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
int fd;
int wr_ret;
char buf[]="hello linux";
fd=open("./a.c",O_TRUNC |O_RDWR);
if(fd<0)
{
printf("open file is failed");
return -1;
}
printf("open file is success ,fd is %d\n",fd);
wr_ret=write(fd,buf,sizeof(buf));
printf("the wr_ret is %d\n",wr_ret); //12个字节 加上“\0”
close(fd);
return 0;
}
read函数
#include <unistd.h>
ssize_t read(int fd, void * buf, size_t count);
函数说明:
read()会把参数fd所指的文件传送count 个字节到buf 指针所指的内存中。
返回值:返回值为实际读取到的字节数
注意:
- 先写再读会涉及一个指针读写位置指针,在写完的指针位置进行读会读不到内容,如下举例
- read时fd中的数据如果小于要读取的数据,就会引起阻塞,详见:https://blog.csdn.net/hhhlizhao/article/details/71552588
举例:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
int fd;
int wr_ret,rd_ret;
char buf[]="hello linux";
char rd_buf[]={0};
fd=open("./a.c",O_TRUNC |O_RDWR);
if(fd<0)
{
printf("open file is failed");
return -1;
}
printf("open file is success ,fd is %d\n",fd);
wr_ret=write(fd,buf,sizeof(buf));
printf("the wr_ret is %d\n",wr_ret);
//read
rd_ret=read(fd,rd_buf,128);
printf("the rd_ret is %d,the rd_buf is %s\n",rd_ret,rd_buf);
close(fd);
return 0;
}
//以上输出为
open file is success ,fd is 3
the wr_ret is 12
the rd_ret is 0,the rd_buf is //发现读不到
lseek函数
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence)
函数作用:
用于移动文件读写指针,因此还有以下两种作用:
- 扩展文件;
- 获取文件大小;lseek(fd,0,SEEK_END)
参数:
- fd——文件描述符
- offset——相对基准的偏移量,字节为单位,为正则向文件末尾移动(向前移),为负数则向文件头部(向后移)
- whence——当前的基准
whence主要有3个标志:
whence | 说明 |
---|---|
SEEK_SET | 从文件头部开始偏移offset 个字节 |
SEEK_CUR | 从文件当前读写的指针位置开始,增加offset 个字节的偏移量 |
SEEK_END | 从文件结尾开始,文件偏移量设置为文件的大小加上偏移量字节 |
返回值:成功,返回从文件开头到当前结束位置的偏移量(1字节为单位);失败返回-1。
举例1:对上个例子应用lseek()将读写指针移到开头,来实现先写再读
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
int fd;
int wr_ret,rd_ret;
char buf[]="hello linux";
char rd_buf[]={0};
fd=open("./a.c",O_TRUNC |O_RDWR);
if(fd<0)
{
printf("open file is failed");
return -1;
}
printf("open file is success ,fd is %d\n",fd);
wr_ret=write(fd,buf,sizeof(buf));
printf("the wr_ret is %d\n",wr_ret);
//start read
lseek(fd,0,SEEK_SET); //<========================================
rd_ret=read(fd,rd_buf,128);
printf("the rd_ret is %d,the rd_buf is %s\n",rd_ret,rd_buf);
close(fd);
return 0;
}
//经过lseek()函数调整读写指针位置后
open file is success ,fd is 3
the wr_ret is 12
the rd_ret is 12,the rd_buf is hello linux
举例2:综合应用——使用以上所学完成类似cp操作
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char* argv[])
{
int rd_fd,wr_fd;
int rd_ret;
int wr_ret;
char read_buf[128]={0};
if(argc<3)
{
printf("are you kiding me? ");
return -1;
}
rd_fd=open(argv[1],O_RDONLY);
if(rd_fd<0)
{
printf("open the src file:%s is failed\n",argv[1]);
return -2;
}
printf("open the %s is sucessful\n",argv[1]);
wr_fd=open(argv[2],O_WRONLY);
if(wr_fd<0)
{
printf("open the des file:%s is failed\n",argv[2]);
return -3;
}
printf("open the %s is sucessful\n",argv[2]);
while(1)
{
rd_ret=read(rd_fd,read_buf,128); //read时有读写指针
wr_ret=write(wr_fd,read_buf,rd_ret); //所以此处一次读不完但是也能连续
if(rd_ret<128)
{
break;
}
memset(read_buf,0,128);
}
close(wr_fd);
close(rd_fd);
return 0;
}
注:
-
从文件向buf中read时,因为文件有读写指针,并且一次循环read完一个buf马上进行write,所以最终得到的内容是连续的。但是要注意write函数,write()函数从buf写数据到fd中时,若buf中数据无法一次性读完,那么第二次读buf中数据时,其读位置指针(也就是第二个参数buf)不会自动移动,需要程序员来控制,而不是简单的将buf首地址填入第二参数即可。
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main(int argc,char* argv[]) { int wr_fd; int wr_ret; char buf[]="hello linux"; wr_fd=open(argv[1],O_CREAT |O_RDWR,0666); if(wr_fd<0) { printf("open the file is failed"); return -1; } wr_ret=write(wr_fd,buf,2); wr_ret=write(wr_fd,buf,2);//写两次结果可能为“hehe” or "hell" close(wr_fd); return 0; }
//编译后执行 ./test test.c 得到test.c文件中内容为“hehe”
可按如下格式实现buf读位置移动:write(fp, p1+len, (strlen(p1)-len))。 这样write第二次循环时便会从p1+len处写数据到fp, 之后的也一样。由此类推,直至(strlen(p1)-len)变为0。
int main() { char *p1 = "This is a c test code"; volatile int len = 0; int fp = open("/home/test.txt", O_RDWR|O_CREAT); for(;;) { int n; n=write(fp, p1+len, (strlen(p1)-len); if(n== 0) { printf("n = %d \n", n); break; } len+=n; } return 0;
-
以上例子还未用到lseek()函数,因为以上函数是直接cp复制一个编辑好的文件,而不是复制通过write函数写出的文件。