Unix文件访问原语
一般来说,Unix程序首先调用 open(或creat)来创建一个文件,接着用read,write和lseek操作该文件中的数据。
如果程序不再需要这人文件,则可以调用close来表示自己已经完成了对文件的操作。最后,如果用户不再需要这个文件,
则可以调用 unlink或remove把它从操作系统中清除出去。
Unix的操作原语:
open 打开一个文件来读,写或创建一个空文件
creat 创建一个空文件
close 关闭以前打开的文件
read 从文件中读取数据
write 将数据写到文件中
lseek 把文件读写指针移动到特定字节
unlink 删除一个文件
remove 删除文件的另一种方法
fcntl 控制文件的属性
open系统调用
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(const char *pathname,int flags,[mode_t mode]);
pathname指向所要打开的文件的路径名,可以是绝对路径,也可以是相对路径。flags指定以何种访问模式访问文件,取值定义在<fcntl.h>中,定义了三种常量:
O_RDONLY: 只读
O_WRONLY: 只写
O_RDWR: 读写
若open调用成功并且成功地打开文件,open的返回值将是一个非负整数,称为文件描述符,它的值应该是当前调用进程的所有空闲文件描述符中最小的一个。如果出错,open返回-1。如果打开的文件不存在,就有可能发生错误。
使用open创建文件
open也可以用来创建文件,如
filedes=open("/tmp/newfile",O_WRONLY | O_CREAT,0644);
使用位运算,如果文件不存在,就会创建长度为0的文件,并且以只读方式打开,文件的访问权限为0644.
还有两种方式,
fd=open("lock",O_WRONLY | O_CREAT | O_EXCL,0644);//如果文件存在,open调用出错返回-1
fd=open("lock",O_WRONLY | O_CREAT | TRUNC,0644);//如果存在,强制把文件长度截为0,相当于覆盖掉
simple_open.c:
#include<stdlib.h> /*for the exit call*/
#include<fcntl.h>
#include<stdio.h>
char *workfile="junk";
int main(void)
{
int filedes;
/*open using O_RDWR from <fcntl.h>*/
/*file to be opened for read/write*/
if((filedes=open(workfile,O_RDWR|O_CREAT,0644))==-1)
{
printf("Could n't open %s/n",workfile);
exit(1); /*error so exit*/
}
printf("successfully");
exit(0);
/*call open successfully*/
}
creat系统调用:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int creat(const char *pathname,mode_t mode);
creat总是把已经存在的文件长度截为0.
下面两个语句是等价的:
filedes=creat("/tmp/newfile",0644);
filedes=open("/tmp/newfile",O_WRONLY | O_CREAT |O_TRUNC,0644);
close系统调用:
close系统调用与open是对立的,表示关闭文件。
#include <unistd.h>
int close(int filedes);
close在调用成功的情况下返回0,错误返回-1.
当一个程序退出时,它所打开的所有文件都将自动关闭。
文件读写read/write
read系统调用用来把文件中任意数目的字符或字节读入调用程序所控制的缓存中。
simple_open.c:
#include<stdlib.h> /*for the exit call*/
#include<fcntl.h>
#include<stdio.h>
char *workfile="junk";
int main(void)
{
int filedes;
/*open using O_RDWR from <fcntl.h>*/
/*file to be opened for read/write*/
if((filedes=open(workfile,O_RDWR|O_CREAT,0644))==-1)
{
printf("Could n't open %s\n",workfile);
exit(1); /*error so exit*/
}
printf("successfully");
exit(0);
/*call open successfully*/
}
simple_read.c:
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<stdio.h>
#define BUFSIZE 512
int main(void)
{
char buffer[BUFSIZE];
int filedes;
ssize_t nread;
long total=0;
char filename[25];
printf("Please input the filename you want to count:");
scanf("%s",filename);
/*open "anotherfile" read only*/
if((filedes=open(filename,O_RDONLY))==-1)
{
printf("error in opening %s\n",filename);
exit(1);
}
while((nread=read(filedes,buffer,BUFSIZE))>0)
{
total+=nread;/*increment total*/
}
printf("total chars in %s :%ld\n",filename,total);
exit(0);
}
文件创建掩码和umask系统调用
个人理解:umask调用接受的参数是新的umask,返回的是旧的umask.
因此可以先把掩码置0,再创建文件,然后再恢复掩码。
例如:old=umask(0);
openfile;
umask(old);
#include<fcntl.h>
#include<sys/stat.h> //umask call
//create file with the given mode
int specialcreat(const char *pathname,mode_t mode)
{
mode_t oldu;//old umask
int filedes;//file descriptor
/*set file creation mask to zero*/
if((oldu=umask(0))==-1)
{
perror("saving old mask");
return (-1);
}
/*create the file*/
if((filedes=open(pathname,O_WRONLY|O_CREAT|O_EXCL,mode))==-1)
{
perror("file open");
}
/*restore the old file mode,even if open failed*/
if(umask(oldu)==-1)
{
perror("restoring old mask");
}
/*return the file descriptor*/
return filedes;
}
int main(void)
{
int specialcreat(const char *pathname,mode_t mode);
char *path1="junk1";//the file path
char *path2="junk2";
if(specialcreat(path1,0777)==-1)
{
perror("file create");
return (-1);
}
/*create file whthout set umask zero*/
if(open(path2,O_WRONLY|O_CREAT|O_EXCL,0777)==-1)
{
perror("file create");
return (-1);
}
return 0;
}
//运行结果如下:
//-rwxrwxrwx 1 jiang jiang 0 2011-03-10 10:30 junk1*
//-rwxr-xr-x 1 jiang jiang 0 2011-03-10 10:30 junk2*
使用access系统调用测试文件的可访问性
#include<unistd.h>
int access(const char *pathname,int amode);
amode参数有三种可能的值:
R_OK 读
W_OK 写
X_OK 执行
返回0表示有权限,返回-1表示没有权限或文件不存在,错误记录在errno中。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
/*example use of access*/
int main(void)
{
char *filename="afile";
if(access(filename,R_OK)==-1)
{
fprintf(stderr,"User cannot read file%s\n",filename);
exit(1);
}
printf("%s readable,proceeding\n",filename);
return 0;
}
link 系统调用:用来创建文件的硬链接。link不能创建目录的链接,并且不能跨文件系统创建链接。
#include<unistd.h>
int link(const char *orginal_path,const char *new_path);
第一个参数必须存在,第二个参数必须不存在,调用成功返回0,失败返回-1;
unlink系统调用:删除文件硬链接
int unlink(const char *path);
/*move --move a file from one pathname to another*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
char *usage="usage:move file1 file2 \n";
int main(int argc,char **argv)
{
/*main use args passed from command line in
* standard manner
*/
if(argc!=3)
{
fprintf(stderr,"%s",usage);
exit(1);
}
if(link(argv[1],argv[2])==-1)
{
perror("Link failed");
exit(1);
}
if(unlink(argv[1])==-1)
{
perror("unlink failed");
unlink(argv[2]);
exit(1);
}
printf("Succeeded\n");
return 0;
}
结果:
jiang@jiangfeng:~/unixprog$ ./move.o junk1 junk3
Succeeded
使用stat和fstat系统调用获得文件信息
stat 和fstat使得一个进程可以查看文件存在的各种属性。
#include<sys/types.h>
#include<sys/stat.h>
int stat(const char *pathname,struct stat *buf);
int fstat(int filedes,struct stat *buf);
stat接受两个参数,第一个是pathname,指向需要查询的文件,第二个是buf,指向stat结构的指针,这个结构记录的是文件的各种属性值。
fstat系统调用的功能基本与stat类似,区别是fstat的第一个参数是文件描述符,所以fstat只可以访问已经打开的文件。
stat结构包含以下内容:只列常用的
mode_t st_mode;//文件的权限值
uid_t st_uid;//文件的uid
gid_t st_gid;//文件的gid
off_t st_size;//文件的逻辑字节数
//filedata.c:
/*filedata ---display information about a file*/
#include<stdio.h>
#include<sys/stat.h>
/*
* use octarray for determining
* if permission bits set
*/
static short octarray[9]={0400,0200,0100,
0040,0020,0010,
0004,0002,0001};//it means rwx rwx rwx
/*record the file permission format as rwxrwxrwx,use
* 10 chars long becausr the last one is null
*/
static char perms[10]="rwxrwxrwx";
int filedata(const char *pathname)
{
struct stat statbuf;
char descript[10];
int j;
if(stat(pathname,&statbuf)==-1)
{
fprintf(stderr,"Couldn't stat %s\n",pathname);
return (-1);
}
/*put permission into readable form*/
for(j=0;j<9;j++)
{
/*
* test whether permission set
* using bitwise AND
*/
if(statbuf.st_mode &octarray[j])
{
descript[j]=perms[j];
}
else
{
descript[j]='-';
}
}
descript[9]='\0';//make sure we've a string
/*display file information*/
printf("\nFile %s:\n",pathname);
printf("Size %ld bytes\n",statbuf.st_size);
printf("User-id %d,Group_id:%d \n\n",statbuf.st_uid,statbuf.st_gid);
printf("Permission:%s\n",descript);
return 0;
}
int main(int argc,char **argv)
{
if(argc!=2)//有两个参数,第一个程序本身的名字,第二个是命令行参数
{
perror("the program must accept a argument!");
}
if(filedata(argv[1])==-1)
{
perror("display filedata error!");
}
return 0;
}
该程序接受一个命令行参数,表示要查看信息的文件名,
运行结果如下:
jiang@jiangfeng:~/unixprog$ ./filedata.o move.c
File move.c:
Size 515 bytes
User-id 1000,Group_id:1000
Permission:rw-r--r--
/*use system call lseek to count the filesize*/
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
int countFileSize(const char *file)
{
int count;
off_t newpos;
int filedes; /*file descript number*/
filedes=open(file,O_RDWR);
newpos=lseek(filedes,(off_t)0,SEEK_END);
count=(int)newpos;
return count;
}
int main(void)
{
int countFileSize(const char *file);
int num;
char filename[]="junk";
num=countFileSize(filename);
printf("The %s size is %i\n",filename,num);
return 0;
}
linux c 输出标准错误
#include<stdlib.h> /*for the exit call*/
#include<fcntl.h>
#include<stdio.h>
#include<errno.h>
char *workfile="junk";
int main(void)
{
int filedes;
/*open using O_RDWR from <fcntl.h>*/
/*file to be opened for read/write*/
if((filedes=open(workfile,O_RDWR))==-1)
{
fprintf(stderr,"error%d\n",errno);
printf("Could n't open %s\n",workfile);
perror("error opening junk");//输出与当前errno值相联系的出错信息
exit(1); /*error so exit*/
}
printf("successfully");
exit(0);
/*call open successfully*/
}
使用系统调用复制文件的小程序
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#define BUFSIZE 512 /*size of chunk to be read*/
#define PERM 0644 /*file permission for new file*/
/*copy name1 to name2*/
int copyfile(const char *name1,const char *name2)
{
int infile,outfile;
ssize_t nread;
char buffer[BUFSIZE];
if((infile=open(name1,O_RDONLY))==-1)
{
printf("open %s error\n",name1);
return -1;
}
if((outfile=open(name2,O_WRONLY |O_CREAT | O_TRUNC,PERM))==-1)
{
close(infile);
printf("open %s error\n",name2);
return -2;
}
/*now read from name1 BUFSIZE chars at a time*/
while((nread=read(infile,buffer,BUFSIZE))>0)
{
/*write buffer to output file*/
// if(write(outfile,buffer,BUFSIZE)<nread)
if(write(outfile,buffer,nread)<nread)
{
close(infile);
close(outfile);
printf("write to %s error!\n",name2);
return -3; /*write error*/
}
}
close(infile);
close(outfile);
if(nread==-1) /*error in last read*/
{
printf("error in lase read %s\n",name1);
return -4;
}
else
{
printf("successfull at copy %s to %s",name1,name2);
return 0; /*all is well*/
}
}
int main(void)
{
int copyfile(const char *name1,const char *name2);
copyfile("test.in","test.out");
return 0;
}