Linux基础和系统编程 中

简介: Linux基础和系统编程 中

Linux基础和系统编程 中


read和write实现cp

1.read成功返回读到的字节数,失败返回-1,并设置相应的errno 的值

2.参数

fd:文件描述符

buf:存数据的缓冲区

count:缓冲区的大小

3.write

参数:

fd:文件描述符

buf:待写出数据的缓冲区

count:数据大小

返回值:返回写入的字节数

0表示没有什么可写的

失败返回-1,设置errno

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<pthread.h>
int main(int argc,char *argv[])
{
•   char buf[1024];
•   int fd1=open(argv[1],O_RDONLY);
    if(fd1==-1)
    {
        perror("open argv1 error");
        exit(1)
    }
•   int fd2=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);
    if(fd2==-1)
    {
        perror("open argv2 error");
        exit(1)
    }
•   while((n=read(fd1,buf,1024))!=0)
•   {
        if(n<0)
        {
            perror("read error");
            exit(1);
        }
•       write(fd2,buf,n);
•   }
•   close(fd1);
•   close(fd2);
•   return 0;
}

4.void perror(const char*s)

perror("open error");

系统调用和库函数比较

1.write是系统调用函数,putc是库函数

2.fgetc比read,write快一点

3.内核有系统级缓冲,默认大小有4096,即4kb大小,会一次性往磁盘写4kb

4.从用户区到内核比较耗时,比磁盘访问时间短,从用户区到内核是电子的操作,从内核到磁盘是物理操作

5.read,write函数会在用户与内核交换时浪费时间

6.fputc函数有一个缓冲,在这个空间缓冲了4kb数据才会进入内核,加快了4096倍速度

7.read,write被称为无缓冲IO(Unbuffered I/O),但不保证不使用内核缓冲

8.strace可以查看一个命令的系统调用,例如:strace ./read_cmp_getc

9.预读入,缓输出

10.系统函数不比库函数高级,系统函数效率不一定比库函数高

一般优先使用库函数

11.系统调用和库函数各有各的使用场景

文件描述符

1.PCB,进程控制块(进程描述符)process control block

本质是一个结构体,其中有一个指针指向是文件描述符表

2.文件描述符是本质可以理解为指针(实际上不是指针,是键值对映射),

3.指针指向

struct file

{

文件信息

}

4.访问打开的文件,只需要有文件描述符

5.0对应STDIN_FILENO,标准输入

1对应STDOUT_FILENO,标准输出

2对应STDERR_FILENO,标准错误

一个进程最多打开1024个文件,最大下标是1023,修改需要改内核

6.新打开文件一定是可用文件描述符中最小的那个

7.FILE结构体包括:文件的偏移量,文件的访问权限,文件的打开标志,文件内核缓冲区的首地址

阻塞与非阻塞

1.读常规文件不会阻塞,不管有多少字节

当读设备文件和读网络文件时会阻塞

2./dev/tty对应终端文件

3.阻塞是文件的属性

4.改变终端阻塞的属性要加O_NOBLOCK

5.fd=-1:并且erron=EAGAIN或EWOULDBLOCK,说明不是read失败,而是read在读一个设备文件(网络文件),并且文件无数据

6.解决非阻塞需要设置超时

fcntl的属性

1.改变一个文件的访问控制属性

2.一个参数是文件描述符fd,一个参数是命令cmd,命令的类型个数决定了后续的参数个数

3.获取文件状态 F_GETFL

设置文件状态 F_SETFL

4.位图

以二进制位画图

5.int flags=fctl(0,F_GETFL)

flgs|=O_NONBLOCK

fcntl(0,F_SETFL,flgs)

lseek函数

1.fd文件描述符

offset偏移量

whence起始偏移位置:SEEK_SET/SEET_CUR/SEEK_END

2.off_t seek(int fd,off_t offset,int whence)

3.返回值是

成功:较起始位置偏移量

失败:-1 errno

4.文件的读写是同一个偏移位置

5.

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main(){
•   int fd,n;
•   char msg[]="It's a test for lseek\n";
•   char ch;
•   fd=open("lseek.txt",O_RDWR|O_CREAT,0644);
•   if(fd<0){
•   perror("open lseek.txt error");
•   exit(1)
}
write(fd,msg,strlen(msg));
lseek(fd,0,SEEK_SET);
while(n=read(fd,&ch,1)){
•   if(n<0){
•   perror("read error");
•   exit(1);
    return 0;
}
}
}

6.应用场景: 文件的读写使用同一偏移位置

使用lseek获取,拓展文件大小(要想使文件大小真正拓展,必须引起IO操作)

7.

获取文件大小:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<pthread.h>
int main(int argc,char *argv[])
{
•   open(argv[1],O_RDWR);
•   if(fd==-1)
•   {
•       perror("open error");
•       exit(1);
•   }
    int length=lseek(fd,0,SEEK_END);
•   printf("file size:%d\n",length);
    close(fd);
    return 0;
}

拓展文件大小:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<pthread.h>
int main(int argc,char *argv[])
{
    open(argv[1],O_RDWR);
    if(fd==-1)
    {
        perror("open error");
        exit(1);
    }
    int length=lseek(fd,111,SEEK_END);
    printf("file size:%d\n",length);
    write(fd,"a",1);
    close(fd);
    return 0;
}

8.^@称为文件空洞行

9.od -tcx filename 查看文件的16进制表示形式

od -tcd filename 查看文件的10进制表示形式

10.turncate拓展文件

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<pthread.h>
int main(int argc,char *argv[])
{
•   int ret=truncate("dict.cp",250);
•   printf("ret=%d\n",ret);
•   return 0;
}

传入传出参数

传入参数:

1.指针作为函数参数

2.通常有const关键字修饰

3.指针指向有效区域,在函数内部做读操作

传出参数:

1.指针作为函数参数

2.在函数调入之前,指针指向的空间可以无意义,但必须有效

3.在函数内部,做写操作

4.函数调用结束后,充当函数返回值

传入传出参数:

1.指针作为函数参数

2.在函数调用之前,指针指向的空间有实际意义

3.在函数内部,先做读操作,后做写操作

4.函数调用结束后,充当函数的返回值

目录项和inode

inode

本质是一个结构体,存储文件的属性信息,权限,类型,大小,时间,用户,盘块位置

dentry(目录项)

存储文件名,inode

文件由inode和dentry组成

硬链接只有dentry不同

磁盘空间没有擦除,只有覆盖

stat函数

1.获取文件属性(从inode结构体中获取)

2.int stat(const char *path,struct stat *buf)

参数:

path:文件路径

buf:传出参数:存放文件属性

返回值:成功:0

失败:-1 errno

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<pthread.h>
int main(int argc,char *argv[])
{
    struct stat sbuf
•   int ret=stat(argv[1],&sbuf)
•   if(ret==-1)
    {
•       perror("stat error");
•       exit(1);
    }
    printf("file size:%d\n",sbuf.st_size);
    return 0;
}

3.宏函数返回值是真假

Istat和stat

1.

需要头文件#include<sys/stat.h>

if(S_ISREG(sb.st_mode))

{

printf("It's a regular\n");

}

2.mkfifo

创建管道

3.stat穿透,默认可以穿透符号链接

不想穿透要换函数,lstat不会穿透

4.cat可以穿透符号链接,vim不可以

5.获取文件大小:buf.st_size

获取文件类型:buf.st_mode

6.文件权限是16位(2字节)后九个是rwxrwxrwx,对应u,g,o

5~7是特殊权限位

最前面四位是文件类型

前4位是掩码

获取前四位信息

   switch(sb.st_mode&S_IFMT)

{

•   case S_IFBLK:  printf("block device\n")

}

传出参数与返回值

1.传出参数有返回值的功能,但是没有替代返回值

2.传出参数也可以向函数返回值,传出参数可以充当函数返回值

link和unlink隐式回收

1.link是实现硬链接的函数

2.LInux下删除文件的机制:不断将st nlink-1,直到减到0为止,没有目录对应的文件,将会被操作系统择机释放

3.我们删除文件,从某种意义上说,只是让文件具备了被释放的条件

4.unlink函数的特征:清除文件时,如果文件的硬链接数到0了,没有dentry对应,但该文件仍不会马上被释放掉,要等所有打开文件的进程关闭该文件,才会择机释放

文件目录rwx权限差异

1.readlink读符号链接

2.getcwd 获取进程当前工作目录

3.vi打开目录,目录的内容叫目录项

4.文件可读是文件内容可以看,可以用cat,more,less

目录可读是目录可以浏览,可以执行ls,tree

文件可以写,可以修改文件内容

目录的写权限是可以添加删除目录项,执行mv,touch,mkdir

文件可执行是可以运行产生一个进程,“./文件名”

目录的执行权限是可以被进入,没有执行权限cd不进去

目录操作函数

opendir

根据传入的目录名打开一个目录(库函数)

DIR*opendir(const char *name);

成功返回指向该目录的结构体指针,失败返回NULL

参数支持相对路径,绝对路径两种方式:例如:打开当前目录

1.getcwd(),opendir()

2.opendir(".")

closedir

关闭打开的目录

int closedir(DIR *dirp);

成功:0

失败:-1 设置errno

readdir

读取目录(库函数)

‘ struct dirent *readdir(DIR *dirp);

成功返回目录项结构体指针

失败返回NULL设置errno为相应值

readwinder

回卷目录读写位置至起始

void rewinder(DIR *dirp)

返回值:无

telldir/seekdir

获取目录读写位置

long telldir(DIR *dirp);成功:与dirp相关目录当前读写位置。

失败-1,设置errno

修改目录读写位置

void seekdir(DIR *dirp,long loc)

返回值:无

参数loc一般由telldir函数的返回值来决定

递归遍历目录思路分析

ls-R.c

1.判断命令行参数,获取用户查询的目录名。argv[1]

argc==1-->./

2.判断用户指定的是否是目录 stat S_ISDIR();

3.读目录:

opendir(dir)

while(readdir()){

普通文件:直接打印

目录:拼接目录访问绝对路径 dir/d_name(sprintf(path,“%s/%s”,dir,dir_name))

递归调用自己。-->opendir(path) readir closedir

}

closedir()

递归遍历目录代码预览

1.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<sys/stat.h>
#include<dirent.h>
void isFile(char *name)
//打开目录,读取目录,处理目录
void read_dir(char *dir,void(*func)(char *))
{
•   char path[256];
•   DIR *dp;
•   struct dirent *sdp;
•   dp=opendir(dir);
•   if(dp==NULL){
•       perror("opendir error");
•       return;
•   }
•   //读取目录项
•   while(sdp=readdir(dp)!=NULL){
•       if(strcmp(sdp->d_name,".")==0||strcmp(sdp->d_name,"..")==0){
•               continue;
•       }
        fprintf(dp);
•       //目录项目本身不可访问,拼接目录/目录项
•       sprintf(path,"%s/%s,dir,sdp->d_name)
•       //判断文件类型,目录递归进入,文件显示名字/大小
•       isFile(path);
        (*func)(path);
•   }
•   closedir(dp);
•   return;
}
void isFile(char *name)
{
•       int ret=0;
•       struct stat sd;
•       //获取文件属性,判断文件类型
•       ret=stat(name,&sb);
•       if(ret==-1){
•           perror("stat error");
•           return;
•       }
•       //是目录文件
•       if(S_ISDIR(sb.st_mode)){
•           read_dir(name);
•       }
•       //是普通文件,显示名字/大小
•       printf("%s\t%d\n",name,sb.st_size);
•       return;
}
int main(int argc,char *argv[])
{
​ //判断命令行参数
​ if(argc==1){
​   isFile(".");
​ }
​ else{
​   isFile(argv[1]);
​ }
}

2.stat函数原型

int stat(const char *path,struct stat *buf)

dup和dup2

1.dup英文为重复

2.cat myls.c > out

3.dup

int dup(int oldfd);

oldfd:已有文件描述符

返回:新文件描述符

头文件:#include<unistd.h>

4.

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int main(int argc,char *argv[])
{
fd=open(argv[1],O_RDONLY);
int newfd=dup(fd);
printf("newfd=%d",newfd);
return 0;
}

5.dup2(dupto)

int dup2(int oldfd,int newfd);

#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int main(int argc,char *argv[])
{
fd1=open(argv[1],O_RDONLY);
fd2=open(argv[2],O_RDONLY);
int fdret=dup2(fd1,fd2);//返回文件描述符fd2
printf("fdret=%d\n",fdret);
int ret=write(fd2,"1234567"); //写入fd1指向的文件
printf("ret=%d\n",ret);
dup2(fd1,STDOUT_FILENO); //将屏幕输入,重定向给fd1所指向的文件
printf("ghjkjhghjikjhg\n");
return 0;
}

6.cat hello.c > out

将应该输出在终端的数据写入文件

7.dup2可以理解为后指向前,newfd指向oldfd

fcntl实现dup描述符

1.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<pthread.h>
int main(int argc,int *argv[])
{
•       int fd1=open(argv[1],O_RDWR);
•       printf("fd1=%d\n",fd1);
•       int newfd=fcntl(fd1,F_DUPFD,0);
•       printf("newfd=%d\n",newfd);
}


相关文章
|
11天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
47 3
|
11天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
36 2
|
21天前
|
Linux 应用服务中间件 Shell
linux系统服务二!
本文详细介绍了Linux系统的启动流程,包括CentOS 7的具体启动步骤,从BIOS自检到加载内核、启动systemd程序等。同时,文章还对比了CentOS 6和CentOS 7的启动流程,分析了启动过程中的耗时情况。接着,文章讲解了Linux的运行级别及其管理命令,systemd的基本概念、优势及常用命令,并提供了自定义systemd启动文件的示例。最后,文章介绍了单用户模式和救援模式的使用方法,包括如何找回忘记的密码和修复启动故障。
42 5
linux系统服务二!
|
21天前
|
Linux 应用服务中间件 Shell
linux系统服务!!!
本文详细介绍了Linux系统(以CentOS7为例)的启动流程,包括BIOS自检、读取MBR信息、加载Grub菜单、加载内核及驱动程序、启动systemd程序加载必要文件等五个主要步骤。同时,文章还对比了CentOS6和CentOS7的启动流程图,并分析了启动流程的耗时。此外,文中还讲解了Linux的运行级别、systemd的基本概念及其优势,以及如何使用systemd管理服务。最后,文章提供了单用户模式和救援模式的实战案例,帮助读者理解如何在系统启动出现问题时进行修复。
41 3
linux系统服务!!!
|
5天前
|
Ubuntu Linux 网络安全
linux系统ubuntu中在命令行中打开图形界面的文件夹
在Ubuntu系统中,通过命令行打开图形界面的文件夹是一个高效且实用的操作。无论是使用Nautilus、Dolphin还是Thunar,都可以根据具体桌面环境选择合适的文件管理器。通过上述命令和方法,可以简化日常工作,提高效率。同时,解决权限问题和图形界面问题也能确保操作的顺利进行。掌握这些技巧,可以使Linux操作更加便捷和灵活。
13 3
|
29天前
|
Web App开发 搜索推荐 Unix
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
【10月更文挑战第21天】Linux系统之MobaXterm远程连接centos的GNOME桌面环境
249 4
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
|
30天前
|
运维 监控 Linux
Linux系统之部署Linux管理面板1Panel
【10月更文挑战第20天】Linux系统之部署Linux管理面板1Panel
90 3
Linux系统之部署Linux管理面板1Panel
|
11天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
43 3
|
14天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
34 6
|
14天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
49 6
下一篇
无影云桌面