1.文件描述符复制函数--dup/dup2/fcntl
#include <unistd.h>
int dup(int fd); /*复制一个现有文件的描述符*/
int dup2(int fd, int fd2); /*把一个文件的旧描述符复制到一个新描述符上*/
函数执行后,返回的新文件描述符与原有的旧文件描述符共用同一个文件表项,但是文件描述符标志将被清除,进程调用exec时文件描述符将不会被关闭。
dup()返回的新文件描述符一定是当前可用文件描述符中的最小值。
dup2()可以用fd2指定新描述符的值。如果fd2已经打开,则先将其关闭。若fd==fd2, 则dup2返回fd2,而不关闭它。
代码样例:
Demo1: 重定向进程的stdin、stdout以及stderr到filename文件
int fd = open(filename, O_WRONLY, 0666);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
dup2(fd, STDERR_FILENO);
Demo2:
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main(){
int fd_old = open("test.txt", O_RDWR | O_CREAT, 0666);
int fd_new = dup(fd_old);
int fd_new_2 = dup2(fd_old, 6);
if((fd_new == -1) || (fd_new_2 == -1)){
perror("dup or dup2 failed");
return -1;
}
printf("fd_old : %d, fd_new : %d \n, fd_new_2 : %d \n", fd_old, fd_new, fd_new_2);
close(fd_old);
char *str = "hello world!";
int ret = write(fd_new, str, strlen(str));
if(ret == -1){
perror("write failed");
return -2;
}
close(fd_new);
return 0;
}
运行结果:
fd_old : 3, fd_new : 4, fd_new_2 : 6
fcntl函数:根据传来的cmd参数来修改已经打开文件的属性
dup(fd)等效于fcntl(fd, F_DUPFD, 0),dup2(fd, fd2)等效于“close(fd2); fcntl(fd, F_DUPFD, fd2)"
#include <fcntl.h>
int fcntl(int fd, int cmd, ... );
--fd表示需要操作的文件描述符,cmd表示对文件描述符进行如何操作
--常用的cmd:
(1) 复制一个已有的描述符(cmd = F_DUPFD/F_DUPFD_CLOEXEC)
(2) 获取/设置文件描述符标志(cmd = F_GETFD/SETFD)
(3) 获取/设置文件状态标志(cmd = F_GETFL/F_SETFL)
(4) 获取/设置异步I/O所有权(cmd = F_GETOWN/F_SETOWN)
(5) 获取/设置记录锁(cmd = F_GETLK/F_SETLK/F_SETLKW)
代码样例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int flags;
int append_flag;
int nonblock_flag;
int access_mode;
int fd; /* File Descriptor */
char *text1 = "abcdefghij";
char *text2 = "0123456789";
char read_buffer[25];
memset(read_buffer, '\0', 25);
/* create a new file */
fd = creat("test.txt",S_IRWXU);
write(fd, text1, 10);
close(fd);
/* open the file with read/write access */
fd = open("test.txt", O_RDWR);
read(fd, read_buffer, 24);
printf("first read is \'%s\'\n",read_buffer);
/* reset file pointer to the beginning of the file */
lseek(fd, 0, SEEK_SET);
/* set append flag to prevent overwriting existing text */
fcntl(fd, F_SETFL, O_APPEND);
write(fd, text2, 10);
lseek(fd, 0, SEEK_SET);
read(fd, read_buffer, 24);
printf("second read is \'%s\'\n",read_buffer);
close(fd);
unlink("test.txt");
return 0;
}
运行结果:
first read is 'abcdefghij'
second read is 'abcdefghij0123456789'
2.获得文件信息的函数 stat/fstat/lstat
#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int fd, struct stat *buf);
buf是一个指向stat结构体的指针:
struct stat {
dev_t st_dev; /* ID of device containing file */
dev_t st_rdev; /* Device ID (if special file) */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
};
stat结构体中的 st_mode:
stat函数和lstat函数的区别:假设有一个文件快捷方式(windows系统),lstat只分析快捷方式的信息,而stat分析的是快捷方式对应的原文件的信息。linux系统中的”快捷方式“被称为软链接。
代码样例:
#include <sys/stat.h>
#include <unistd.h>
main()
{
struct stat buf;
stat("/etc/yum", &buf);
printf("/etc/yum file_size = %d \n", buf.st_size);
printf("/etc/yum file_mode = %s \n", buf.st_mode);
printf("/etc/yum Device_ID = %d \n", buf.st_dev);
}
运行结果:
/etc/yum file_size = 4096
/etc/yum file_mode = 16877
/etc/yum Device_ID = 64769
Linux中的stat命令:
用法:
stat [OPTION]... FILE...
常见参数:
-L, --dereference
-f, --file-system display file system status instead of file status
-c --format=FORMAT use the specified FORMAT instead of the default;
output a newline after each use of FORMAT
--printf=FORMAT like --format, but interpret backslash escapes,
and do not output a mandatory trailing newline;
if you want a newline, include \n in FORMAT
-t, --terse print the information in terse form
命令执行样例:
3.权限屏蔽字函数umask
在Linux操作系统创建的文件总是有对应的默认权限,这个权限可以由umask进行设置,umask与chmod的效果刚好相反,umask设置的是权限位的“补码”。有了umask对默认权限的设置,当创建一个文件后,新文件的默认权限就是最大权限减去 umask 指定的权限。
文件权限在Linux中的表示:
[root@VM-4-13-centos cpp_learning]# ls -l hello.txt
-rw-r--r-- 1 root root 12 Apr 13 00:07 hello.txt
umask函数一般用来为进程设置文件模式创建屏蔽字,并返回之前的值。
当编写创建新文件的程序时,如果我们想确保指定的访问权限位已经激活,那么必须在进程运行时修改umask值。
例如,如果我们想确保任何用户都能读文件,应该把umask设置为0。
#include <sys/stat.h>
mode_t umask(mode_t, cmask);
用户可以设置cmask值以控制他们所创建文件的默认权限。
cmask常见取值:
S_IRUSR 当前用户可读
S_IWUSR 当前用户可写
S_IXUSR 当前用户可执行
S_IRGRP 用户组可读
S_IWGRP 用户组可写
S_IXGRP 用户组可执行
S_IROTH 其他用户可读
S_IWOTH 其他用户可写
S_IXOTH 其他用户可执行
代码样例:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
main() {
int fd;
mode_t oldmask;
printf("Your old umask is %i\n",oldmask=umask(S_IRWXG));
if ((fd = creat("test.txt", S_IRWXU|S_IRWXG)) < 0)
perror("creat() error");
else {
system("ls -l test.txt");
close(fd);
unlink("test.txt");
}
umask(oldmask);
}
运行结果:
Your old umask is 36
-rwx------ 1 root root 0 Apr 13 10:24 test.txt
Linux umask指令
umask [-p] [-S] [mode]
命令执行样例:
~~The End~~