1、UNIX文件基础
1.1 UNIX输入输出
1 文件描述符
(1)顺序分配的非负整数
(2)内核用以标识一个特定进程正在访问的文件
(3)其他资源(socket、pipe)访问的标识
2 标准输入stdin、标准输出stdout和标准出错stderr
这三项是shell默认打开的,对应的文件描述符分别是0/1/2
1.2 UNIX出错处理
1.2.1 错误码errno
全局的错误码errno,执行函数发生错误时,errno会被置为一个非0的数字,对应一个错误编号。正确时该值不会被清0,但有可能会改变。在使用前,errno首先应被置0;
1.2.2错误处理函数
错误处理函数有两个,strerror()和perror();
函数原型:void perror(const char *s);
功能:在标准出错上打印错误信息
显示效果:s + ‘:’ + ‘空格’ + ‘错误信息’ + ‘\n’
功能:在标准出错上打印错误信息
显示效果:s + ‘:’ + ‘空格’ + ‘错误信息’ + ‘\n’
函数原型char *strerror(int errnum);
功能 :将错误码转化成对应的错误信息
功能 :将错误码转化成对应的错误信息
#inclu #include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
int fd = open(argv[1], O_RDONLY);
if(fd == -1)
{
printf("printf\n"); //打印在标准输出上
perror("perror"); //打印在标准出错上
printf("strerror:%s\n", strerror(errno));
return -1;
}
return 0;
}
我们显示一个出错结果
perro是自动打印出了出错的信息,stderr是将特定的错误信息打印出来。
1.2.3 系统调用和库函数
系统调用
1、用户空间进程访问内核的接口
2、把用户从底层的硬件编程中解放出来
3、极大提高了系统的安全性
库函数
1、库函数为了实现某个功能而封装起来的API集合
2、提供统一的编程接口,更加便于应用程序的移植
我们上一节标准IO的讲到的函数属于是库函数,是标准C库函数,只要有标准C库就都可以使用。本文讲到的文件IO属于系统调用,是用户层向Linux内核层转换的接口。
系统调用和库函数的区别
(1)所有的操作系统都提供多种服务的入口点,通过这些入口点,程序向内核请求服务
(2)从执行者的角度来看,系统调用和库函数之间有重大的区别,但从用户的角度来看,其区别并不重要
(3)应用程序可以调用系统调用或者库函数,库函数则会调用系统调用来完成其功能
(4)系统调用通常提供一个访问系统的最小界面,而库函数通常提供比较复杂的功能。
2 文件IO
同标准IO类似,本文主要介绍以下几个函数:
①open()/creat()
②close()
③read()
④write()
⑤lseek()
2.1 打开文件
头文件:#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 open(const char *pathname, int flags, mode_t mode);
功能:打开一个文件,获得文件的文件描述符
参数:pathname:指定打开的文件路径及名字
参数:pathname:指定打开的文件路径及名字
mode:与O_CREAT同时存在才生效。指定文件的创建权限
返回值:成功返回描述符,这个描述符是最小的可用描述符;失败返回-1;
open()可以打开设备文件,但是不能创建设备文件,设备文件通常使用命令mknod创建。
文件创建的权限还与权限掩码umask有关,umask默认为002,并且创建文件时默认所有用户都没有执行权限,所以
即使在打开一个文件时设置权限为“777”,实际权限则是“664”。创建一个目录时的默认权限是“775”,也就是有执行
权限
2.2 关闭
函数原型:int close(int fd);
参数:文件描述符
返回值:成功返回0,失败返回-1
2.3 read
函数原型:size_t read(int fd, void *buf, size_t count);
功能:从文件fd中期望读取count字节的数据存储到buf内
参数:count:期望读取的字节数
返回:成功读取的字节数,0文件末尾,-1出错
功能:从文件fd中期望读取count字节的数据存储到buf内
参数:count:期望读取的字节数
返回:成功读取的字节数,0文件末尾,-1出错
2.4 write
函数原型:ssize_t write(int fd, const void *buf, size_t count);
功能:将buf里的数据写到文件fd中,大小为count字节
返回:成功写入的字节数,失败-1
功能:将buf里的数据写到文件fd中,大小为count字节
返回:成功写入的字节数,失败-1
2.5 定位
函数原型:off_t lseek(int fd, off_t offset, int whence);
功能:改变文件当前的读写位置
参数:whence:SEEK_SET SEEK_CUR SEEK_END(最后一个字符的下一个位>
offset:偏移量,与whence相加
返回:重新设定位置后当前位置的偏移量(相对起始位置)
功能:改变文件当前的读写位置
参数:whence:SEEK_SET SEEK_CUR SEEK_END(最后一个字符的下一个位>
offset:偏移量,与whence相加
返回:重新设定位置后当前位置的偏移量(相对起始位置)
每个打开的文件都有一个与其相关的“当前文件位移量”,它是一个非负整数,用以度量从文件开始处计算的字节数。
通常,读/写操作都从当前文件位移量处开始,在读/写调用成功后,使位移量增加所读或者所写的字节数。
lseek()调用成功为新的文件位移量,失败返回-1,并设置errno。
lseek()只对常规文件有效,对socket、管道、FIFO等进行lseek()操作失败。
lseek()仅将当前文件的位移量记录在内核中,它并不引起任何I/O操作。
文件位移量可以大于文件的当前长度,在这种情况下,对该文件的写操作会延长文件,并形成空洞。
通常,读/写操作都从当前文件位移量处开始,在读/写调用成功后,使位移量增加所读或者所写的字节数。
lseek()调用成功为新的文件位移量,失败返回-1,并设置errno。
lseek()只对常规文件有效,对socket、管道、FIFO等进行lseek()操作失败。
lseek()仅将当前文件的位移量记录在内核中,它并不引起任何I/O操作。
文件位移量可以大于文件的当前长度,在这种情况下,对该文件的写操作会延长文件,并形成空洞。
复制拷贝文件例程
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define N 32
int main(int argc, const char *argv[])
{
int fd_r = open(argv[1], O_RDONLY);
if(fd_r == -1)
{
printf("fd_r open error\n");
return -1;
}
int fd_w = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0664);
if(fd_w == -1)
{
printf("fd_w open error\n");
return -1;
}
char buf[N] = {0};
int ret = 0;
while((ret = read(fd_r, buf, N)) > 0) //ret为0代表读到文件末尾
{
write(fd_w, buf, ret);
}
close(fd_r);
close(fd_w);
return 0;
}
2.6 文件锁
函数原型:int fcntl(int fd, int cmd, …);
参数:fd,文件描述符
cmd:F_GETLK:检查文件锁
F_SETLK:设置文件锁
F_SETLK:设置文件锁(可能引起睡眠)
返回值:成功返回0,失败返回-1
2.7 获取文件信息
文件信息结构体
struct stat {
ino_t st_ino; // ionde号
mode_t st_mode; // 权限、类型
nlink_t st_nlink; // 硬连接数
uid_t st_uid; // user ID of owner
gid_t st_gid; // group ID of owner
off_t st_size; // 大小
time_t st_atime; // 最后访问时间
time_t st_mtime; // 最后修改时间
};
ino_t st_ino; // ionde号
mode_t st_mode; // 权限、类型
nlink_t st_nlink; // 硬连接数
uid_t st_uid; // user ID of owner
gid_t st_gid; // group ID of owner
off_t st_size; // 大小
time_t st_atime; // 最后访问时间
time_t st_mtime; // 最后修改时间
};
st_mode指的是文件权限和类型,linux系统定义了以下几种情况(八进制)
S_IFMT 0170000 bitmask for the file type bitfields S_IFSOCK 0140000 socket S_IFLNK 0120000 symbolic link S_IFREG 0100000 regular file S_IFBLK 0060000 block device S_IFDIR 0040000 directory S_IFCHR 0020000 character device S_IFIFO 0010000 fifo S_ISUID 0004000 set UID bit S_ISGID 0002000 set GID bit (see below) S_ISVTX 0001000 sticky bit (see below) S_IRWXU 00700 mask for file owner permissions S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 mask for group permissions S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 mask for permissions for others (not in group) S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permisson S_IXOTH 00001 others have execute permission
1、int stat(const char *path, struct stat *buf);
功能:获取一个文件的属性信息
参数:path:要访问的文件
buf :存储属性信息
返回:成功返回0,失败返回-1
通过文件描述符获取该文件的属性信息。其余与stat一样。
3、int lstat(const char *path, struct stat *buf);
当访问软链接文件时,lstat获得的是链接文件的属性信息,stat获得的是原文件的属性信息
3、标准IO与文件比较
去