本文讲解文件的偏移(lseek()函数)、文件状态的获取(fstat()函数)、文件空间的映射(mmap()函数)、文件的属性(fcntl()函数)
1.文件偏移量lseek()函数
文件偏移量是指文件当前的操作位置,相对文件开始位置的偏移
写入数据成功,文件偏移量要向后移动写入数据的大小
读出数据成功,文件偏移量要想前移动读出数据的大小
在使用open()函数的是时候,当使用flags指定为O_APPEND选项,文件的偏移量为0,如果指定了O_APPEND选项,偏移到文件的末尾
1.1.lseek()函数介绍
#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fildes,off_t offset,whence);
注意:
**filds为文件描述符,通常为open()的返回值,offset为偏移的值,whence为操作模式
**whence为SEEK_SET,则offset为相对文件开始处的值
**whence 为SEEK_CUR,则offset为相对当前位置的值
**whence 为SEEK_END,则offset为相对文件结尾的值
**当前位置的确定:
off_t cur_pos = lseek(fd,0,SEEK_CUR);
**offset是一个非负整数
**函数成功执行返回值为文件的偏移量,失败返回-1
1.2 lseek()函数的通用例子:对标准输入进行偏移操作
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
int main(){
off_t offset = -1;
offset = lseek(1,0,SEEK_CUR); /*将标准输入的文件描述符设置为当前值*/
if(offset = -1){
printf("STDIN can‘t seek\n");
return -1;
}else{
printf("STDIN CAN seek\n");
};
return 0;
}
关于lseek的特别注意:
lseek()函数对文件偏移量的设置可以移除文件,即设置的位置可以超出文件的大小,这就有可能造成文件的空洞
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main(){
int fd;
char filename[] = "hole.h";
ssize_t size = -1;
ssize_t offset = -1;
char buf1[] = "01234567";
char buf2[] = "abcd";
fd = open(filename,O_RDWR|O_CREAT,S_IRWXU);
if(fd == -1){
printf("创建文件失败\n");
return -1;
}
size = write(fd,buf1,8);
if(size != 8){
printf("文件写入失败");
return -1;
}
offset = lseek(fd,32,SEEK_SET); /*设置文件偏移量为绝对值32*/
if(offset != offset){ /*设置失败*/
return -1;
}
size = write(fd,buf2,4); //再次写入
if(size != 4){
printf("文件写入失败");
return -1;
}
close(fd);
return 0;
}
程序执行后,用十六位进制工具od查看生成的hole.h内容,可以看到文件的空洞情况
#od -c hole.h #文件中间存在空洞现象
2.获得文件状态fstat()函数
获得文件的大小、权限、时间等
2.1.fstat()函数的介绍
查看文件的所有者、文件的修改时间、文件的大小。
函数原型:
#include<sys/types.h>
#include<sys/stat.h>
int stat(const char*path,struct stat *buf);
int fstat(int filedes,struct stat *buf); //常用
int lstat(const char *path,struct stat *buf);
**第一个参数可以是文件的路径或者是文件的描述符;buf 指向struct stat的指针
**函数执行成功是返回0,失败返回-1;
**struct stat结构如下:
struct stat{
dev_t st_dev; /*文件所处设备的设备ID号*/
ino_t st_ino; /*inode数值*/
mode_t st_mode; /*保护设置*/
nlink_t st_nlink; /*硬链接数*/
uid_t st_uid; /*文件所有者ID*/
gid_t st_gid; /*文件所有组的组ID*/
dev_t st_rdev; /*字节计数的大小*/
blksize_t st_bliksize; /*文件系统的块大小*/
blkcnt_t st_blocks; /*占用的块的数量*/
time_t st_atime; /*最后方位的时间*/
time_t st_mtime; /*最后的修改时间*/
time_t st_ctime; /*最后状态改变时间*/
};
2.2.stat()函数的例子:查看文件test.txt的相关例子:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
int main(vodd){
struct stat st;
if(-1 == stat("test.txt",&st)){
printf("获取文件失败\n");
return -1;
}
printf("包含此文件的设备ID:%d\n",st.st_dev); /*设备的ID号*/
printf("此文件的节点:%d\n",st.st_ino); /*文件的节点*/
printf("文件的保护模式:%d\n",st.st_mode); /**/
printf("文件的硬连接数:%d\n",st.st_nlink);
printf("文件的所有者ID:%d\n",st.st_uid); /*文件所有者ID*/
printf("文件所有组ID:%d\n",st.st_gid); /*所有组ID*/
printf("字节数的大小:%d\n",st.st_rdev); /*字节书的大小*/
printf("文件系统块大小:%d\n",st.st_blksize); /*文件系统快的大小*/
printf("占用的块的数量:%d\n",st.st_blocks); /*占用的快的数量*/ printf("最后访问的时间:%d\n",st.st_atime); /*最后的访问时间*/
printf("最后的修改时间:%d\n",st.st_mtime); /*最后的修改时间*/
printf("最后的状态改变时间:%d\n",st.st_ctime); /*最后状态改变时间*/
return 0;
};
3.文件空间映射mmap()函数
mmap()函数用来将文件或者设备空间映射到内存中,可以通过对映射后的内存空间的存取来获得与存取文件一致的控制方式,不必再用read()函数,write()函数,
映射的内存并不占用空间,仅仅占用一段的地址空间,
3.1.mmap()函数原型:
#include<sys/mman.h>
void *mmap(void *start,size_t length,int port,int flags,int fd,off_t offset)
**函数将文件描述符fd对应的文件中,从offset开始的一段长lengeh的数据空间映射到内存中
**映射成功的话返回的是映射空间内存的地址,失败的话返回为为(void*)-1.通过error值可以获得
**start参数:用户可以在参数start中指定要映射的地址,设置为NULL表示由系统决定映射到的什么地址。
**length参数:表示映射到内存中的数据的大小
**使用mmap()函数的限制:只能对映射到的内存区域进行操作,即开始为offset、大小为len的区域。
**fd是文件描述符
**在offset中可以对映射地址进行偏,即设置映射开始的位置
**port映射区的保护方式:
PROT_EXEC:映射区域可执行
PROT_READ:映射区域可读取
PROT_WRITE:表示映射区可写入
PORT_NONE:表示映射区不能存取
......
此参数可以组合,同时port的设置会受到文件打开时的选项限制
**flags指定映射区的类型、选项和是否可以对映射对象进行操作(读写等),这个参数和open()函数中的含义类似。flags也可以是一个组合值
MAP_FIXED:.....
3.2.munmap()函数
函数原型:
#include<sys/mman.h>
int munmap(void *stat,size_t length);
取消mmap()函数的映射环境
**start:为mmap()函数成功后的返回值,即映射的内存空间地址
**length为映射的长度
3.3函数mman和munmap的例子:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/mman.h>
#include<string.h>
#define FILELENGTH 80
int main(void)
{
int fd = -1;
char buf[]="quick brown fox jumps over the lazy dog";
char filename[]= "mmap.txt";
char *ptr = NULL;
fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);
if(fd == -1){
return -1;
}
lseek(fd,FILELENGTH-1,SEEK_SET);
write(fd,"a",1); /*写入一个字符后,文件的长度为80*/
ptr=(char*)mmap(NULL,FILELENGTH,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if((char*)-1 == ptr){
printf("mmap failure\n");
close(fd);
return -1;
}
memcpy(ptr+16,buf,strlen(buf));
munmap(ptr,FILELENGTH);
close(fd);
return 0;
}
4. 文件的属性fcntl()函数
fcntl()函数用于获得和改变已经打开文件的属性
4.1.fcntl()函数原型:
#include<unistd.h>
#include<fcntl.h>
int fcntl(int fd,int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock *lock);
**操作成功返回值依靠cmd,出错返回-1;
F_DUPFD:返回值为新的文件描述符
F_GETFD:返回值为获得的相应的标示符
F_GETFL:文件描述符的标志
F_GETOWN:结果为正数则为进程的ID,进程为负数则为进程组ID号
F_DUPFD:命令用于复制文件描述符fd,获得的新文件描述符作为函数值返回.获得的文件描述符是尚未使用的文件描述符中大于或等于第3个参数值中的最小值
F_GETFD:获得文件描述符
F_SETFD:设置文件描述符
F_GETFL:标志获得文件描述符fd的文件状态标志
4.2.F_GETFL的例子
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
int main(void){
int flags = -1;
int accmode = -1;
flags = fcntl(0,F_GETFL,0);
if(flags < 0){
printf("failure to use fcntl\n");
return -1;
}
accmode = flags & O_ACCMODE; /*获得访问模式*/
if(accmode == O_RDONLY) /*只读*/
printf("STDIN READ ONLY\n");
else if(accmode == O_WRONLY)
printf("STDIN WRITE ONLY\n");
else if(accmode == O_RDWR)
printf("STDIN READ WRITE\n");
else
printf("STDIN READ WRITE\n");
if(flags & O_APPEND)
printf("STDIN APPEND\n");
if(flags & O_NONBLOCK)
printf("STDIN NONBLOCK\n");
return 0;
}
4.3.F_SETFL的例子
4.4.F_GETOWN的例子:
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
int main(void){
int uid;
int fd = open("test.txt",O_RDWR);
uid = fcntl(fd,F_GETOWN); /*获得接收信号的进程ID*/
printf("the SIG recv ID is %d\n",uid);
close(fd);
return 0;
}
5.F_SETOWN的例子
本文出自 “wewinSHELL学习笔记” 博客,请务必保留此出处http://wewin11235.blog.51cto.com/8179974/1620491
原文地址:http://wewin11235.blog.51cto.com/8179974/1620491