每日一练(二十一)
文章目录
12.6 通过函数修改查看文件属性
修改文件的访问属性
获取文件的属性
注意:
- stat 与 lstat的主要区别在于作用与链接文件时,stat获取的是所链接文件的属性,lstat获取的是链接文件本身的属性
- stat 与 fstat 一样,只不过是获取文件的方式不同,一种是文件路径,一种是文件描述符
- 通过参数中的 struct stst *buf 结构体来获取文件的属性,结构体成员如下:
还可以通过系统定义的宏来判断文件类型、文件访问权限:
官方例子:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysmacros.h>
int
main(int argc, char *argv[])
{
struct stat sb;
if (argc != 2) {
fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (lstat(argv[1], &sb) == -1) {
perror("lstat");
exit(EXIT_FAILURE);
}
printf("ID of containing device: [%lx,%lx]\n",
(long) major(sb.st_dev), (long) minor(sb.st_dev));
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);
}
12.7 常用进程产看方式
ps 静态查看系统进程快照
ps用来产看静态的进程统计信息,常用的选项如下:
- a:显示当前终端下所有进程信息,包括其他用户的进程
- u:以用户为主的格式输出进程信息
- x:显示当前用户在所有终端下的进程
- -e:显示系统内所有进程信息
- -l:使用常格式显示进程信息
- -f:使用完整格式显示进程信息
注意,有些命令选项是不加-
的,所以经常将aux
和-elf
分布组合使用
ps aux
的执行结果如下:
注意:
- VSZ:占用虚拟内存(swap空间)的大小
- RSS:占用常驻内存(物理内存)的大小
- STAT:显示当前进程状态:S(休眠)、R(运行)、Z(僵死)、<(高优先级)、N(低优先级)、s(父进程)、+(前台进程)
- TTY:表示该进程在哪个终端上运行,
?
表示未知或者不需要终端
top 动态查看进程信息
top用于动态查看进程的信息,默认三秒刷新一次,top
执行结果如下:
注意:
- CPU信息:us,用户占用;sy,内核占用;ni,优先级调度占用;id,空闲CPU;wa,I/O等待占用;hi,硬件中断占用;si,软件中断占用;st,虚拟化占用。了解空闲的CPU百分比,主要看%id部分
- 在top命令的全屏操作界面中,按P键根据CPU占用情况对进程列表进行排序,或按M键根据内存占用情况排序,按N键根据启动时间进行排序,按h键可以获得top程序的在线帮助信息,按q键可以正常地退出top程序
- 可以在top操作界面通过
k
键来终止对应的进程
/proc 产看进程详细信息
Linux中/proc
目录是一种文件系统,即proc文件系统,proc文件系统是一种伪文件系统(虚拟文件系统),存储的是当前内核运行状态的一些特殊文件。
所以用户可以通过查看/porc
中的相关文件来获取系统硬件以及当前正在运行的进程的信息,其中有些文件虽然会返回进程相关的大量信息,但是实际大小却是0Byte,下面随便列出一个/proc
下一个进程的目录:
相关文件的说明参考链接:Linux /proc目录详解 - 滴水瓦 - 博客园 (cnblogs.com)
pstree 产看进程树
linux中,每一个进程都是由其父进程创建的。此命令以可视化方式显示进程,通过显示进程的树状图来展示进程间关系。如果指定了pid了,那么树的根是该pid,不然将会是init(pid: 1)
htop 文本交互模式查看
htop与top很类似,但是htop是交互式的文本模式的进程查看器。它通过文字图形化地显示每一个进程的CPU和内存使用量、swap使用量。使用上下光标键选择进程,F7和F8改变优先级,F9杀死进程。Htop不是系统默认安装的,所以需要额外安装。
12.8 fork 创建多个子进程
创建多个子进程
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, const char *argv[])
{
int n;
pid_t pid;
for (i = 0; i < 5; i++) {
pid = fork();
if (pid < 0) {
perror("fork");
} else if (pid == 0) { //进入子进程,直接返回,子进程不再fork子进程
printf("this is %d process, pid:%d, ppid:%d\n", i, getpid(), getppid());
exit(0);
} else {
wait(NULL); //等待 i 儿子
}
}
return 0;
}
12.9 反向递归遍历链表
给出一个单向不循环链表的头结点,要求不改变链表结构的情况下反向遍历链表中的元素。
思路:递归实现,判断p是否为空,来输出元素。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int data_t;
typedef struct node {
data_t data;
struct node *next;
}node;
node *list_create();
int list_show(node *H);
node *list_pre_find(node *H, int post);
int list_insert_post(node *H, int post, data_t val);
int list_delete(node *H, int post);
int list_free(node *H);
int list_reverse_show(node *H);
int main(int argc, const char *argv[])
{
int i, n, num;
printf("input num size :");
scanf("%d", &n);
node *H = list_create();
printf("intput data:");
for (i = 0; i < n; i++) {
scanf("%d", &num);
list_insert_post(H, i, num);
}
list_show(H);
/* 功能测试 */
list_delete(H, 0);
list_show(H);
list_insert_post(H, 0, 99);
list_show(H);
/* 递归反向遍历,不打印头结点数据,所以传入 H->next */
list_reverse_show(H->next);
puts("");
list_free(H);
return 0;
}
int list_reverse_show(node *H)
{
node *p = H;
if (p != NULL) {
list_reverse_show(p->next); //陷入递归,直到链表末尾开始返回,逐步执行printf
printf("%d ", p->data);
}
return 0;
}
node *list_create()
{
node *p = (node*)malloc(sizeof(node));
if (NULL == p) {
printf("malloc filed\n");
return NULL;
}
memset(p, 0, sizeof(node));
p->next = NULL;
return p;
}
int list_show(node *H)
{
if (NULL == H) {
printf("H is NULL\n");
return -1;
}
node *p = H;
printf("H->");
while (p->next != NULL) {
p = p->next;
printf("%d->", p->data);
}
printf("NULL\n");
return 0;
}
node *list_pre_find(node *H, int post)
{
if (NULL == H) {
printf("H is NULL\n");
return NULL;
}
int i;
node *p;
p = H;
for (i = 0; i < post; i++) {
if (NULL == p) {
printf("post is over!\n");
return NULL;
}
p = p->next;
}
return p;
}
int list_insert_post(node *H, int post, data_t val)
{
if (NULL == H) {
printf("H is NULL\n");
return -1;
}
node *p, *q;
p = list_create();
p->data = val;
q = list_pre_find(H, post);
p->next = q->next;
q->next = p;
return 0;
}
int list_delete(node *H, int post)
{
if (NULL == H) {
printf("H is NULL\n");
return -1;
}
node *p = list_pre_find(H, post);
node *q;
q = p->next;
p->next = q->next;
free(q);
q = NULL;
return 0;
}
int list_free(node *H)
{
if (NULL == H) {
printf("H is NULL\n");
return -1;
}
node *p = H;
node *q;
while (p != NULL) {
q = p;
p = p->next;
free(q);
}
q = NULL;
return 0;
}
12.10 Linux 确定文件类型
Linux中确定文件类型使用命令file
,使用方法为:
file filename
Linux中一切皆文件!!!