4. mmap/munmap
1. 打开/关闭一个文件
NAME
open, creat - open and possibly create a file or device
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
open用来打开一个文件(或创建一个文件并打开它)
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname: 要打开的文件的文件名(带路径)
flags: 打开标志。用位域实现
O_RDONLY: RD, read 只读打开
O_WRONLY: WR, write只写打开
O_RDWR: read write 读写打开
以上三个标志任选其一
O_APPEND: 追加方式。
O_CREAT : create创建标志(如果文件不存在则创建)
O_NONBLOCK: non block 非阻塞方式打开。
"阻塞方式": 如果文件为空,read则会等待
"非阻塞方式":你懂的
O_EXCL: 该标志一般和O_CREAT 配合使用(O_CREAT | O_EXCL),
用来测试文件是否存在。指定O_CREAT | O_EXCL,
如果文件存在,则open会失败,并且errno == EEXIST
O_TRUNC: truncate(剪断), 截短标志.(清零)
假如文件存在,并且是一个普通文件,而且
打开方式是O_RDWR或 O_WRONLY,则文件内容会被
清空。
...
mode: 用来指定新创建的文件的权限,有两种方式:
(1) S_IRUSR, S_IWUSR, S_IXUSR -> S_IRWXU == S_IRUSR | S_IWUSR | S_IXUSR
S_IRGRP, S_IWGRP,S_IXGRP -> S_IRWXG ==
S_IROTH, S_IWOTH, S_IXOTH -> S_IRWXO ==
S_IRUSR | S_IRGRP | S_IROTH
(2) 0660
返回值:
如果成功返回一个文件描述符,后续对该文件的操作
都必须通过此文件描述符。
失败返回-1, errno被设置
creat仅用来创建一个文件,
int creat(const char *pathname, mode_t mode);
成功返回0,失败返回-1
=====
NAME
close - close a file descriptor
SYNOPSIS
#include <unistd.h>
int close(int fd);
2. 读写一个文件 read/write
NAME
read - read from a file descriptor
SYNOPSIS
#include <unistd.h>
read用来从fd指定的文件中,读取 count个字节到
buf指定的内存空间。
ssize_t read(int fd, void *buf, size_t count);
fd: 文件描述符,表示要从哪个文件里读数据
buf: 指针,指向一段内存,用来保存从文件中读取
到的数据
count: 表示要读多少字节数据
返回值:
> 0 表示成功读取到的数据的字节数
= -1: 表示失败了,errno被设置
=0: 表示文件结束了。
==
NAME
write - write to a file descriptor
SYNOPSIS
#include <unistd.h>
write用来把buf指向的内存空间中的前面count个字节
写到fd指定的文件中去
ssize_t write(int fd, const void *buf, size_t count);
fd: 文件描述符,表示要写到哪个文件中去
buf:指针,指向要写的数据
count:表示要写多少字节数据
返回值:
> 0: 表示成功写了多少个字节
=-1: 失败了,errno被设置
=0: 表示什么也没写。
练习:
用文件IO的接口写一个程序,来实现两个文件的拷贝。
read/write成功后,光标位置会自动增加n个位置(n表示你成功读或写的
字节数)
3.定位光标
NAME
lseek - reposition read/write file offset
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd: 要重定位的文件
offset: 偏移量,可正可负,具体含义需要结合第三个参数
whence: 定位方式,有三种:
SEEK_SET: 基于文件开头定位
SEEK_CUR: 基于文件当前位置定位
SEEK_END: 基于文件末尾定位
返回值:
成功返回新光标位置相对于文件开头的偏移量(以字节为单位)
失败返回-1, errno被设置。
例子:
如何求一个文件的大小?
unsinged long filesize = lseek(fd, 0, SEEK_END);
注意:
我们在实际读写文件前,一般要先定位lseek
我们能不能像操作内存一样,去操作文件呢?
当然可以。
需要用到mmap
4. mmap
NAME
mmap, munmap - map or unmap files or devices into memory
SYNOPSIS
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
addr: 映射地址,表示要映射到进程地址空间的哪个位置。
一般为NULL, 让操作系统自动为我选择一个合适的地址。
length:要映射的文件区域的长度。向上取PAGE_SIZE(4K)的整数倍
prot: 映射后内存区域的权限(应与文件打开权限一致,
因为操作此区域内存实际上就是操作文件内容)
PROT_EXEC:可执行
PROT_READ:可读
PROT_WRITE:可写可读
PROT_NONE:没访问权限
flags: 映射标志。决定对映射部分的操作是否对其他进程可见
MAP_SHARED: 共享。对其他进程可见,内存操作应用到文件中去
MAP_PRIVATE: 私有。对其他进程不可见,内存操作不应用到文件中去
fd: 文件描述符,表示要映射哪个文件
offset:偏移量,表示从文件哪个地方开始映射。
offset必须为PAGE_SIZE(4K)的整数倍
返回值:
成功返回映射后的内存首地址。
失败返回MAP_FAILED, errno被设置。
munmap就是解映射
int munmap(void *addr, size_t length);
addr: 要解映射的 首地址。PAGE_SIZE的整数倍。
length: 要解映射的长度。PAGE_SIZE
返回值:
成功返回0,
失败返回-1, errno被设置。
NOTE:
进程退出,会自动unmap,但是关闭文件不会自动unmap.
文件属性操作函数:
1.stat/fstat/lstat: get file status
2.access: 测试调用进程是否有权限去访问某个文件
3.umask : 设置文件权限掩码
4. chmod/fchmod 用来改变某个文件的权限位
5. chown/fchown/lchown 用来改变某个文件的所有者
6. truncate/ftruncate用来把某个文件截短
7. chdir 改变当前工作目录
getcwd获取当前目录的绝对路径
8. remove /unlink/rmdir 删除一个文件或目录
1. stat/fstat/lstat用来获取文件的属性信息
NAME
stat, fstat, lstat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
在linux内核中一个文件的属性(状态)信息,是用一个
结构体struct stat来描述的。如下:
struct stat {
//dev_t 在内核是用来表示设备号的。设备号相当于
//是设备的身份ID
dev_t st_dev; //设备号,容纳该文件的那个设备的设备号
ino_t st_ino; // inode number , i-node号
mode_t st_mode; //文件权限位
nlink_t st_nlink; //该文件的硬链接 数,
//硬链接与软链接的区别,你们要懂的。
uid_t st_uid; //文件所有者的ID(用户ID)
gid_t st_gid; //文件所有者的组ID
dev_t st_rdev; //文件的设备号(假如该文件是设备)
off_t st_size; // 文件内容的大小,以字节为单位
//普通文件,目录文件,符号链接文件
//上述三种文件的文件内容是什么?
//目录文件的内容:目录项数组
//符号链接文件的内容是: 保存它指向的文件的文件名
blksize_t st_blksize;//文件系统的块大小
blkcnt_t st_blocks; //占多少块(固定以512为块大小)
time_t st_atime; // 最后访问时间,"文件内容"
time_t st_mtime; //最后修改时间,"文件内容"
time_t st_ctime; //最后改变时间,"文件属性", i-node
};
stat用来把path指定的文件的属性信息,保存到
buf指向的结构体struct stat 中。
int stat(const char *path, struct stat *buf);
fstat功能与返回值与stat 一样,只不过,fstat是用文件描述符
来指定文件的。
int fstat(int fd, struct stat *buf);
lstat功能与stat相同,只不过当path是一个符号链接时,获取的是符号
链接本身的属性信息,而不是它指向的文件。
int lstat(const char *path, struct stat *buf);
返回值:
成功返回0,
失败返回-1, errno被设置
例子:
struct stat st;
stat(path, &st);
st.st_size ->
st.st_mode 包含文件的类型与权限,用下列宏来解析:
S_ISREG(st.st_mode) 普通文件 regular file
S_ISDIR(st.st_mode) 目录文件directory
S_ISCHR(st.st_mode) 字符设备 char
S_ISBLK(st.st_mode) 块设备 block
S_ISFIFO(st.st_mode) 管道文件 pipe(无名管道,有名管道 fifo)
S_ISLNK(st.st_mode) 符号链接文件 link
S_ISSOCK(st.st_mode) 套接字文件 socket
权限位:
S_IRUSR , S_IRGRP, S_IROTH
S_IWUSR
S_IXUSR
if (st.st_mode & S_IRUSR)
{
//用户有读的权限
}
练习:
写一个程序,求任意一个文件的类型、权限、
以及文件(假如该文件是普通文件、目录文件、符号
链接文件)的大小.
文件的类型和权限请按命令ls -l的形式打印
2. access 用来测试调用进程是否有相应的权限去访问由pathname指定的文件
NAME
access - determine accessibility of a file
SYNOPSIS
#include <unistd.h>
int access(const char *pathname, int amode);
pathname: 要测试的文件
amode:要测试的访问权限, "按位或",可以测试多项权限
R_OK : 测试是否可读
W_OK : 测试是否可写
X_OK :测试是否可执行
F_OK :测试文件是否存在
R_OK | W_OK
返回值:
成功返回0, 所有测试权限都OK
失败返回-1, 至少有一项测试没通过
3 .umask 设置文件创建的掩码
NAME
umask - set and get the file mode creation mask
SYNOPSIS
#include <sys/stat.h>
掩码,当中为1的bit位, 表示你在创建文件时不能指定
mode_t umask(mode_t cmask);
umask(022);
open(,,0660);
=> 0644
4. chmod/fchmod:用来改变文件的权限
NAME
chmod, fchmod - change permissions of a file
SYNOPSIS
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
chmod第一个是文件名
fchmod第一个参数是文件描述符
mode:新的权限 ,有两种方式指定,你懂的。
(1) S_IRUSR
(2) 0660
返回值:
成功返回0,
失败返回-1, errno被设置
5. chown/fchown
NAME
chown, fchown, lchown - change ownership of a file
SYNOPSIS
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
6 .文件截短
NAME
truncate, ftruncate - truncate a file to a specified length
SYNOPSIS
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
NOTE:
假如原文件长度> length, 保留文件前面length长度,后面的没了
假如原文件长度< length, 文件长度延伸至length,
7. chdir改变当前工作目录
NAME
chdir, fchdir - change working directory
SYNOPSIS
#include <unistd.h>
int chdir(const char *path);
8. 获取进程当前工作目录的绝对路径名
NAME
getcwd, getwd, get_current_dir_name - get current working
directory
SYNOPSIS
#include <unistd.h>
char *getcwd(char *buf, size_t size);
char *get_current_dir_name(void);
9. 删除一个文件(普通文件或目录文件): remove
删除普通文件:
unlink
删除一个空目录:
rmdir
NAME
remove - remove a file or directory
SYNOPSIS
#include <stdio.h>
remove用来删除pathname指定的文件或目录
int remove(const char *pathname);
返回值:
成功返回0,
失败返回-1, errno被设置。
NAME
unlink - delete a name and possibly the file it refers to
SYNOPSIS
#include <unistd.h>
unlink用来删除一个文件系统中的名字或普通文件
int unlink(const char *pathname);
NAME
rmdir - delete a directory
SYNOPSIS
#include <unistd.h>
rmdir用来删除一个空目录
int rmdir(const char *pathname);
DESCRIPTION
rmdir() deletes a directory, which must be empty.
目录结构及目录操作:(dir.c)
1. 创建、删除目录
mkdir
rmdir
2. 打开一个目录
opendir
3. 读一个目录
readdir
4.关闭一个目录
closedir
目录作业:
1.写一个程序,删除一个目录(可能为空,也可能不为空)
2.写一个程序,求一个目录下面所有的图片文件(.bmp, .jpg)的个数
1. 创建、删除一个目录
NAME
mkdir - create a directory
SYNOPSIS
#include <sys/stat.h>
#include <sys/types.h>
mkdir用来创建一个目录
int mkdir(const char *pathname, mode_t mode);
pathname:要创建的目录的路径名
mode: 新创建的目录的权限,有两种方式指定:
(1) S_IRUSR, ...
(2) 0660
返回值:
成功返回0,
失败返回-1, errno被设置。
NAME
rmdir - 删除一个空目录
SYNOPSIS
#include <unistd.h>
int rmdir(const char *pathname);
2. 打开一个目录opendir
NAME
opendir, open a directory
SYNOPSIS
#include <sys/types.h>
#include <dirent.h>
在linux中,用结构体 DIR 来表示一个打开的目录。
DIR *opendir(const char *name);
name: 要打开的目录名
返回值:
如果成功,返回一个DIR的指针
如果失败,返回NULL, errno被设置。
3. 读一个目录readdir
一个目录的内容,目录项的数组。
那么目录项是个什么东西呢?
在linux下目录项用结构体struct dirent,定义如下:
struct dirent {
ino_t d_ino; //I-NODE编号
off_t d_off; //数组的下标
unsigned short d_reclen; //该结构体的长度
unsigned char d_type; //该目录项代表的文件的类型(不是所有文件系统都支持)
char d_name[256]; //该目录项代表的文件的文件名(不带路径)
};
d_ino, d_name只有这两个成员变量是被所有系统支持的。
NAME
readdir, - read a directory
SYNOPSIS
#include <dirent.h>
readdir用来从dirp指定的目录中,读取下一个
目录项(struct dirent)的指针。如果一个目录中有多个
目录项,那么你就需要调用readdir多次,直到它
返回NULL为止。
struct dirent *readdir(DIR *dirp);
返回值:
成功返回目录中下一个目录项的指针
如果失败或读完了,返回NULL。
如果errno设置了,就是表示失败了。
4. 关闭一个目录
NAME
closedir - close a directory
SYNOPSIS
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);