文件I/O部分断断续续写了三天,最后总结发现还有好多内容是略过没讲的,我的内心是崩溃的。UNIX环境高级编程这本书,虽然我只看了四章我就发现了书里面的内容讲的太跳,如果是刚接触UNIX或者没有一点C语言基础的会很难上手。这就造成了,前面讲的会漏掉很多内容。
详细内容可 man fstat 查看
#include
#include
#include
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
其中时间函数部分,参看:C语言再学习 -- 时间函数
#include
#include
#include
#include
#include
#include
#include
int main (void)
{
struct stat st = {};
int res = stat ("a.txt", &st);
if (-1 == res)
perror ("Fail to stat"), exit (1);
printf ("st_mode = %o, st_size = %ld, st_mtime = %ld\n",
st.st_mode, st.st_size, st.st_mtime);
printf ("文件的权限是:%o\n", st.st_mode&0777);
printf ("文件的大小是:%ld\n", st.st_size);
if (S_ISREG (st.st_mode))
printf ("是普通文件\n");
if (S_ISDIR (st.st_mode))
printf ("是目录文件\n");
printf ("最后一次修改时间是:%s\n", ctime (&st.st_mtime));
struct tm* pt = localtime (&st.st_mtime);
printf("最后一次修改时间是:%d-%d-%d %02d:%02d:%02d\n",pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,pt->tm_hour,pt->tm_min,pt->tm_sec);
return 0;
}
输出结果:
st_mode = 100644, st_size = 0, st_mtime = 1490857501
文件的权限是:644
文件的大小是:0
是普通文件
最后一次修改时间是:Thu Mar 30 15:05:01 2017
最后一次修改时间是:2017-3-30 15:05:01
# stat c_test/
文件:"c_test/"
大小:4096 块:8 IO 块:4096 目录
设备:801h/2049d Inode:2102110 硬链接:2
权限:(0775/drwxrwxr-x) Uid:( 1000/ tarena) Gid:( 1000/ tarena)
最近访问:2017-03-30 15:05:03.502154419 +0800
最近更改:2017-03-30 15:05:01.858151879 +0800
最近改动:2017-03-30 15:05:01.858151879 +0800
创建时间:-
# stat a.txt
文件:"a.txt"
大小:0 块:0 IO 块:4096 普通空文件
设备:801h/2049d Inode:2121684 硬链接:1
权限:(0644/-rw-r--r--) Uid:( 0/ root) Gid:( 0/ root)
最近访问:2017-03-30 15:05:01.858151879 +0800
最近更改:2017-03-30 15:05:01.858151879 +0800
最近改动:2017-03-30 15:05:01.858151879 +0800
创建时间:-
S_ISREG(m) is it a regular file (普通文件)
S_ISDIR(m) directory (目录文件)
S_ISCHR(m) character device (字符特殊文件)
S_ISBLK(m) block device (块特殊文件)
S_ISFIFO(m) FIFO (named pipe) (管道或 FIFO)
S_ISLNK(m) symbolic link (符号链接)(Not in POSIX.1-1996.)
S_ISSOCK(m) socket (套接字)(Not in POSIX.1-1996.)
我们讲权限的时候,也讲过使用 ls -l 命令 也可以查看文件的类型的:
# ls -l
总用量 40
drwxr-xr-x 2 root root 4096 Mar 30 16:42 test
-rw-r--r-- 1 root root 872 Mar 30 15:04 test.c
其中第一个字符含义:#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
struct stat sb;
if (argc != 2) {
fprintf(stderr, "Usage: %s \n", argv[0]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
printf("I-node number: %ld\n", (long) sb.st_ino);
printf("Mode: %lo (octal)\n",
(unsigned long) sb.st_mode);
printf("Link count: %ld\n", (long) sb.st_nlink);
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
printf("Preferred I/O block size: %ld bytes\n",
(long) sb.st_blksize);
printf("File size: %lld bytes\n",
(long long) sb.st_size);
printf("Blocks allocated: %lld\n",
(long long) sb.st_blocks);
printf("Last status change: %s", ctime(&sb.st_ctime));
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime));
exit(EXIT_SUCCESS);
}
输出结果:
# ./a.out test.c
File type: regular file
I-node number: 2121694
Mode: 100644 (octal)
Link count: 1
Ownership: UID=0 GID=0
Preferred I/O block size: 4096 bytes
File size: 1642 bytes
Blocks allocated: 8
Last status change: Fri Mar 31 09:15:48 2017
Last file access: Fri Mar 31 09:15:53 2017
Last file modification: Fri Mar 31 09:15:48 2017
# ls -l /dev/tty
crw-rw-rw- 1 root tty 5, 0 Mar 29 16:00 /dev/tty
# stat /dev/tty
文件:"/dev/tty"
大小:0 块:0 IO 块:4096 字符特殊文件
设备:5h/5d Inode:4961 硬链接:1 设备类型:5,0
权限:(0666/crw-rw-rw-) Uid:( 0/ root) Gid:( 5/ tty)
最近访问:2017-03-30 16:35:58.445938548 +0800
最近更改:2017-03-29 16:00:37.867616181 +0800
最近改动:2017-03-29 16:00:37.867616181 +0800
创建时间:-
The following flags are defined for the st_mode field:
S_IFMT 0170000 bit mask for the file type bit fields
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-group-ID 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 permission
S_IXOTH 00001 others have execute permission
chmod 命令用于修改这 9 个权限位。该命令允许我们用 u 表示用户(所有者),用 g 表示组,用 o 表示其他。
#include
int access(const char *pathname, int mode);
/* Values for the second argument to access.
These may be OR'd together. */
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define X_OK 1 /* Test for execute permission. */
#define F_OK 0 /* Test for existence. */
#include
#include
int main (void)
{
if (0 == access ("a.txt", F_OK))
printf ("文件存在\n");
if (0 == access ("a.txt", 4))
printf ("文件可读\n");
if (0 == access ("a.txt", W_OK))
printf ("文件可写\n");
if (0 == access ("a.txt", 1))
printf ("文件可执行\n");
return 0;
}
输出结果:
文件存在
文件可读
文件可写
#include
#include
mode_t umask(mode_t mask);
//创建文件 hh 查看权限:
# ls -l hh
-rw-r--r-- 1 root root 0 Mar 31 10:34 hh
查看:
# umask
0022
#include
#include
#include
#include
#include
#include
int main (void)
{
//使用umask函数设置屏蔽的权限
mode_t old = umask (0055);
//设置新的屏蔽字,返回旧的系统默认
// 当前系统默认屏蔽 0055
printf ("old = %o\n", old);
int fd = open ("a.txt", O_RDWR | O_CREAT, 0777);
if (-1 == fd)
perror ("fail to open"),exit (1);
//恢复系统默认的屏蔽字
//对已经创建过的文件权限没有影响
umask (old);
close (fd);
return 0;
}
输出结果:
old = 22
查看 a.txt 权限,说明实际权限为 0722 (0777&~0055)屏蔽了0055
# ls -la a.txt
-rwx-w--w- 1 root root 0 Mar 31 10:25 a.txt
示例说明:
-p:输出的权限掩码可直接作为指令来执行;
-S:以符号方式输出权限掩码。
设置新屏蔽权限:
# umask -p 0055
# umask -S 0055
u=rwx,g=w,o=w
查看:
# umask
0055
#include
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
The new file permissions are specified in mode, which is a bit mask created by ORing together zero or more of the following:
S_ISUID (04000) set-user-ID (set process effective user ID on execve(2))
S_ISGID (02000) set-group-ID (set process effective group ID on execve(2); mandatory locking, as described in fcntl(2); take a new
file's group from parent directory, as described in chown(2) and mkdir(2))
S_ISVTX (01000) sticky bit (restricted deletion flag, as described in unlink(2))
S_IRUSR (00400) read by owner
S_IWUSR (00200) write by owner
S_IXUSR (00100) execute/search by owner ("search" applies for directories, and means that entries within the directory can be
accessed)
S_IRGRP (00040) read by group
S_IWGRP (00020) write by group
S_IXGRP (00010) execute/search by group
S_IROTH (00004) read by others
S_IWOTH (00002) write by others
S_IXOTH (00001) execute/search by others
//示例一 chmod
#include
#include
#include
#include
#include
#include
int main (void)
{
struct stat st;
int res = stat ("a.txt", &st);
if (-1 == res)
perror ("fail to stat"), exit (1);
printf ("权限是:%o\n", st.st_mode&0777);
res = chmod ("a.txt", 0600);
if (-1 == res)
perror ("fail to chmod"), exit (1);
res = stat ("a.txt", &st);
if (-1 == res)
perror ("fail to stat"), exit (1);
printf ("权限是:%o\n", st.st_mode&0777);
return 0;
}
输出结果:
权限是:644
权限是:600
//示例二 fchmod
#include
#include
#include
#include
#include
#include
int main (void)
{
int fd = open ("a.txt", O_RDONLY | O_CREAT, 0644);
struct stat st;
int res = stat ("a.txt", &st);
if (-1 == res)
perror ("fail to stat"), exit (1);
printf ("权限是:%o\n", st.st_mode&0777);
res = fchmod (fd, 0600);
if (-1 == res)
perror ("fail to chmod"), exit (1);
res = stat ("a.txt", &st);
if (-1 == res)
perror ("fail to stat"), exit (1);
printf ("权限是:%o\n", st.st_mode&0777);
return 0;
}
输出结果:
权限是:644
权限是:600
chmod 644 a.txt
查看:
# ls -l a.txt
-rw-r--r-- 1 tarena root 0 Mar 31 16:16 a.txt
#include
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
//示例一 chown
#include
#include
int main (void)
{
//chown ("a.txt", 0, -1);
chown ("a.txt", 0, 0);
return 0;
}
修改前:
# ls -l a.txt
总用量 20
-rw------- 1 tarena tarena 0 Mar 31 14:24 a.txt
chown ("a.txt", 0, 0); 修改后:
# ls -l a.txt
总用量 20
-rw------- 1 root root 0 Mar 31 14:24 a.txt
chown ("a.txt", 0, -1); 修改后:
# ls -l a.txt
总用量 20
-rw------- 1 root tarena 0 Mar 31 14:24 a.txt
//示例二 fchown
#include
#include
#include
#include
#include
#include
int main (void)
{
int fd = open ("a.txt", O_RDONLY | O_CREAT, 0644);
if (-1 == fd)
perror ("fail to open"), exit (1);
fchown (fd , 1000, 1000);
return 0;
}
修改前:
# ls -la
总用量 12
-rw-r--r-- 1 root root 0 Mar 31 15:34 a.txt
修改后:
# ls -la
总用量 20
-rw-r--r-- 1 tarena tarena 0 Mar 31 15:34 a.txt
//示例三 lchown
#include
#include
#include
int main (void)
{
int res = lchown ("/dev/cdrom1", 1000, 1000);
if (-1 == res)
perror ("fail to lchown"), exit (1);
return 0;
}
修改前:
# ls -l cdrom1 sr0
lrwxrwxrwx 1 root root 3 Mar 29 16:00 cdrom1 -> sr0
brw-rw---- 1 root cdrom 11, 0 Mar 29 16:00 sr0
修改后:
# ls -l cdrom1 sr0
lrwxrwxrwx 1 tarena tarena 3 Mar 29 16:00 cdrom1 -> sr0
brw-rw---- 1 root cdrom 11, 0 Mar 29 16:00 sr0
# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
tarena:x:1000:1000:tarena,,,:/home/tarena:/bin/bash
示例二:fchown,打开时文件描述符。
# stat /dev/cdrom1
文件:"/dev/cdrom1" -> "sr0"
大小:3 块:0 IO 块:4096 符号链接
设备:5h/5d Inode:7459 硬链接:1
权限:(0777/lrwxrwxrwx) Uid:( 0/ root) Gid:( 0/ root)
最近访问:2017-03-31 15:59:53.712010169 +0800
最近更改:2017-03-29 16:00:36.411616237 +0800
最近改动:2017-03-31 15:59:47.936011311 +0800
创建时间:-
sudo chgrp -R zslf test
查看:
root@zslf-:/mnt# ls -la test/
总用量 8
drwxr-xr-x 2 root zslf 4096 11月 24 17:20 .
drwxr-xr-x 5 root root 4096 11月 24 17:20 ..
sudo chown -R zslf.zslf test
查看:
root@zslf-virtual-machine:/mnt# ls -la test/
总用量 8
drwxr-xr-x 2 zslf root 4096 11月 24 17:20 .
drwxr-xr-x 5 root root 4096 11月 24 17:20 ..
sudo chown -R zslf.zslf test
查看:
root@zslf-virtual-machine:/mnt# ls -la test/
总用量 8
drwxr-xr-x 2 zslf zslf 4096 11月 24 17:33 .
drwxr-xr-x 5 root root 4096 11月 24 17:20 ..
-rw-r--r-- 1 zslf zslf 0 11月 24 17:33 hh
# ls -la
总用量 20
drwxrwxr-x 2 tarena tarena 4096 Mar 31 16:16 .
drwxrwxr-x 4 tarena tarena 4096 Mar 28 15:38 ..
-rwxr-xr-x 1 root root 7233 Mar 31 16:16 a.out
-rw-r--r-- 1 tarena root 0 Mar 31 16:16 a.txt
-rw-r--r-- 1 root root 184 Mar 31 16:15 test.c
# ls -l /dev/cdrom1
lrwxrwxrwx 1 root root 3 Apr 5 09:19 /dev/cdrom1 -> sr0
# ls -l a.out
-rwxr-xr-x 1 root root 7233 Mar 31 16:16 a.out
# du -h a.out
8.0K a.out
文件 a.out 长度为 7.2K,可 du 命令报告该文件所使用的磁盘空间总量为 8.0K。很明显,此文件中有很多空洞.
#include
#include
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
#include
//示例一 truncate 函数
#include
#include
int main (void)
{
int res = truncate ("a.txt", 50);
if (-1 == res)
perror ("fail to truncate"), exit (1);
return 0;
}
a.txt 为空时:
执行前:
-rw-r--r-- 1 tarena root 0 Mar 31 16:16 a.txt
执行后:
-rw-r--r-- 1 tarena root 50 Apr 5 13:14 a.txt
长度截断为50,后面的数据填充为 0。
a.txt 不为空时:
执行前:
-rw-r--r-- 1 tarena root 296 Apr 5 13:17 a.txt
执行后:
-rw-r--r-- 1 tarena root 50 Apr 5 13:14 a.txt
长度截断为50, 后面的数据不再能访问。
//示例二 ftruncate 函数
#include
#include
#include
#include
#include
#include
int main (void)
{
int fd = open ("a.txt", O_RDWR);
if (-1 == fd)
perror ("fail to open"), exit (1);
int res = ftruncate (fd, 50);
if (-1 == res)
perror ("fail to truncate"), exit (1);
return 0;
}
a.txt 为空时:
执行前:
-rw-r--r-- 1 tarena root 0 Mar 31 16:16 a.txt
执行后:
-rw-r--r-- 1 tarena root 50 Apr 5 13:14 a.txt
长度截断为50,后面的数据填充为 0。
a.txt 不为空时:
执行前:
-rw-r--r-- 1 tarena root 296 Apr 5 13:17 a.txt
执行后:
-rw-r--r-- 1 tarena root 50 Apr 5 13:14 a.txt
长度截断为50, 后面的数据不再能访问。
#include
int rename(const char *oldname, const char *newname);
int renameat(int oldfd,const char *oldname, int newfd, const char *newname);
#include
#include
int main (void)
{
rename ("a.txt", "b.txt");
return 0;
}
--backup=<备份模式>:若需覆盖文件,则覆盖前先行备份;
-b:当文件存在时,覆盖前,为其创建一个备份;
-f:若目标文件或目录与现有的文件或目录重复,则直接覆盖现有的文件或目录;
-i:交互式操作,覆盖前先行询问用户,如果源文件与目标文件或目标目录中的文件同名,则询问用户是否覆盖目标文件。用户输入”y”,表示将覆盖目标文件;输入”n”,表示取消对源文件的移动。这样可以避免误将文件覆盖。
--strip-trailing-slashes:删除源文件中的斜杠“/”;
-S<后缀>:为备份文件指定后缀,而不使用默认的后缀;
--target-directory=<目录>:指定源文件要移动到目标目录;
-u:当源文件比目标文件新或者目标文件不存在时,才执行移动操作。
将文件ex3改名为new1
mv ex3 new1
#include
int mkdir (const char *pathname, mode_t mode);
int mkdirat(int dirfd, const char *pathname, mode_t mode);
S_IRWXU 00700权限,代表该文件所有者拥有读,写和执行操作的权限
S_IRUSR(S_IREAD) 00400权限,代表该文件所有者拥有可读的权限
S_IWUSR(S_IWRITE) 00200权限,代表该文件所有者拥有可写的权限
S_IXUSR(S_IEXEC) 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权限,代表其他用户拥有执行的权限
#include
#include
int main (void)
{
mkdir ("test", 0755);
return 0;
}
-Z:设置安全上下文,当使用SELinux时有效;
-m <目标属性>或--mode<目标属性>建立目录的同时设置目录的权限;
-p或--parents 若所要建立目录的上层目录目前尚未建立,则会一并建立上层目录;
--version 显示版本信息。
在目录/usr/meng下建立子目录test,并且只有文件主有读、写和执行权限,其他人无权访问
mkdir -m 700 /usr/meng/test
在当前目录中建立bin和bin下的os_1目录,权限设置为文件主可读、写、执行,同组用户可读和执行,其他用户无权访问
mkdir -p-m 750 bin/os_1
#include
int rmdir( const char *pathname );
返回值:若成功则返回0,若出错则返回-1
#include
#include
int main (void)
{
rmdir ("test");
return 0;
}
-p或--parents:删除指定目录后,若该目录的上层目录已变成空目录,则将其一并删除;
--ignore-fail-on-non-empty:此选项使rmdir命令忽略由于删除非空目录时导致的错误信息;
-v或-verboes:显示命令的详细执行过程;
--help:显示命令的帮助信息;
--version:显示命令的版本信息。
删除子目录os_1和其父目录bin
rmdir -p bin/os_1
-d:直接把欲删除的目录的硬连接数据删除成0,删除该目录;
-f:强制删除文件或目录;
-i:删除已有文件或目录之前先询问用户;
-r或-R:递归处理,将指定目录下的所有文件与子目录一并处理;
--preserve-root:不对根目录进行递归操作;
-v:显示指令的详细执行过程。
删除 test 目录下除隐含文件外的所有文件和子目录
# rm -r test
#include
#include
DIR *opendir(const char *name);
#include
struct dirent *readdir(DIR *dirp);
struct dirent {
ino_t d_ino; /* inode number */ //i节点的编号
off_t d_off; /* offset to the next dirent */ //距离下一个子项的偏移量
unsigned short d_reclen; /* length of this record */ //记录的长度
unsigned char d_type; /* type of file; not supported //文件的类型
by all file system types */
char d_name[256]; /* filename */ //文件名
};
#include
#include
int closedir(DIR *dirp);
#include
#include
#include
#include
int main (void)
{
DIR *dir = opendir ("code");
if (NULL == dir)
perror ("fail to opendir"), exit (1);
struct dirent *ent;
while (ent = readdir (dir))
printf ("文件名为:%s\n", ent->d_name);
closedir (dir);
return 0;
}
输出结果:
文件名为:test
文件名为:.
文件名为:..
#include
int chdir(const char *path);
int fchdir(int fd);
//示例一 chdir
#include
#include
#include
int main (void)
{
if (-1 == chdir ("/tmp"))
perror ("fail to chdir"), exit (1);
return 0;
}
//示例二 fchdir
#include
#include
#include
#include
#include
#include
int main (void)
{
int fd = open ("/tmp", O_RDONLY);
if (-1 == fchdir (fd))
perror ("fail to fchdir"), exit (1);
char buf[100];
if (getcwd(buf, 100) == NULL)
perror ("fail to getcwd"), exit (1);
printf("cwd = %s\n", buf);
return 0;
}
输出结果:
cwd = /tmp
#include
char *getcwd(char *buf, size_t size);
#include
#include
#include
int main (void)
{
if (chdir("/usr/bin/") < 0)
perror ("chdir failed"), exit (1);
char buf[100];
if (getcwd(buf, 100) == NULL)
perror ("fail to getcwd"), exit (1);
printf("cwd = %s\n", buf);
return0;
}
输出结果:
cwd = /usr/bin