NAME
getcwd, getwd, get_current_dir_name - get current working directory
SYNOPSIS
#include <unistd.h>
把获取到的工作路径(绝对路径)保存到buf指向的内存空间(必须可用)
char* getwd(char *buf);
buf:是用来保存获取到的工作路径的
返回值:
成功返回获取到的工作路径字符串的首地址(buf)
失败返回NULL,同时errno被设置
警告: the `getwd' function is dangerous and should not be used.
getwd有一个bug,不应该被使用,可能会造成内存越界
如果buf指向的空间不够大(当前目录字符串长度超出了buf指向的空间)
getwd就会访问buf后面的空间(造成数据会误修改)
---------------------------------------------------------------------------
getcwd是getwd的升级版本
char* getcwd(char *buf, size_t size);
buf:是用来保存获取到的工作路径的
size:指定了buf可用空间的大小,如果当前的目录长度字符串超过了size-1,这个函数就会报错
返回值:
成功返回获取到的工作路径字符串的首地址(buf)
失败返回NULL,同时errno被设置
---------------------------------------------------------------------------
get_current_dir_name也是获取当前的工作路径,只不过这个函数不需要你给定空间,
会在函数内部malloc自动分配足够长的空间,保存获取到的工作路径,并且返回首地址
所以为了防止内存泄漏,使用者使用完毕之后,应该free这个空间
char* get_current_dir_name(void);
返回值:
成功返回获取到的工作路径字符串的首地址
失败返回NULL,同时errno被设置
修改: 改变进程当前的工作路径
cpp复制代码
NAME
chdir, fchdir - change working directory
SYNOPSIS
#include <unistd.h>
int chdir(const char *path);
path:要切换到的工作路径的目录字符串
chdir("/home/china/");
-----------------------------------------------------
int fchdir(int fd);
fd:要切换到的工作目录的文件描述符
如:
int fd = open("/home/china/", O_RDONLY) ;
fchdir(fd);
返回值:
成功会改变当前的工作路径,返回0
失败返回-1,同时errno被设置
✔7. 文件截短 (truncate)
cpp复制代码
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);
文件必须可写
path:你要截短的文件的路径名(相对路径/绝对路径)
绝对路径------>工作路径+path
length:截短之后的文件长度
length < 原来的长度
"截短":文件变成指定的长度,文件的大小改变
length > 原来的长度
"留空洞",空洞的内容是无知的
返回值:
成功返回0
失败返回-1,同时errno被设置
int ftruncate(int fd, off_t length);
=====>
int fd = open(...); // 文件必须以可写的方式打开
ftruncate(fd, length);
✔8. 删除文件
cpp复制代码
rm 删除文件
rmdir 删除空目录
unlink // 删除一个普通文件
rmdir // 删除一个空目录
remove // 删除一个普通文件或者一个空目录
NAME
unlink, unlinkat - delete a name and possibly the file it refers to
SYNOPSIS
#include <unistd.h>
int unlink(const char *pathname);
// 删除一个文件的时候仅仅只是标记inode没有被使用了
pathname:要删除的那个文件的文件名(带路径)
返回值:
成功删除返回0
失败返回-1,同时errno被设置
我们知道Linux中文件是用inode节点来区分文件的,当我们删除一个文件的时候并不一定
系统就会释放inode节点的内容。当满足下面的要求的时候系统才会释放inode节点的内容
(1) inode中记录指向该节点的硬链接数为0
(2) 没有进程打开指向该节点的文件
执行unlink()函数并不一定会真正的删除文件,如果要删除的文件是硬链接文件,它先会检查
文件系统中此文件的硬链接数是否为1,如果不是1说明此文件还有其他硬链接对象,删除一个
文件的时候仅仅只是标记inode没有被使用了,只对此文件的硬链接数进行减1操作。若硬链接
数为1,并且在此时没有任何进程打开该文件,此内容才会真正地被删除掉。在有进程打开
此文件的情况下,则暂时不会删除,直到所有打开该文件的进程都结束时文件就会被删除
如果要删除的文件是符号链接(软链接)文件,则此链接会被删除
--------------------------------------------------------------------------------------
NAME
rmdir - delete a directory
SYNOPSIS
#include <unistd.h>
int rmdir(const char *pathname);
目录必须是空的
pathname:要删除的目录的路径名
返回值:
成功删除返回0
失败返回-1,同时errno被设置
------------------------------------
NAME
remove - remove a file or directory
SYNOPSIS
#include <stdio.h>
int remove(const char *pathname);
删除一个普通文件或者一个空目录
remove 删除一个普通文件 ------>unlink
remove 删除一个空目录 ------>rmdir
9. 获取文件的属性 (stat)
任何一个文件都有自己的属性 (inode中的内容)
man -a inode
cpp复制代码
NAME
stat, fstat, lstat, fstatat - get file status
获取文件属性
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
stat是用来获取pathname指定的文件的属性信息,获取到的属性信息保存到statbuf指针指向
的内存中(statbuf必须指向一个可用的空间)
stat这个函数获取文件的属性信息,只需要提供文件名不需要打开它
int stat(const char *pathname, struct stat *statbuf);
pathname:你要获取哪一个文件的属性(路径名)
statbuf:结构体指针,指向一块可用的空间,用来保存获取到的文件的属性信息
返回值:
成功返回0,失败返回-1,同时errno被设置
struct stat *statbuf = NULL;
int r = stat("1.txt", statbuf); // ERROR 指针必须指向一块可用的空间
==============>
struct stat statbuf;
// struct stat *p = malloc(sizeof(*p));
int r = stat("1.txt", &statbuf);
---------------------------------------------------------------------------
fstat功能和stat类似,只不过需要提供文件描述符,需要提前打开文件
int fstat(int fd, struct stat *statbuf);
---------------------------------------------------------------------------
lstat功能和stat类似,只不过当pathname是一个符号链接的时候,
lstat获取的是符号链接本身的属性信息(软连接同样有自己的inode),
而stat是获取符号链接指向的那个文件的属性信息
int lstat(const char *pathname, struct stat *statbuf);
文件B是文件A的符号链接(ln -s A B):给A创建一个软连接B
B----->A
stat(B) 获取的是A的inode的信息
lstat(B) 获取的是B的inode的信息
文件的属性:
实际上Linux系统是使用一个 struct stat 的结构体保存文件的所有属性信息
cpp复制代码
struct stat {
dev_t st_dev; /* ID of device containing file */
// 容纳该文件的设备的设备号码,文件存储在哪一个设备上面
ino_t st_ino; /* Inode number */
// 该文件的inode号码
mode_t st_mode; /* File type and mode */
// 保存了文件的权限和类型,使用位域(bit)实现
nlink_t st_nlink; /* Number of hard links */
// 硬链接数量(有多少个文件名关联这个inode)
uid_t st_uid; /* User ID of owner */
// 文件的所有者ID(文件属于哪个用户)
gid_t st_gid; /* Group ID of owner */
// 文件的组ID(文件属于哪个用户组)
dev_t st_rdev; /* Device ID (if special file) */
// 如果文件是一个特殊的设备,设备号码
off_t st_size; /* Total size, in bytes */
// 文件的大小(字节数量)
// 普通文件:文件内容的大小
// 对应符号链接(软链接)的文件内容是什么呢?
// 指向的那个文件的文件名字
// 目录文件的内存是什么?
// 是目录项,大小为4096
blksize_t st_blksize; /* Block size for filesystem I/O */
块大小(与具体的硬件设备有关)
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
该文件占用多少块(512字节为一块)
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
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 */
// 最后修改时间 (修改了属性信息,inode中的内容)
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
解析权限和类型的方式:
cpp复制代码
mode_t st_mode; /* File type and mode */
// 保存了文件的权限和类型
st_mode使用位域实现,可以使用以下的宏去解析这个变量
如:
// 获取文件的属性
struct stat st;
int r = stat("1.txt", &st);
st.st_mode就保存了1.txt的文件的权限和类型
文件的类型
S_IFMT 0170000 bit mask for the file type bit field
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 管道文件
to test for a regular file (for example)
if ((st.st_mode & S_IFMT) == S_IFREG) {
// 当前文件是一个普通文件
}
或者:
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;
}
或者:
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)? 管道文件
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) 链接文件
S_ISSOCK(m) socket? (Not in POSIX.1-1996.) 套接字文件
stat(pathname, &st);
if (S_ISREG(st.st_mode)) {
// 当前文件是一个普通文件
}
-----------------------------------------------------------------------------
文件的权限信息
printf("Mode: %lo (octal)\n", (unsigned long)st.st_mode);
if (st.st_mode & S_IRUSR) {
// 用户拥有可读的权限
} else {
// 用户,不拥有可读的权限
}
S_IRWXU 00700 user (file owner) has read, write, and execute permission
用户拥有可读可写可执行的权限
S_IRUSR 00400 user has read permission、
S_IWUSR 00200 user has write permission
S_IXUSR 00100 user has execute permission
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others have read, write, and execute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
U/USR 用户(文件的拥有者)
G/GRP 组用户
O/OTH 其他用户
不管你使用的是哪一个函数(stat/fstat/lstat)都是获取到上面结构体的信息
cpp复制代码
注意时间格式转化
struct timespec {
time_t tv_sec; /* seconds */
// 秒,记录的是从1970年1月1日到现在的秒数
long tv_nsec; /* nanoseconds */
// 纳秒
};
1s == 1000 ms
1ms == 1000 us
1us == 1000 ns
既然你给出的是一个秒数,如何把一个秒数转化为时间呢?
#include <time.h>
char* ctime(const time_t *timep); // 把秒数转化为时间字符串
timep:你要转化的秒数
可以把当前的秒数转化为一个表示时间的字符串
如:
printf("%s\n", ctime(&st.st_atim.tv_sec));
or
printf("%s\n", ctime(&st.st_atime));
----------------------------------------------------------------------------
struct tm* localtime(const time_t *timep);
可以把一个当前的秒数转化为一个表示时间的结构体
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */ // 须+1
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
cpp复制代码
如何获取系统时间:
NAME
time - get time in seconds
SYNOPSIS
#include <time.h>
time_t time(time_t *tloc);
=============================
time_t tm = time(NULL);
or
time_t tm;
time(&tm);
--------------------------------------------------------------------------
如何获取更加精准的时间:
NAME
gettimeofday, settimeofday - get / set time
SYNOPSIS
#include <sys/time.h>
// 微秒级别的时间
int gettimeofday(struct timeval *tv, struct timezone *tz);
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
// 纳秒级别的时间
int clock_gettime(clockid_t clk_id, struct timespec *tp);
struct timespec {
time_t tv_sec; /* seconds */
// 秒,记录的是从1970年1月1日到现在的秒数
long tv_nsec; /* nanoseconds */
// 纳秒
};
a.打开目录(opendir)
NAME
opendir, fdopendir - open a directory
SYNOPSIS
#include <sys/types.h>
#include <dirent.h>
DIR* opendir(const char *name);
DIR *dir = opendir("/home/china");
------------------------------------------------------------------
DIR* fdopendir(int fd);
int fd = open("/home/china", O_RDONLY);
DIR *dir = fdopendir(fd);
name/fd:你要打开的目录的路径名/文件描述符
返回值:
成功就会返回一个DIR指针(指向当前目录项的指针)
失败返回NULL,同时errno被设置
在Linux中,使用DIR结构体表示一个打开的目录,至于目录里面有什么,
不需要关心,只需要知道DIR类型的指针表示一个已经打开的目录就可以了,
后序操作这个目录的时候,使用这个指针表示这个目录即可
cpp复制代码
b.读取目录项(readdir)
通过读取目录项,就可以知道目录中有哪些文件了
NAME
readdir - read a directory
SYNOPSIS
#include <dirent.h>
readdir是用来从dirp指向的目录中,读取下一个"目录项"的指针,
一个目录中有多少个"目录项",就有多少个文件
每一次调用readdir,都会给你返回一个指向目录项的指针,
并且让指针指向下一个目录项(偏移量),直到返回NULL,表示读取完毕
struct dirent* readdir(DIR *dirp);
dirp:指向你要读取目录项的目录(是opendir的返回值)
In the glibc implementation, the dirent structure isdefined as follows:
struct dirent {
--->ino_t d_ino; /* Inode number */
// 当前读取到的目录项的inode编号
off_t d_off; /* Not an offset; see below */
// 目录项的偏移
unsigned short d_reclen; /* Length of this record */
// 该结构体的长度
unsigned char d_type; /* Type of file; not supported by all
filesystem types */
// 读取到的目录项指向的文件的类型,不是所有的文件系统都支持
--->char d_name[256]; /* Null-terminated filename */
// 该目录项指向的文件名字(读取到的是相对路径---目录下面的文件名)
};
注意:
该结构体的成员,只有d_ino,和d_name两个成员是所有文件系统都支持的,
如果你想要你的代码有更好的兼容性和可移植性,在代码中尽量只使用这两个成员
返回值:
On success, readdir() returns a pointer to a dirent structure.
(This structure may be statically allocated; do not attempt to free(3) it.)
如果成功,readdir()返回一个指向struct dirent *的结构体指针
(此结构体是静态分配的;不要试图去释放它)
If the end of the directory stream is reached, NULL is returned
and errno is not changed.
If an error occurs, NULL is returned and errno is set appropriately.
成功返回一个指向目录项(struct dirent *)的指针,读完后会返回NULL,errno不会
被设置,失败返回NULL,并且errno被设置
cpp复制代码
c.关闭目录(closedir)
NAME
closedir - close a directory
SYNOPSIS
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
dirp:指向你要关闭的目录的DIR结构体
返回值:
成功返回0
失败返回-1,同时errno被设置
cpp复制代码
创建目录
NAME
mkdir, mkdirat - create a directory
SYNOPSIS
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
相对路径:以工作路径作为参照点
返回值:
成功返回0
失败返回-1,同时errno被设置
如果目录已存在,nkdir会失败,返回-1,同时errno == EEXIST