linuxC应用

参考正点原子linuxC应用开发

参考正点原子linuxC应用开发

文件

一个进程打开一个文件,系统会给进程返回一个文件描述符;有进程打开文件描述符是有限的,可以使用 “ulimit -n”命令查看一个进程可以打开的最大文件数量。
创建出一个进程,系统会默认存在三个文件描述符,0 标准输出, 1 标准输入,2标准错误输出。
open
打开文件有两个系统调用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int flags);	//打开一个文件,
int open(const char *path, int flags, mode_t mode);	// 打开一个文件,如果该文件不存在则创建文件
	path 为文件路径,可以问相对路径,也可以为绝对路径。
	flags 文件标志,代表打开文件时对文件的访问模式,以及一些文件特性
		O_RDONLY	只读打开
		O_WRONLY	只写打开
		O_RDWR		可读可写打开
		O_CREAT		当文件不存在则创建文件,此标志是在含有三个参数的open系统调用中有用,且 mode_t 需要传入文件权限
		O_EXCL			测试打开的文件是否存在,存在则返回错误,是一个原子操作,便于重复创建一个文件
		O_NOFOLLOW	是否对软连接进行解引用,软链接文件的内容保存了文件的真正位置,当没有次参数时,打开软链接文件时,会对链接文件进行解引用,最终打开正真文件。
		O_APPEND	每次写入时都会在文件末尾追加,但是读数据不影响,也就是默认打开文件时,光标处于文件开头,只要写入,则会追加在末尾写入,写完光标则停留在末尾;多次open同一个文件,带有O_APPEND写入时,不会出现覆盖情况
		O_ASYNC
		O_DSYNC
		O_NOATIME
		O_NOBLOCK
		O_SYNC
		O_TRUNC		将打开的文件直接截取为0
mode 问文件权限,文件访问权限决定着进程是否能对文件进行访问。
	理解文件权限:程序员需要操作电脑,先以用户账号登录电脑,用户账号代表着程序员,当程序员运行程序,则产生一个进程,该进程属于程序员在使用,进程打开一个文件代表着程序员想要打开文件。文件访问权限代表着该进程(用户)是否有权力去访问它。
	文件权限有四组,S  U  G  O , 每组都由三个bit表示 rwx(读,写,执行),一般以八进制表示777, 该位为1表示具有权限,为0表示没有权限;
		S 特殊文件权限,
		U  用户访问权限
		G 用户组访问权限
		O 其他人访问权限
返回文件描述符,该文件描述符表打开文件,当返回值为 -1 表示错误
write
#include <unistd.h>
ssize_t wirte(int fd,const void *buf, size_t count);
	fd 表示文件描述符
	buf 要写入文件的内容首地址
	count 表示写入文件内容的大小。
	返回值:返回-1表示写入错误,返回值大小表示写入文件的大小。
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
	fd  表示文件描述符
	buf 表示存储读取内容的首地址
	count 表示想要读取的字节数
	返回值:表示实际读取字节数的大小,返回-1表示读取数据错误
close
#include <unistd.h>
int close(int fd);
	fd 表示文件描述符
	返回值 返回0表示成功,-1表示错误
当进程结束,系统会将该进程打开的所有文件都关闭。
lseek
光标:光标决定着操作文件的位置
偏移量:描述光标距离文件开始处的偏移大小。
系统打开文件,默认的偏移量为0,也就是光标现在处于文件的开始处。随着对文件的写入和读取,光标会移动,偏移量也会随着改变。
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
	fd 表示 文件描述符
	offset 表示偏移位置,该偏移位置是结合 whence参数来确定光标在整个文件中的位置
	whence 有三个选项 SEEK_SET(文件开始处),SEEK_CUR(现在文件的位置),SEEK_END(文件的末尾)
	返回值:文件的偏移量大小,即光标的位置。-1表示错误

静态文件

文件是保存在硬盘,u盘中,硬盘最小的存储单位为扇区,每个扇区的大小为512B,但是操作系统读取硬盘的最小单位为块,每块为4KB。
硬盘在格式化时,分为两个区域,一个为数据区,一个为Inode区,数据区保存数据,inode区中有inode表和inode节点,每一个文件对应一个inode节点,我们通过inode表号 获取到inode节点,inode 节点记录着文件的属性,以及相关信息。(注意文件名并不存在inode节点中)。
系统打开文件会经过三步骤:
	1.通过文件名确定inode编号,
	2.通过inode 编号在inode表中找到inode 节点,
	3.通过inode 节点记录的信息确定文件存在的位置,按块读取出数据。
进程与打开文件之间的关联:
	进程控制块PCB(struct_task)中有一个文件描述符表,通过文件描述符可以在文件描述表中获取到文件表,文件表中记录着文件的各种属性,其中有一个属性可以获取到inode 节点。
streeror
#include <string.h>
#include <errno.h>
char *strerror(errno);
	errno 系统错误编号
perror
#include <stdio.h>
void perror(const char *buf);
	直接输出系统错误信息
	buf 想要在错误信息前面添加的内容。
_exit
#include <unistd.h>
void _exit(int status);
	系统调用退出程序。
	status 表示系统退出状态,0表示正常退出。
exit
#include <stdlib.h>
void exit(int status);
	标准C库函数,该函数内部会做一些清理工作,最后调用_exit() 函数。
空洞文件
空洞文件的概念:使用lseek 函数,修改文件光标的位置,当文件光标的位置大于文件实际长度,就会形成空洞文件。
当我们查看文件的大小时,显示的是空洞文件的大小,但是实际占用的内存大小会小于空洞文件的大小。
多次打开文件问题。
一个进程多次使用open打开一个文件。
	多次使用open,会得到不同的文件描述符,不同的文件表,相同的一份动态文件内容,和文件表中指向相同的inode节点
一个进程多次使用dup,dup2打开文件。
	其实dup,dup2都只是将文件描述符表指向了同一个文件表。
dup,dup2
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
	复制文件描述符,但是就得文件描述符和新的文件描述符指向同一个文件表。
	返回值:新的文件描述符
对文件进行读写的原子操作
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, void *buf, size_t count, off_t offset);
	其参数和返回值和 read,write函数一样,除了 
	offset 相对于文件开始处的偏移量。
O_EXCL 和 O_APPEND 标志也是原子操作,前者为了避免在多个进程创同时创建一个文件,后者用于多个进程写入时避免写入覆盖。
fcntl
#include <fcntl.h>
#include <unistd.h>
int fcntl(int fd, int cmd, ...);
	fcntl 是一个多功能函数,可以复制文件符,对文件进行加锁,修改文件部分状态标志,修改文件描述符标志,设置异步io
	fd 文件描述符
	cmd 可以为多中类型,不定参数 ... 会根据cmd类型参数而定
	复制文件描述符 F_DUPFD 
	获取/设置文件锁 F_GETLK / F_SETLK
	获取/设置文件状态标志 F_GETFL / F_SETFL
	获取/设置文件描述符 F_GETFD / F_SETFD
	获取/设置异步IO所有权 F_GETOWN / F_SETOWN
ioctl
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
IO文件杂物箱,一般用在IO驱动方面。
truncate , ftruncate
#include <unistd.h>
#include <sys/types.h>
	int ftruncate(int fd, off_t offset);
	int truncate(const char *path, off_t offset);
	对文件进行截取,当文件大于截取长度,会将后面的数据丢弃;当文件小于截取长度,会使用‘\0’字符进行填充;
	注意:ftruncate 函数第一参数为问价描述符,其文件状态标志必须具有写的权限。
	返回值为0表示成功。 -1表示错误。
标准C库IO
#include <stdio.h>
struct FILE ;
	此结构体为标准IO函数打开文件返回的结构体地址,该结构体具成员中有文件描述符,进程缓存buf等。
fopen
#include <stdio.h>
FILE * fopen(const char *path, const char *mode);
	path 文件路径,包含文件名
	mode 打开文件时,对文件的读写模式,如果该文件不存在则创建文件时,文件权限为默认 0666
		“r” 						O_RDONLY
		"r+“ 						O_RDWR
		"w"		 				O_WRONLY | O_CREAT | O_TRUNC
		'w+"						O_RDWR | O_CREATE | O_TRUNC
		"a”						O_WRONLY | O_CREAT |  O_APPEND
		"a+"						O_RDWR | O_CREATE | O_APPEND
fread,fwrite
#include <stdio.h>
size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *buf, size_t size,  size_t nmemb, FILE *stream);
	buf 读写数据存储区域,
	size 数据项的大小
	nmemb 多少个数据项
	stream FILE指针
	返回值: 返回读写数据项的个数。
fseek
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
	设置光标位置
	stream FILE指针
	offset 偏移位置
	whence 光标位置,SEEK_SET, SEEK_CUR, SEEK_END
	返回值:0表示成功,-1表示失败,与lseek的返回值有所不同,lseek返回-1 为失败,非负数表示光标位置。
ftell
#include <stdio.h>
int ftell(FILE *stream );
	获取文件光标位置
	stream FLIE指针
	返回值: 返回光标位置。-1 表示失败
feof
#include <stdio.h>
int feof(FILE *stream);
	end-of-file,达到文件末尾,
	stream FILE指针
	返回值,非0表示到达文件末尾。0 表示为到达文件末尾。
ferror
#include <stdio.h>
int ferror(FILE *stream);
	当文件的IO操作发生错误时,错误标志位将会被置位,
	stream FILE指针
	返回值:非0表示发生错误,0 表示没有发生错误。
clearerr
#include <stdio.h>
void clearerr(FILE *stream);
清除错误标志位和到达末尾标志位

文件类型

linux 文件类型分为 7种,
	1.普通文件,字符表示“-”,包含文本文件,二进制文件
	2.目录文件,字符表示“d”
	3.字符设备文件,字符表示“c”
	4.块设备文件,字符表示“d”
	5.软连接文件,字符表示“l”
	6.套接字文件,字符表示“s”
	7,管道文件,字符表示“p”
stat,fstat,lstat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
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  结构体变量中。
	path 为打开的文件
	buf 保存了文件属性信息
	i返回值:0 表示成功, -1表示失败
struct timespec
#include <time.h>
struct timespec
{
	time_t tv_sec;		//秒
	syscall_slong_t tv_nsec;	//纳秒
};
linux时间结构体

文件属主,进程属主,进程有效属组

linux 是一个支持多用户,多进程的系统,多用户代表可以多个人操作一个系统,多进程代表用户可以同时操作多个任务。
那么我们就绪需要确保系统中的资源是属于哪个用户,以及对资源的控制权问题。所以就存在资源所有者(用户ID)和资源所属组(用户组ID)。
文件属主:
					文件用户ID
					文件用户组ID
进程属主:
					进程用户ID:决定了该
					进程用户组ID
进程有效属主:
					进程有效用户ID
					进程有效用户组ID
					进程附属组ID
chown,fchown,lchown
#include <unistd.h>
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 onwer, gid_t group);
	修改文件所属和文件所属组。
	修改文件所属的条件是该进程的有效用户ID为root用户;
	修改文件所属组的条件是该进程的有效用户ID 为 root 用户,或是文件所属用户。
	path 文件路径以及文件名
	onwer 文件所属ID
	group 文件所属组ID
	返回值:0表示成功,-1表示失败
getuid, getgid
#include <unistd.h>
#include <sys/types.h>
	uid_t getuid(void);		//获取进程的用户ID(所属ID)
	gid_t getgid(void);		//获取进程的用户组ID(所属组ID)

目录权限的作用

目录的可读,可写,可执行权限与文件的可读可写所有不同
	可读权限:可以列出目录下的内容
	可写权限:可以在目录下创建文件,删除文件
	可执行权限:进入到该目录,可以对该目录下的文件进行读写执行操作。
文件检查
进程能否对一个文件进行操作,首先进程进程是否有操作文件的权限,然后再判断打开文件时的文件标志位,最后才能操作文件。
#include <unistd.h>
int access(const char *path, int mode);
	path 文件所在位置,以及文件名	
	mode 检测文件的模式,该检测模式可以进行与运算
		F_OK		检测文件是否存在
		R_OK		检测是否拥有读权限
		W_OK		检测是否拥有写权限 	
		X_OK		检测是否拥有执行权限
	返回值: 0 表示成功,-1 表示失败,只要有一项不具有权限则返回 -1
chmod, fchmod
#include <sys/stat.h>
	int chmod(const char *path, int mode);		//若文件为软连接文件,则修改软连接指向的文件
	int fchmod(int fd, int mode);
	修改文件权限, mode 为文件权限。文件权限可以使用八进制 0777等
	返回值: 0 表示成功,-1表示失败
umask
文件权限掩码,其作用是对新创建的文件权限进行屏蔽。
#include <sys/types.h>
#include <sys/stat.h>
int umask(mode_t mask);
	mask 屏蔽的权限
	返回值:0表示成功,-1表示失败。
文件的时间戳属性
文件时间属性有:文件最后被访问,文件最后被修改,文件状态最后改变
	文件最后被访问:指对文件内容进行读取的最后时间。
	文件最后被访问:指对文件内同进行修改的最后时间 。
	文件状态最后改变:指对文件的inode节点进行修改的最后时间
utime
#include <sys/types.h>
#include <utime.h>
int utime(const char *filename, const struct utimbuf time);
	struct utimbuf {
		time_t atime;
		time_t modtime;
	}
	修改文件的最后访问时间和最后修改时间。只有root用户和文件所属用户可以修改。

软链接与硬链接

软连接:该文件的内容指向具体的文件,软连接有自己的inode,有自己的文件内容
硬链接:两个不同的文件名称,但是他们两个指向同一个inode,具有相同文件内容。
shell 命令:
	软连接: ln -s 源文件  软连接文件
	硬链接: ln 源文件  硬链接文件
硬链接的缺点:
	1.不能对目录进行硬连接。
	2.硬连接要求链接文件和源文件在同一个文件系统中
软连接的优点:
	1.可以对目录进行链接
	2.可以跨不同的文件系统进行链接
	3.可以对不存在的文件进行链接
link
#include <unistd.h>
int link(const char *oldpath, const char *newpath);
	创建硬链接
	oldpath  源文件
	newpath 链接文件
	返回值: 0 表示成功, -1 表示失败
symlink
#include <unistd.h>
int symlink(const char *oldpath, const char *newpath);
	创建软连接
	oldpath 源文件
	newpath 链接文件
	返回值:0表示成功, -1表示失败
readlink
#include  <unistd.h>
int readlink(const char *pathname, char *buf, size_t size);
	读取软连接文件,
	pathname 软连接文件名
	buf  读取软连接文件内容的内存缓冲区
	size 读取的大小。
	返回值: -1表示读取失败, 成功则返回读取的字节数。

目录

在linux 中,目录和文件的存储形式一样,分为inode节点和目录块,而文件分为inode 和数据块,数据块保存着数据信息;目录块保存着文件名或是目录名,以及inode。如果该目录下有多个文件,则目录块则有多个目录条。
目录的操作也可以使用,open,read,write,但是我们一般使用操作目录的系统调用或是库函数。
mkdir
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *path, modt_t mode);
	创建一个目录
	path 创建目录的路径
	mode 与创建文件的权限一样,最终的权限为 (mode & ~umask);
	返回值:0 表示成功,-1表示失败
rmdir
#include <unistd.h>
int rmdir(const char *path);
	删除一个空目录,即文件该文件下只有 . 和 .. 目录项。
	path 为删除目录路径,该路径不能为软连接文件指向目录。
	返回值:0表示成功,-1表示失败
opendir
#include <sys/typed.h>
#include <dirent.h>
DIR * opendir(const char *path);		//标准C库函数
	打开目录
	path 目录路径
	返回值: DIR 目录句柄,与FILE 文件句柄意思相近。 返回NULL表示打开失败
readdir
#include <dirent.h>
struct dirent * readdir(DIR *dirp);
	读取目录内容,
	DIR 目录句柄
	返回值:返回一条目录条的信息,当读取到末尾或是读取错误会返回NULL, 但是错误会设置 erron;
	struct dirent {
		ino_t d_ino;		//idnoe 编号号
		off_t d_off;
		unsigned short d_reclen;
		unsigned char d_type;
		char d_name[256];		//文件名
	};
rewinddir
#include <sys/types.h>
#include <dirent.h>
void rewinddir(DIR *dirp);
	与 fseek(), lseek(),功能类似,使DIR 句柄指向第一个目录条。
closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
	dirp 目录句柄
	返回值:0表示成功,-1表示失败 
getcwd
#include <unistd.h>
int getcwd(char *buf, size_t size);
	获取进程当前的工作目录,current working directory。
	buf 当前目录存储内存缓冲区
	size buf 大小
	返回值:0表示成功,-1表示失败
chdir
#include <unistd.h>
int chdir(const char *path);
int fchdir(int fd);
path 为改变进程的工作目录路径
fd 为使用open打开的一个目录路径。
返回值,0表示成功, -1表示失败
unlink
删除文件的本质是:删除该目录下对应文件名的目录条,再去操作inode属性的 inode链接计数。当inode链接接计数为0,linux内核会回收该inode数据区和数据块。unlink不会对软连接解引用,直接删除软连接。
#include <unistd.h>
int unlink(const char *path);
	path 文件名称
	返回值:0表示成功,-1表示失败
remove
#include <stdio.h>
int remove(const char *path);
	 标准C库函数,与 unlink, rmdir一样,不会对软连接进行解引用
	 path 文件路径
	 返回值:0表示成功,-1表示失败
rename
#include <stdio.h>
int rename(const char *oldpath, const char *newpath); //可以改变文件,也可以改变目录
	rename 只会改变文件目录条。不会改变其他属性。
	oldpath 	修改前的文件名
	newpath 修改后的文件名
	返回值: 0 表示成功,-1表示失败。
	1.当newpath 存在则会直接覆盖存在的文件或是目录,软连接、
	2.当oldpath和newpath 相同,则不发生改变,但是调用成功
	3.不管目录,文件,软连接都只会改变名称,不会改变属性。
	4.当oldpath 为目录,那么newpath 要不就不存在,要不就是一个空目录。
	5.oldpath 和 newpath 必须在同意文件系统中。

信号

linux的信号是一种异步通信机制,也可以理解为软中断;其作用能做打断程序的正常执行,执行信号处理函数,处理完成在返回到被打断程序的地方继续执行。
当信号产生后,处理信号的方法有三种:
	忽略信号:不对信号进行处理,两个信号是不能忽略 SIGKILL(进程结束信号) , SIGSTOP(进程停止信号)
	捕获信号:当信号到达进程后,执行预先绑定的信号处理函数。
	执行系统默认操作:大多数信号,系统的默认操作为终止进程
可靠信号和不可靠信号
可靠信号和不可靠信号的区别为:可靠信号支持排队,不可靠信号不支持排队。其本质为不可靠信号在捕获信号时,还有相同的信号产生,可能会丢失该信号;
不可靠信号: 1 - SIGRTMIN ,不包含SIGRTMIN
可靠信号: SIGRTMIN - SIGRTMAX
系统默认处理行为即信号
占位
signal
signal 可将信号的处理方式设置为 捕获,忽略,默认的系统处理。
#define SIG_ERR		-1			//函数返回 错误时返回该值
#define SIG_DFL		0			
#define SIG_IGN			1
#include <signal.h>
typedef void (*sig_t)(int);		// 函数指针
sig_t signal(int signum, sig_t handler);
	signum 信号编号
	handler 信号	sig_t 类型的函数指针。 当为 SIG_DFL 时表示 设置该信号为系统默认信号,当 为 SIG_IGN 是表示设置该信号为忽略。 
	返回值:成功:返回 handler 函数指针; 失败:返回SIG_ERR.
两种不同状态下的信号处理方式
程序启动:相当于执行exec 族函数,这时信号处理函数为 系统默认的处理方式。
进程创建:相当于执行fork函数,这时信号处理函数将会继承 父进程的处理方式。 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值