在上一篇文章中讲解了linux中文件编程的基本函数,在这儿将继续讲解一些比较高级的文件编程
1 确定和改变文件模式
1.1 umask 函数
通过ls -l 命令可以察看一个文件或者一个文件夹的属性,其中在我的电脑运行ls -l 3-1.c就有如下结果:
其中,最开始的1-10个字符表示所有者、所属组、其他人的读写执行权限,通常通过4,2,1来表示读、写、执行的权限,例如6=4+2 表示具有读写权限,不具有执行权限。
在文件中具有一个文件屏码,称为umask,在终端中输入umask,有如下结果:
即在linux中默认的umask为0002
在命令行中如果想要改umask的数值,那么就在终端中输入:umask+新数值即可。当然也可以通过函数来改变。格式如下:
#include<sys/stat.h>
mode_t umask( mode_t mask )
cmaks表示新设置的文件创建屏蔽码,返回值为原来的umask值
例如:creat("tz.txt",0777);如果此时的umaks=042,那么此时的tz.txt的权限为0735
1.2 chmod 和fchmod 函数
#include<sys/stat.h>
int chmod( const char *pathname, mode_t mode );
int fchmod( int fd, mode_t mode );
功能:改变一个文件的存取权限
备注:要改变一个文件的访问权限位,进程的有效用户ID必须等于文件所有者的用户ID,或者该进程具有超级用户权限。
参数说明:pathname表示指定的文件名,mode表示新的文件权限,fd表示一个文件描述符。
返回值:成功返回0,反之返回-1
1.3 chown和fchown 函数
在umask函数那么通过ls -l 3-1.c可以可知3-1.c的所有者和所属组,即1后面的ricklu
功能:改变文件或者路径的所属组和所有者
格式:#include<unistd.h>
int chown( const char *pathname, uid_t owner, gid_t group );
int fchown( int fd, uid_t owner, gid_t group );
参数:pathname表示文件名或者路径名的指针,owner表示改变后的所有者,group表示改变后的所属组
备注:只有root用户才可以使用这两个函数改变任意一个文件的所有者和所属组,普通用户只能改变自己所有的文件的组识别号,且只能在其所属组中进行选择。
1.4 rename 函数
功能:对一个文件重命名
格式:#include<stdio.h>
int rename(const char *oldname,const char *newname)
参数:分别表示旧文件名和新文件名
返回值:成功返回0,反之返回-1
1.5 truncate和ftruncate 函数
功能:对文件的大小进行修改,截断文件长度。
格式:#include<unistd.h>
int truncate( const char *pathname, off_t length );
int ftruncate( int fd, off_t length );
参数:pathname和fd同上,length表示将文件截取到的长度-文件的新长度
返回值:成功返回0,反之返回-1
1.6 access 函数
功能:以实际用户ID和实际组ID测试访问权限
格式:#include<unistd.h>
int access( const char *pathname, int mode );
参数:pathname同上,mode表示待测试的权限
返回值:成功返回0,反之返回-1
说明:mode可以取如下的值从而对因测试权限,通过|来决定mode的值
R_OK 测试读权限
W_OK 测试写权限
X_OK 测试执行权限
F_OK 测试文件是否存在
例子:access(“tz.txt”,06)测试tz.txt是否具有读写权限
access(“tz”,F_OK) 测试tz是否存在
2 查询文件信息
对于一个文件而言,它的详细信息都是存储在stat这一个结构体中,通过stat中不同的数值可以获得不同的信息,因此获取文件信息的核心就是struct stat
2.1 stat 和fstat和lstat 函数
功能:获取文件相关的信息结构填入由指针buf指向的stat结构中
格式:#include<sys/stat.h>
int stat( const char *restrict pathname, struct stat *restrict buf );
int lstat( const char *restrict pathname, struct stat *restrict buf );
int fstat( int fd, struct stat *buf );
参数:pathname同上,buf表示stat的指针,用来存储文件或者路径的相关信息
返回值:成功返回0,反之返回-1
备注:可以通过mode&S_IFMT的结果来检测文件类型,在这儿会用一个例子来说明
2.2 utime 和utimes 函数
每个文件都有三个时间戳关联:最近访问时间、最近修改时间和最近特性修改时间,它们分别对应stat中的st_atime、st_mtime和st_ctime。在这儿它们都是time_t类型,定义在<time.h>。可以通过函数来改变一个文件的最近访问时间和最近修改时间,但是不能修改最近特性修改时间,因为i节点由系统来维护。
功能:修改文件的访问时间和修改时间
格式:#include<utime.h>
int utime( const char *pathname, cosnt struct utimebuf *times );
int utimes( const char *pathname, cosnt struct timeval values[2] );
参数:pathname表示要更新时间的文件或者路径 ,utimebuf表示一个时间结构体,values[0]和values[1]分别表示指定文件的访问时间和修改时间。
返回值:成功返回0,并更新st_ctime,失败返回-1
说明:utimebuf结构和 timeval结构
struct utimebuf
{
time_t actime; //访问时间
time_t modtime; //修改时间
}
struct timeval
{
long tv_sec;//自公元纪年来的秒数
long tv_usec;//秒后的微秒数
}
特别注意:此函数的操作及执行它所要求的特权取决于times参数是否为NULL:
1 如果times是NULL,则访问时间和修改时间都设置为当前时间,执行此操作必须满足:进程的有效用户ID和该文件的所有者ID必须相等,或者进程对该文件必须具有写权限。
2 如果times非NULL,则访问时间和修改时间都设置为times所指向结构中的值,执行此操作必须满足:进程的有效用户ID和该文件的所有者ID必须相等,或者进程是超级进程,对文件仅有写权限是不够的。
在这儿通过如上介绍,来判断一个文件的类型
#include<sys/stat.h>
#include<sys/types.h>
#include<utime.h>
#include<fcntl.h>
#include<stdio.h>
int main(int argc,char *argv[])
{
int i;
struct stat buf;
char *ptr;
for(i=1;i<argc;i++)
{
printf("%s: ",argv[i]);
if(lstat(argv[i],&buf)<0)
{
perror("error\n");
continue;
}
switch(S_IFMT&buf.st_mode)
{
case S_IFREG:ptr="常规文件";break;
case S_IFDIR:ptr="目录文件";break;
case S_IFCHR:ptr="字符设备文件";break;
case S_IFBLK:ptr="块设备文件";break;
case S_IFIFO:ptr="管道文件";break;
case S_IFLNK:ptr="符号链接文件";break;
case S_IFSOCK:ptr="套借字文件";break;
default:ptr="未知文件";break;
}
printf("%s\n",ptr);
}
return 0;
}
打开一个文件,将他截断至0长度,但维持他的访问时间和修改时间不变
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<utime.h>
int main(int argc,char *argv[])
{
struct stat statbuf;//保存时间的结构体
struct utimbuf times;//设置时间的结构体
int i,fd;
if(argc!=2)
{
printf("参数错误\n");
return 1;
}
if((fd=open(argv[1],O_RDWR))==-1)
{
printf("打开文件失败\n");
return 2;
}
if(stat(argv[1],&statbuf)<0)
{
return 2;
}
if(ftruncate(fd,0)<0)
{
printf("截断文件长度失败\n");
return 3;
}
printf("%s is ftruncate now\n",argv[1]);
times.actime=statbuf.st_atime;
times.modtime=statbuf.st_mtime;
if(utime(argv[1],×)==0)
printf("时间修改成功\n");
else
printf("时间修改失败\n");
close(fd);
return 0;
}
2.3 文件长度
文件长度由stat结构成员st_size表示,以字节为单位,此字段只对普通文件、目录文件和符号链接有意义。
3 文件其他操作
3.1 dup和dup2 函数
功能:复制文件描述符
格式:#include<unistd.h>
int dup( int oldfd );
int dup2( int oldfd, int newfd);
参数:oldfd和newfd分别表示旧文件描述符和新文件描述符
返回值:成功返回新的文件描述符,出错返回-1
说明:dup一定返回当前可用的最小文件描述符; dup2指定参数newfd为新的文件描述符,当newfd打开时,先将其关闭,若oldfd和newfd相等,返回newfd而不关闭它。
#include<sys/stat.h>
#include<utime.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdio.h>
int main(int argc,char *argv[])
{
int fd;
if(argc<2)
{
printf("参数错误\n");
return 1;
}
if((fd=open(*(argv+1),O_CREAT|O_WRONLY,0644))==-1)
{
printf("打开文件出错\n");
return 2;
}
if(dup2(fd,STDOUT_FILENO)==-1)
{
printf("文件重定向出错\n");
return 3;
}
printf("dup2 successed!\n");
close(fd);
return 0;
}
3.2 fcntl 函数
fcntl代表对文件控制,他提供了进一步管理低级文件描述符的各种手段,用它可以对一打开的文件描述符进行各种控制操作。
格式:#include<fcntl.h>
int fcntl( int fd, int cmd, int arg );
参数:fd同上,通过cmd的去之决定是否需要arg,此时cmd的取值如下:
F_DUPFD 复制文件描述符fd,返回大于或者等于arg的最低序号的文件描述符,新文件描述符作为函数返回值返回。
F_GETFD 获取close-on-exec标志。如果最后一位是0,则该标志未设置,返回0或者1.
F_SETFD 设置close-on-exec的值为arg。
F_GETFL 对应于fd的文件状态标志作为函数值返回。文件状态标志在open函数已经说明。
F_SETFL 将文件状态标志设置为第三个参数的值。可以更改的标志是O_APPEND、O_NONBLOCK、O_NDELAY
F_GETOWN 取当前接收SIGIO和SIGURG信号的进程ID或进程租ID。
F_SETOWN 设置接收SIGIO和SIGURG信号的进程ID或进程租ID。正的arg参数表示一个进程ID,负的arg参数表示等于arg的绝对值的进程租ID。
返回值:失败时返回-1
#include<sys/stat.h>
#include<utime.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdio.h>
#define BLOCK 0
#define BUFSIZE 1024
char *values[]={"123\n","456\n","007\n","421\n","F"};//权限值
int main(int argc,char *argv[])
{
int fd,flags;
int i;
char userno[BUFSIZE],**ptr;
ptr=values;
for(i=0;i<BUFSIZE;i++)
{
userno[i]='\0';
}
setbuf(stdout,(char *)NULL);//清空
if((fd=open("/dev/tty",O_NDELAY|O_RDONLY))==-1)//打开终端从中读取数据
{
printf("open error\n");
return 1;
}
printf("Enter Your user ID:\n");
sleep(4);
if(read(fd,userno,BUFSIZE)==-1)
{
printf("Bye Bye\n");
return 2;
}
while(strcmp(*ptr,userno,3)!=0&&(strcmp(*ptr,"F")!=0))//判断是否匹配
++ptr;
if(strcmp(*ptr,"F")==0)
{
printf("invalid user ID\n");
return 3;
}
flags=fcntl(fd,F_GETFL);
flags&=BLOCK;
flags&=fcntl(fd,F_SETFL,flags);//取消O_NDELAY标志,
printf("enter data:\n");//未输入就一直等待
i=read(fd,userno,BUFSIZE);
printf("\n welcome #");
write(1,userno,i);
close(fd);
return 0;
}