文件的创建
这里先来看Linux系统调用方式的文件编程
首先,文件是如何产生的?我们可以使用creat函数来创建一个文件。在终端中man creat
#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);
int creat(const char *pathname, mode_t mode);
creat函数的参数,filename是要创建的文件名,包含路径。mode是创建模式。
文件名不包含路径时,则产生的文件会出现在程序的工作目录。
常见的创建模式有
S_IRWXU 00700 user (file owner) has read, write and execute permission
S_IRUSR 00400 user has read permission
S_IWUSR 00200 user has write permission
S_IXUSR 00100 user has execute permission
S_IRWXG 00070 group has read, write and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others have read, write and executepermission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
此外,还可以用数字来表示文件的访问权限,1表示可执行,2表示可写,4表示可读。三个数字可任意相加,所得的和用来表示文件的权限。如可读可执行可用5表示,可读可写用6表示。#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
creat("hello_creat",0755);
return 0;
}
编译执行后,会在程序的执行目录下产生一个名为hello_creat文件。这个只是个示例程序,完善一点,需要判断一下creat的返回值,防止出错。
文件的打开操作
有了文件,我们就可以看看文件里面是什么或者向文件里存放一些我们自己的东西。但在这之前,需要先打开文件。首先介绍一下文件描述符。在linux系统中,每一个打开的文件都有一个文件描述符。它是一个非负的整数。当文件被打开时,系统会分配一个文件描述符。
文件的打开,可以只用open函数。老规矩,man一下
#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);
int creat(const char *pathname, mode_t mode);
pathname依然是包含路径的文件名。flags是打开标志。常见的打开标志有O_RDONLY, O_WRONLY, or O_RDWR,分别是只读、只写、读写。此外还有O_APPEND追加方式,O_CREAT,O_NOBLOCK等等。如果选用了O_CREAT,那么就需要使用含有3个参数的open函数,第三个参数正是用来制定文件的权限的。这个和creat函数相同。
如果文件正确打开,会得到文件描述符。文件使用完毕后,就需要用close来关闭文件。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void)
{
int fd;
if((fd = open("abc.txt",O_RDONLY | O_CREAT,0755))<0)
{
perror("open");
exit(1);
}
printf("fd = %d\n",fd);
close(fd);
return 0;
}
在这里使用O_CREAT,如果文件不存在会创建。如果没有O_CREAT,文件不存在的话,open会出错。
文件的读写
既然文件已经打开,那就开始尽情地蹂躏它吧!我们通过程序创建的文件,是空文件,所以我们先尝试向里面写点内容。接下来,write函数出场了。
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数fd,是刚才用open获得的文件描述符。buf是准备写入的内容。count是写入内容的长度。
函数的返回值是实际写入的字节数。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void)
{
int fd,len = 0;
char buf[100] = {0};
if((fd = open("abc.txt",O_RDWR | O_CREAT,0755))<0)
{
perror("open");
exit(1);
}
if((len = write(fd,"hello world",11))<0)
{
perror("write");
close(fd);
exit(1);
}
return 0;
}
编译执行完毕后,打开abc.txt,就可以看到我们用程序写入的“hello world”了。
文件中有了内容,可以使用read函数将内容读出来。 #include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数fd依然是文件描述符。buf是读出内容的存放首地址。count是预期读到的字节数。
返回值是实际读到的字节数。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void)
{
int fd,len = 0;
char buf[100] = {0};
if((fd = open("abc.txt",O_RDWR | O_CREAT,0755))<0)
{
perror("open");
exit(1);
}
if((len = read(fd,buf,100))<0)
{
perror("read");
close(fd);
exit(1);
}
printf("read %s\n",buf);
return 0;
}
编译执行后,可读出刚才写入的“helloworld”
读写指针的偏移
我们先来做这样一个程序:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void)
{
int fd,len = 0;
char buf[100] = {0};
if((fd = open("abc.txt",O_RDWR | O_CREAT,0755))<0)
{
perror("open");
exit(1);
}
if((len = write(fd,"hello abcde",11))<0)
{
perror("write");
close(fd);
exit(1);
}
if((len = read(fd,buf,100))<0)
{
perror("read");
close(fd);
exit(1);
}
printf("read %s\n",buf);
return 0;
}
我们预期会看到输出 read helloabcde,但是只输出了read,哪里不对呢?这里介绍文件读写指针的概念。在对文件进行读写操作的时候,会有一个文件读写指针来指示当前操作位置与起始位置的偏移。
函数lseek可用于读写指针的定位。 #include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能是将文件读写指针相对whence移动offset个字节。操作成功是,返回文件指针相对于文件头的位置。whence可使用SEEK_SET、SEEK_CUR、SEEK_END,分别表示相对文件开头、相对稳健读写指针的当前位置、相对稳健末尾。offset可以取负值,表示向前移动。
在上面的例子中,写入“helloabcde”后,文件读写指针在“hello abcde”之后,所以再进行读操作时,无法读出内容来。
这里我们使用lseek来计算一下文件的长度。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main(void)
{
int fd,len = 0;
fd = open("abc.txt",O_RDONLY);
if(fd<0)
{
perror("open");
exit(1);
}
len = lseek(fd,0,SEEK_END);
if(len < 0)
{
perror("lseek");
close(fd);
exit(1);
}
printf("len = %d\n",len);
return 0;
}
文件访问判断
当我们需要判断文件是否可以进行读写或者执行操作时,可以使用access函数。
#include <unistd.h>
int access(const char *pathname, int mode);
pathname是文件名,可包含路径。mode是要判断的权限,可以取下列值或者其组合,R_OK:文件可读,W_OK:文件可写,X_OK:文件可执行,F_OK:文件存在。
成功时,函数返回0,否则返回-1。
#include <stdio.h>
#include <unistd.h>
int main(void)
{
if(access("/etc/service",W_OK) == 0)
{
printf("ok\n");
}
else
{
printf("can not be writen\n");
}
return 0;
}
然后我们看一下service文件的权限,$ll/etc/service
-rw-r--r--. 1root root 641020 Mar 24 2012 services