基于文件描述符的文件操作
打开、创建和关闭文件
#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 函数等价于open(pathname,O_CREAT|O_TRUNC|O_WRONLY,mode);
open()函数出错时返回-1,相关参数如下:
flags 和 mode 都是一组掩码的合成值,flags 表示打开或创建的方式,mode 表示文件的访问权限。 mode参数只有在建立新文件时才会生效(flags中包含O_CREAT),表示新建文件的权限,但最终所建文件的权限会受到umask值所影响,因此该文件权限应该为(mode-umaks)。
flags 的可选项有
O_RDONLY 以只读的方式打开
O_WRONLY 以只写的方式打开
O_RDWR 以读写的方式打开
O_CREAT 如果文件不存在,则创建文件
O_EXCL 仅与 O_CREAT 连用,如果文件已存在,则强制 open 失败
O_TRUNC 如果文件存在,将文件的长度截至 0
O_APPEND 已追加的方式打开文件, 每次调用 write 时,文件指针自动先移到文件尾,用于多进程写一个文件的情况。
O_NONBLOCK 非阻塞方式打开,无论有无数据读取或等待,都会立即返回进程之中。
O_NODELAY 非阻塞方式打开
O_SYNC 同步打开文件,只有在数据被真正写入物理设备设备后才返回
mode的可选项有:
mode 的可选项有:
S_IRWXU 00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
S_IRUSR 00400 权限,代表该文件所有者具有可读取的权限。
S_IWUSR 00200 权限,代表该文件所有者具有可写入的权限。
S_IXUSR 00100 权限,代表该文件所有者具有可执行的权限。
S_IRWXG 00070 权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
S_IWGRP 00020 权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
S_IRWXO 00007 权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002 权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。
close 用于文件的关闭:
int close(int fd); //fd 表示文件描述符,是先前由 open 或 creat 创建文件时的返回值。
文件使用完毕后,应该调用 close 关闭它,一旦调用 close,则该进程对文件所加的锁全都被释放,并且使文件的打开引用计数减 1,只有文件的打开引用计数变为 0 以后,文件才会被真正的关闭。
#include <func.h>
int main(int argc, char* argv[])
{
ARGS_CHECK(argc, 2);
int fd;
fd = open(argv[1],O_RDWR);
ERROR_CHECK(fd, -1, "open");
printf("fd=%d\n",fd);
close(fd);
return 0;
}
#include <func.h>
int main(int argc, char* argv[])
{
ARGS_CHECK(argc, 2);
int fd;
fd = open(argv[1],O_RDWR|O_CREAT,0666);
ERROR_CHECK(fd, -1, "open");
printf("fd=%d\n",fd);
return 0;
}
读写文件
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count); //文件描述符 缓冲区 长度
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符 buf:写入的字符串,传入指向字符串的指针 count:写入的字节数
对于read函数同理,buf为读出的缓冲区,count为读出的字节数
read 和 write 函数,出错返回-1,读取完了之后,返回 0, 其他情况返回读写的个数
read.c
#include <func.h>
int main(int argc, char* argv[])
{
ARGS_CHECK(argc, 2);
int fd;
fd = open(argv[1],O_RDWR);
ERROR_CHECK(fd, -1, "open");
printf("fd=%d\n",fd);
char buf[128]={0};
int ret = read(fd,buf,sizeof(buf));
printf("buf=%s,ret=%d\n",buf,ret);
close(fd);
return 0;
}
write.c
#include <func.h>
int main(int argc, char* argv[])
{
ARGS_CHECK(argc, 2);
int fd;
fd = open(argv[1],O_RDWR);
ERROR_CHECK(fd, -1, "open");
printf("fd=%d\n",fd);
int ret = write(fd,&fd,sizeof(int));
printf("write count = %d\n",ret);
close(fd);
return 0;
}
案例:将 aaa.txt 中的内容复制到 bbb.txt 中,其中 bbb.txt 起初不存在
#include <stdio.h>
#include <stdlib.h> //包含 exit
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h> //用 perror 输出错误
#include <unistd.h>
#define FILENAME1 "./aaa.txt" //用宏定义文件的路径
#define FILENAME2 "./bbb.txt"
int main()
{
char buf[512] = {0};
int fo1 = open(FILENAME1, O_RDONLY); //fo1,fo2 都是文件描述词
int fo2 = creat(FILENAME2, 0755); //创建文件
//int fo2 = open(FILENAME2, O_WRONLY | O_CREAT);
if( (-1 == fo1) || (-1 == fo2) )
{
perror("open failed!\n");
//用于输出错误信息.类似于:fputs(”open failed\n”,stderr);
exit(-1);
}
int fr = 0;
while( (fr = read(fo1, buf, sizeof(buf))) > 0 )
//如果 read 读取成功,返回的是长度,否则,返回-1
{
int fw = write(fo2, buf, fr);
if( -1 == fw )
{
perror("write failed!");
exit(-1);
}
}
close(fo1);
close(fo2);
}
改变文件大小
#include <unistd.h>
int ftruncate(int fd, off_t length);
函数 ftruncate 会将参数 fd 指定的文件大小改为参数 length 指定的大小。参数 fd 为已打开的文
件描述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数 length 大,则超过的
部分会被删去。
返回值 执行成功则返回 0,失败返回-1。
#include <func.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
ARGS_CHECK(argc, 2);
int fd;
fd = open(argv[1],O_RDWR);
ERROR_CHECK(fd, -1, "open");
printf("fd=%d\n",fd);
int ret = ftruncate(fd,50);
ERROR_CHECK(ret,-1,"ftruncate");
close(fd);
return 0;
}
int main()
{
int fd = open("a.txt", O_WRONLY);
ftruncate(fd, 1000);
close(fd);
return 0;
}
文件定位
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
函数 lseek 将文件指针设定到相对于 whence,偏移值为 offset 的位置
whence 可以是下面三个常量的一个
SEEK_SET 从文件头开始计算
SEEK_CUR 从当前指针开始计算
SEEK_END 从文件尾开始计算
利用该函数可以实现文件空洞(对一个新建的空文件,可以定位到偏移文件开头 1024 个字节的地
方,在写入一个字符,则相当于给该文件分配了 1025 个字节的空间,形成文件空洞)通常用于多
进程间通信的时候的共享内存。
int main()
{
int fd = open("c.txt", O_WRONLY | O_CREAT);
lseek(fd, 1024, SEEK_SET);
write(fd, "a", 1);
close(fd);
return 0;
}
获取文件信息
可以通过 fstat 和 stat 函数获取文件信息,调用完毕后,文件信息被填充到结构体 struct stat变量中,函数原型为:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *file_name, struct stat *buf); //文件名 stat 结构体指针
int fstat(int fd, struct stat *buf); //文件描述符 stat 结构体指针
结构体 stat 的定义为:
struct stat {
dev_t st_dev; /*如果是设备,返回设备表述符,否则为 0*/
ino_t st_ino; /* i 节点号 */
mode_t st_mode; /* 文件类型 */ 无符号短整型
nlink_t st_nlink; /* 链接数 */
uid_t st_uid; /* 属主 ID */
gid_t st_gid; /* 组 ID */
dev_t st_rdev; /* 设备类型*/
off_t st_size; /* 文件大小,字节表示 */
blksize_t st_blksize; /* 块大小*/
blkcnt_t st_blocks; /* 块数 */
time_t st_atime; /* 最后访问时间*/
time_t st_mtime; /* 最后修改时间*/
time_t st_ctime; /* 最后权限修改时间 */
};
对于结构体的成员 st_mode,有一组宏可以进行文件类型的判断:
S_ISLNK(mode) 判断是否是符号链接
S_ISREG(mode) 判断是否是普通文件
S_ISDIR(mode) 判断是否是目录
S_ISCHR(mode) 判断是否是字符型设备
S_ISBLK(mode) 判断是否是块设备
S_ISFIFO(mode) 判断是否是命名管道
S_ISSOCK(mode) 判断是否是套接字
#include<sys/stat.h>
#include<unistd.h>
int main()
{
struct stat buf;
stat (“/etc/passwd”,&buf);
printf(“/etc/passwd file size = %d \n”,buf.st_size);//st_size 可以得到文件大小
return 0;
}
//如果用 fstat 函数实现,如下:
int fd = open (“/etc/passwd”,O_RDONLY); //先获得文件描述符
fstat(fd, &buf);
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
int main()
{
int fd = open("/home/wangxiao/0926/a.txt", O_RDONLY);
if(fd == -1)
{
perror("open error");
exit(-1);
}
struct stat buf;
int iRet = fstat(fd, &buf);
if(iRet == -1)
{
perror("fstat error");
exit(-1);
}
if(S_ISREG(buf.st_mode))
{
printf("regular file!\n");
}
if(S_ISDIR(buf.st_mode))
{
printf("directory!\n");
}
if(S_ISLNK(buf.st_mode))
{
printf("link file!\n");
}
printf("the size of file is : %d\n", buf.st_size);
time_t tt = buf.st_atime;
struct tm *pT = gmtime(&tt);
printf("%4d-%02d-%02d %02d:%02d:%02d\n", (1900+pT->tm_year), (1+pT->tm_mon),
pT->tm_mday, (8+pT->tm_hour), pT->tm_min, pT->tm_sec);
printf("the last access time is : %d\n", buf.st_atime);
close(fd);
return 0;
}