函数open(),create(),lseek()介绍
- 函数原型:
int open(const char* pathname, int falgs);
int create(const char* pathname, int falgs);
int open(const char* pathname, int flags, mode_t mode);
int create(const char* pathname, int flags, mode_t mode); - 包含头文件
sys/types.h,sys/stat.h和fcntl.h; - 返回值
正常返回文件的描述值,错误返回-1; - flags
必选:
O_RDONLY,O_WRONLY,O_RDWR
可选:
O_APPEND 追加
O_CREAT 不存在则创建,mode需要设置!
O_EXCL 查看文件是否存在,如果同时指定了O_CREAT,而文件已经存在在则返回错误。用这种方法可以安全打开文件
O_TRUNC 将文件长度截断为0,通常用于对需要清空的文件进行归零操作 - mode
结合O_CREAT使用,否则无效
读写执行权限:
S_IRWXU(G\O) U(G\O)分别代表user、group、other
读或写或执行权限
S_IR(W\X)USR(GRP\OTH) R(W\X)分别代表读写执行,USR(GRP\OTH)分别代表user、group、other - 示例
/*open_test.c 打开文件的例子*/
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
int main(void)
{
int fd = -1;
char filename[] = "test.txt";
fd = open(filename,O_RDWR);
if(fd>-1)
{
printf("Open file %s success,fd:%d\n",filename,fd);
}
else
{
printf("Open file %s failure!\n",filename);
}
return 0;
}
- 执行结果
$ ll
总用量 5
drwxrwxrwx 1 zhujun zhujun 256 10月 4 18:54 ./
drwxrwxrwx 1 zhujun zhujun 360 10月 4 18:23 ../
-rwxrwxrwx 1 zhujun zhujun 638 10月 4 18:54 open_test.c*
$ gcc -o open1 open_test.c
$ ./open1
Open file test.txt failure!
$ echo "">test.txt
$ ./open1
Open file test.txt success,fd:3
关闭文件函数close()
头文件unistd.h
int close(int fd);
读取文件read()函数
- 依赖头文件unistd.h
- 函数原型
ssize_t read(int fd, void* buf, size_t count);
从文件描述符fd对应的文件中读取count字节,放到buf开始的缓冲区中,如果count=0,则返回0,不进行其他操作;如果count大雨SSIZE_MAX,则结果不可预料。读取成功的时候,文件对应的读取位置指针,向后移动位置,大小为成功读取的子节成功则返回字节数,失败返回-1,文件末尾返回0。 返回值类型为ssize,具体实现时可以定义为long或者int - 示例
/* 文件read_test.c */
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
int main(void)
{
int fd = -1;
ssize_t size = -1;
char buff[10];
char filename[] = "test.txt";
fd = open(filename, O_RDONLY);
if(fd<0)
{
printf("Open file %s failure\n",filename);
}
else
{
printf("Open file %s success,fd %d\n",filename,fd);
}
while(size)
{
size = read(fd, buff, 10);
if(size == -1)
{
close(fd);
printf("Read file error occurs.\n");
return -1;
}
else
{
if(size>0)
{
printf("Read %d bytes:",size);
printf("\"");
for(int i=0;i<size;i++)
printf("%c",*(buff+i));
printf("\"\n");
}
else
{
printf("Reach EOF.\n");
}
}
}
return 0;
}
test.txt 文件内容:
This is a test file to test if read function could run well.
- 运行结果
$ gcc -o rt read_test.c
read_test.c: In function ‘main’:
read_test.c:29:37: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 3 has type ‘int’ [-Wformat=]
printf("Open file %s success,fd %ld\n",filename,fd);
~~^
%d
read_test.c:44:19: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘ssize_t {aka long int}’ [-Wformat=]
printf("Read %d bytes:",size);
~^
%ld
$ ./rt
Open file test.txt success,fd 3
Read 10 bytes:"This is a "
Read 10 bytes:"test file "
Read 10 bytes:"to test if"
Read 10 bytes:" read func"
Read 10 bytes:"tion could"
Read 10 bytes:" run well."
Read 1 bytes:"
"
Reach EOF.
lseek()函数
- 函数原型:
#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fd, off_t offset, int whence);
-
描述:
对文件描述符fd对应的文件,按照模式whence和相对偏移量offset,重新设置文件的偏移量。返回新的偏移量(成功),失败返回-1。
whence表示操作模式,offset表示相对偏移量
whence:
SEEK_SET
文件起始位置
SEEK_CUR
当前偏移位置
SEEK_END
文件末尾off_t cur_pos = lseek(fd, 0, SEEK_CUR)
可以获得当前的偏移量,也可以校验当前设备是否支持lssek函数。 -
示例
/* lseek_test.c */
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
int main(void)
{
off_t offset = -1;
offset = lseek(1, 0, SEEK_CUR);/*将标准输入文件描述符的文件偏移量设为当前值*/
/* 0,1,2描述符分配给系统,0:标准输入;1:标准输出;2:标准错误*/
if(offset == -1)
{
printf("STDOUT can`t seek\n");
return -1;
}
else
{
printf("STDOUT can seek\n");
}
return 0;
}
- 结果
$ gcc -o lsek lseek_test.c
$ ./lsek
STDOUT can`t seek
获得文件状态fstat函数
- 文件状态:文件大小、权限、修改时间
- stat(), fstat(), lstat()可以获得文件的状态
- 函数原型:
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
int stat(const char* path, struct stat * buf);
int fstat(int fd, struct stat * buf);
int lstat(const char* path, struct stat *buf);
- 描述:成功时返回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_blksize; /*文件系统的块大小*/
blkcnt_t st_blocks; /*占用的块的数量*/
time_t st_atime; /*最后方位时间*/
time_t st_mtime; /*最后修改时间*/
time_t st_ctime; /*最后状态改变时间*/
}
文件空间映射函数mmap
- 函数原型:
#include<sys/mman.h>
void* mmap(void * start, size_t length, int prot, int flags, int fd, off_t offset);
- 描述:
将文件或者设备空间映射到内存中,可以通过对映射后的内存空间存取来获得存取文件一致的控制方式,不必使用read、write函数。简单来说就是将文件映射到内存中的某一段,映射到的内存不占用空间,仅仅占用一段地址空间。
将描述符fd对应的文件,自offset开始的一段长为length的数据映射到内存中,用户可以设定映射的内存地址,但是具体映射到内存的位置由返回值确定。当映射成功后,返回映射到的内存地质。如果失败返回值为(void *)-1。通过errno获得错误方式。
start 指定要映射到的地址,通常为NULL
prot 表示映射区保护方式,是一个组合值,可以是一个或者多个
当然这个设置会受到打开文件的限制,权限不能超过打开文件的权限,超过则对应的权限失效。值 描述 PROT_EXEC 可执行 PROT_READ 可读 PROT_WRITE 可写 PROT_NONE 不能存取
flags 设定映射对象的类型、选项和是否可以对映射对象进行操作,也是一个组合值值 描述 MAP_FIXED 如果设置了start,而无法映射到所指的地址,则映射失败 MAP_SHARED 共享映射区域,映射区域允许其他进程共享,对映射区域写入数据将会写入到原文件中 MAP_PRIVATE 对映射区域的修改不会写入原文件 MAP_ANONYMOUS 建立匿名映射。此时忽略参数fd,不涉及文件,而且映射区无法和其他进程共享 MAP_DENYWRITE 禁止文件写入操作,只能通过对映射区操作的方式实现对文件的操作,不允许直接操作文件 MAP_LOCKED 将映射区锁定,此区域不会被虚拟内存重置
MAP_PRIVATE,MAP_SHARED必须选其一。shared表示多个进程使用一个内存映射的副本,任何进程都可以对此映射区进行修改,而且修改可见。private表示多个进程之间的副本不一致,写入操作之后,会复制一个副本给修改的进程。
munmap函数 取消mmap函数的映射关系
- 原型
#include<sys/mman.h>
int munmap(void* start, size_t length);
- 描述:
start为mmap函数的返回值,即映射的内存地址,length为映射长度 - 编程模式:
/*打开文件*/
fd = open(filename, flags, mode);
if(fd<0)
...(error);
ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
/*对文件进行操作*/
...
/*取消映射关系*/
numap(ptr, len);
/*关闭文件*/
close(fd);
- 示例
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/mman.h>
#include<string.h>
#include<stdio.h>
#define FILELENGTH 80
int main(void)
{
int fd = -1;
char buf[] = "quick brown fox jumps over the lazy dog";
char* ptr = NULL;
/*打开文件,并将文件长度缩短为0,不存在则创建,权限为可读可写可执行*/
fd = open("mmap.txt", O_RDWR|O_CREAT|O_TRUNC, S_IRWXU);
if(fd == -1) return -1;
/*将文件长度扩展为80,向后偏移文件的偏移量到79*/
lseek(fd, FILELENGTH-1, SEEK_SET);
write(fd, "a", 1);/*随意写入一个字符*/
/*将文件mmap.txt中的数据从开头到1M的数据映射到内存中,对文件操作立即显示在文件上,可读写*/
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;
}
/*将buf中的字符串复制到映射区域中,起始位置为ptr+16*/
memcpy(ptr+16, buf, strlen(buf));
munmap(ptr, FILELENGTH);
close(fd);
return 0;
}
- 运行结果
$ gcc -o mapt mmap_test.c
$ ./mapt
$ ll
总用量 82
drwxrwxrwx 1 zhujun zhujun 4096 10月 5 16:07 ./
drwxrwxrwx 1 zhujun zhujun 4096 10月 4 18:23 ../
-rwxrwxrwx 1 zhujun zhujun 8704 10月 5 16:07 mapt*
-rwxrwxrwx 1 zhujun zhujun 1347 10月 5 16:06 mmap_test.c*
-rwxrwxrwx 1 zhujun zhujun 80 10月 5 16:07 mmap.txt*
$ od -c mmap.txt
0000000 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000020 q u i c k b r o w n f o x
0000040 j u m p s o v e r t h e l
0000060 a z y d o g \0 \0 \0 \0 \0 \0 \0 \0 \0
0000100 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 a
0000120