一 readlink 命令
前面知道,如果a.soft是一个软链接,我们使用 cat a.soft,会直接查看这个软链接指向的文件
那么我们就是想看这个软链接是啥,可以使用 readlink a.soft
二 获取工作目录 getcwd函数
获取进程当前工作目录 (卷3,标库函数)
size 为buf 的大小。
char *getcwd(char *buf, size_t size); 成功:buf中保存当前进程工作目录位置。失败返回NULL。
成功则 将buf中的数据 作为返回值返回;也就是说,在成功的情况下,返回值和buf中的值是一样的。
失败,则返回 NULL,一般当size 不够大,放不下的时候,就会返回null

三 改变当前进程的工作目录
改变当前进程的工作目录
int chdir(const char *path); 成功:0;失败:-1设置errno为相应值
int main() {
char nowpath[128];
getcwd(nowpath,sizeof(nowpath));
cout << "nowpath = " <<nowpath << endl;
int ret = chdir("/home/hunandede/projects/linuxcpp/aaa");// aaa 目录是真实存在的 ret =0
//int ret = chdir("/home/hunandede/projects/linuxcpp/bbb");//bbb目录不存在, ret=-1
//另一个问题是 chdir虽然成功了,但是意义在哪里,这个当前文件肯定是指的 可执行文件的路径了,改变目录也不会将 执行文件 拷贝到 aaa目录
cout << "ret = " << ret << endl;
getcwd(nowpath, sizeof(nowpath));
cout << "nowpath = " << nowpath << endl;
return 0;
}
四。文件,目录权限
注意:目录文件也是“文件”。其文件内容是该目录下所有子文件的目录项dentry。 可以尝试用vim打开一个目录。
文件 和 目录 的 RWX的权限 ,对应的操作也不同
|
r |
w |
x | |
|
文件 |
文件的内容可以被查看 |
内容可以被修改 |
可以运行产生一个进程 |
|
cat、more、less… |
vi、> … |
./文件名 | |
|
目录 |
目录可以被浏览 |
创建、删除、修改文件 |
可以被打开、进入 |
|
ls、tree… |
mv、touch、mkdir… |
cd |
目录设置黏住位:若有w权限,创建不变,删除、修改只能由root、目录所有者、文件所有者操作。
opendir函数
根据传入的目录名打开一个目录 (库函数) DIR * 类似于 FILE *
DIR *opendir(const char *name); 成功返回指向该目录结构体指针,失败返回NULL
参数支持相对路径、绝对路径两种方式:例如:打开当前目录:① getcwd() , opendir() ② opendir(".");
closedir函数
关闭打开的目录
int closedir(DIR *dirp); 成功:0;失败:-1设置errno为相应值
readdir函数
读取目录 (库函数)
struct dirent *readdir(DIR *dirp); 成功返回目录项结构体指针;失败返回NULL设置errno为相应值
需注意返回值,读取数据结束时也返回NULL值,所以应借助errno进一步加以区分。
struct 结构体:
struct dirent {
ino_t d_ino; inode编号
off_t d_off;
unsigned short d_reclen; 文件名有效长度
unsigned char d_type; 类型(vim打开看到的类似@*/等)
char d_name[256];文件名
};
其成员变量重点记忆两个:d_ino、d_name。实际应用中只使用到d_name。
练习1:实现简单的ls功能。 【imp_ls.c】
练习2:实现ls不打印隐藏文件。每5个文件换一个行显示。 【imp_ls2.c】
拓展1:实现ls -a -l 功能。
//1.得到 最前面的那个d, 使用 filetype表示
void getfiletype(__mode_t & smode,char * filetype) {
switch (smode & S_IFMT) {
case S_IFBLK:
//printf("block device\n");
strcpy(filetype,"b\0");
break;
case S_IFCHR:
//printf("character device\n");
strcpy(filetype, "c\0");
//return "c";
break;
case S_IFDIR:
//printf("directory\n");
//return "d";
strcpy(filetype, "d\0");
break;
case S_IFIFO:
//printf("FIFO/pipe\n");
strcpy(filetype, "p\0");
//return "p";
break;
case S_IFLNK:
//printf("symlink\n");
//return "l";
strcpy(filetype, "l\0");
break;
case S_IFREG:
//printf("regular file\n");
//return "-";
strcpy(filetype, "-\0");
break;
case S_IFSOCK:
//printf("socket\n");
//return "s";
strcpy(filetype, "s\0");
break;
default:
printf("unknown\n");
strcpy(filetype, "u\0");
break;
}
}
//2.得到权限 rwxrwxr-x
void getfilepermissions(__mode_t & smode, char * filepermissions) {
//S_IRWXU 00700 owner has read, write, and execute permission
//S_IRUSR 00400 owner has read permission
//S_IWUSR 00200 owner has write permission
//S_IXUSR 00100 owner 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(not in group) 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
if (smode & S_IRUSR)//-----为真,表示可读
{
strcpy(filepermissions, "r\0");
//filepermission = filepermission + "r";
}
else {
//filepermission = filepermission + "-";
strcpy(filepermissions, "-\0");
}
if (smode & S_IWUSR)//-----为真,表示可写
{
strcat(filepermissions,"w\0");
//filepermissions = filepermission + "w";
}
else {
//filepermissions = filepermission + "-";
strcat(filepermissions, "-\0");
}
if (smode & S_IXUSR)//-----为真,表示可执行
{
//filepermission = filepermission + "x";
strcat(filepermissions, "x\0");
}
else {
//filepermission = filepermission + "-";
strcat(filepermissions, "-\0");
}
//Group
//S_IRGRP 00040 group has read permission
//S_IWGRP 00020 group has write permission
//S_IXGRP 00010 group has execute permission
if (smode & S_IRGRP)//-----为真,表示可读
{
//filepermission = filepermission + "r";
strcat(filepermissions, "r\0");
}
else {
//filepermission = filepermission + "-";
strcat(filepermissions, "-\0");
}
if (smode & S_IWGRP)//-----为真,表示可写
{
//filepermission = filepermission + "w";
strcat(filepermissions, "w\0");
}
else {
//filepermission = filepermission + "-";
strcat(filepermissions, "-\0");
}
if (smode & S_IXGRP)//-----为真,表示可执行
{
//filepermission = filepermission + "x";
strcat(filepermissions, "x\0");
}
else {
//filepermission = filepermission + "-";
strcat(filepermissions, "-\0");
}
//other
//S_IROTH 00004 others have read permission
//S_IWOTH 00002 others have write permission
//S_IXOTH 00001 others have execute permission
if (smode & S_IROTH)//-----为真,表示可读
{
//filepermission = filepermission + "r";
strcat(filepermissions, "r\0");
}
else {
//filepermission = filepermission + "-";
strcat(filepermissions, "-\0");
}
if (smode & S_IWOTH)//-----为真,表示可写
{
//filepermission = filepermission + "w";
strcat(filepermissions, "w\0");
}
else {
//filepermission = filepermission + "-";
strcat(filepermissions, "-\0");
}
if (smode & S_IXOTH)//-----为真,表示可执行
{
//filepermission = filepermission + "x";
strcat(filepermissions, "x\0");
}
else {
//filepermission = filepermission + "-";
strcat(filepermissions, "-\0");
}
}
int fileinfo(const char * filepathname,const char *filename, char *allstr) {
int ret = 0;
struct stat sta ;
ret = lstat(filepathname,&sta);
if (ret < 0 ) {
cout << "stat filepathname error " << filepathname << endl;
perror(" stat filename error");
return ret;
}
//这里得到了文件的属性,得到2 个点,1是文件的类型,2是得到文件的权限,就能弄出来这个了 drwxrwxr-x
//drwxrwxr-x 4 hunandede hunandede 4096 2月 21 15:16 .
//1.得到 最前面的那个d, 使用 filetype表示
__mode_t smode = sta.st_mode;
char filetype[2] = { 0 };
getfiletype(smode, filetype);
//2.得到权限 rwxrwxr-x
char filepermissions[10] = { 0 };
getfilepermissions(smode,filepermissions);
//3. 得到user名
__uid_t userid = sta.st_uid; //__uid_t本质上是 unsigned int
//4. 得到组名
__gid_t groupid = sta.st_gid; //__gid_t 本质上是 unsigned int
//5. 得到文件大小
__off_t filesize = sta.st_size; // long int
//6.得到时间
ctime(&(sta.st_atime));
//7.得到文件名,已经设置为第二个参数了
//8 组合
strcpy(allstr,filetype);
strcat(allstr, filepermissions);
strcat(allstr, " ");
char useridchar[64] = { 0 };
sprintf(useridchar, "%u", userid);
strcat(allstr, useridchar);
strcat(allstr, " ");
char groupidchar[64] = { 0 };
sprintf(groupidchar, "%u", groupid);
strcat(allstr, groupidchar);
strcat(allstr, " ");
//文件大小
filesize = filesize / 8; //filesize 的本质是 long int
char filesizestr[256] = { 0 };
sprintf(filesizestr, "%lu", filesize);
strcat(allstr, " ");
//名字
strcat(allstr, filename);
strcat(allstr, " ");
//时间
strcat(allstr, ctime(&(sta.st_atime)));//ctime()本身返回的字符串,看起来最后会有一个\n
//这里的问题是 ctime 本身有一个\n,如果按照ls -la 的命名,时间是在 名字 之前的,也就是说,名字会在下一行才能显示
//printf("\n");
return 0;
}
int main() {
int ret = 0;
char dirpath[512] = { 0 };
strcat(dirpath,"/home/hunandede/");
DIR * pd = opendir(dirpath);
if (pd == NULL) {//open 失败
perror("opendir error");
ret = -1;
return ret;
}
dirent * spd = NULL;
int num = 0;
while (true) {
int temperrno = errno;
//cout << "before temperrno = " << temperrno << endl;
spd = readdir(pd);
if (spd != NULL) {
//判断是得到的文件的,那么就要从这里得到数据,
//mtk81234 得到文件的整体的名字
memset(dirpath, 0,512);
//dirpath[512] = { 0 };
strcat(dirpath, "/home/hunandede/");
//cout << "aaa = " << dirpath << endl;
//cout << "bbb = " << spd->d_name << endl;
char* filepathname = strcat(dirpath, spd->d_name);
//cout << "ccc = " << filepathname << endl;
char allstr[512] = { 0 };
fileinfo(filepathname, spd->d_name, allstr);
cout << allstr << endl;
}
else {
//出错 和 读到目录的最后,都会是NULL,需要通过 errno区分
//cout << "after errno = " << errno << endl;
if (temperrno != errno) {
//当出错的时候 errno 变化,和之前记录的temperrno 不一样,因此用这个判断是否有问题
//perror("readdir error errno because ");
ret = errno;
return ret;
}
else {
//cout << "readdir end " << endl;
break;
}
}
}
ret = closedir(pd);
if (ret == -1) {//close 失败
perror("opendir error");
ret = -1;
return ret;
}
cout << endl;
cout << "duandian" << endl;
}
拓展2:统计目录及其子目录中的普通文件的个数
//拓展2:统计目录及其子目录中的普通文件的个数
bool isfolderfiletype(__mode_t st_mode) {
//cout << "st_mode = " << st_mode << endl;
if ((st_mode & S_IFMT) == S_IFDIR) { //注意这里, & 和 ==的优先级问题,==的优先级要比 & 这个高,因此要用()弄起来
return true;
}
else {
return false;
}
}
//使用递归来实现
int filenumber(char * filepathname, int &num) {
struct stat sta;
//1 打开目录文件
DIR *dir = opendir(filepathname);
dirent *pdirent = NULL;
int ret = 0;
while (true) {
//2 读取目录文件
pdirent = readdir(dir);
int temperrno = errno;
if (pdirent == NULL) {
//出错 和 读到目录的最后,都会是NULL,需要通过 errno区分
//cout << "after errno = " << errno << endl;
if (temperrno != errno) {
//当出错的时候 errno 变化,和之前记录的temperrno 不一样,因此用这个判断是否有问题
//perror("readdir error errno because ");
ret = errno;
return ret;
}
else {
//cout << "readdir end " << endl;
return ret;
}
}
else {
//3.当读到目录的文件时候,将这个文件的全路径使用filerealpathname记录
char filerealpathname[256] = { 0 };
strcat(filerealpathname, filepathname);
strcat(filerealpathname, "/");
strcat(filerealpathname, pdirent->d_name);
//4.再得到这个文件的属性,
lstat(filerealpathname, &sta);//获取文件属性
//4.1如果是. 和 ..,我们不显示,注意的是:.和..是文件夹。最后,要continue,让while循环继续。
if (strcmp(".", pdirent->d_name) == 0 || strcmp("..", pdirent->d_name) == 0) {
//隐藏 . 和 ..文件,注意这两个还都是文件夹。
//cout << "childfullnameaaa = " << filerealpathname << endl;
//cout << "" << endl;
//num++;
continue;
//4.2如果不是.和.. 根据这个文件的属性判断是否是folder,如果是folder,则要再将当前文件塞入该方法,执行
}else if (isfolderfiletype(sta.st_mode)) {
//cout << "childfullname = " << filerealpathname << endl;
filenumber(filerealpathname, num);
}
//4.3 如果不是点 和点点,也不是 folder,则说明是文件,直接打印,计数num++;
else {
cout << "childfullnameaaa = " << filerealpathname << endl;
num++;
continue;
}
}
}
closedir(dir);
}
int main() {
int num = 0;
filenumber("/home/hunandede/projects/linuxcpp",num);
cout << "num = " << num << endl;
return 0;
}
本文介绍了Linux系统编程中的几个关键概念,如使用`readlink`查看软链接指向的文件,通过`getcwd`和`chdir`操作工作目录,以及处理文件权限、目录结构、递归遍历目录统计普通文件数量。还涵盖了`opendir`,`closedir`,和`readdir`函数的使用,以及如何获取和展示文件的基本信息。
1686

被折叠的 条评论
为什么被折叠?



