UC高级编程第二天

一.LINUX中缓存类型

1.用户空间缓存机制

1.行缓存:stdin/stdout

2.无缓存:普通文件

3.全缓存 :stderr

行缓存:遇到\n换行符

进程正常终止的时候,从main函数 return

二 linux中文件的类型:共有7种
-:表示普通文件
d: 表示文件夹文件
c: 表示字符设备文件
b: 表示块设备文件
s: 表示socket文件
l:表示链接文件
p: 表示管道文件

三. 标准IO之定位流

fseek:

int fseek(FILE *stream, long offset, int whence);

功能:
定位文件流
参数:
fp: 改变偏移量的文件
offset: 偏移的字节个数
whence: SEEK_SET 定位文件流在文件的开头
SEEK_CUR 定位文件流在文件的当前位置
SEEK_END 定位文件流在文件的末尾
返回值:
成功 返回0
错误 -1 errno被设置

rewind:

rewind(3)  
		rewind() == fseek (fp, 0L, SEEK_SET);
		功能:将文件流定位到文件的开头位置

ftell:

ftell(3) 
		功能:获取当前文件位置并返回
		返回值: 成功 返回文件当前位置
		

四.系统IO,文件IO标准IO的区别

1.文件IO是linux内核向上提供的接口,都是系统调用函数

2.系统调用函数是内核直接提供的函数,在linux操作系统中有470+
库函数是在系统调用的基础上再次根据不同的需求进行封装的,标准IO都是通过系统调用函数而实现的

可以简单的说明

标准IO:

标准IO是C语言标准库中定义的一组用于输入输出操作的函数,如printf、scanf、fopen、fclose等。
它提供了一种抽象层,使得程序员不必关心底层硬件的细节,就可以进行文件和设备的数据交换。
标准IO通常使用缓冲机制来提高I/O操作的效率。

系统IO:

  • - 系统IO通常指的是操作系统层面的输入输出操作,它可能包括对硬件设备的直接访问。
    - 系统IO可能涉及到更底层的接口,如中断、DMA(直接内存访问)等,这些通常由操作系统的设备驱动程序来管理。
    - 系统IO可能不使用缓冲,或者使用不同的缓冲策略。
    

文件IO(File I/O):

文件IO是指对文件进行读写操作的过程,它是I/O操作的一种特例。
文件IO可以通过标准IO函数实现,也可以通过系统调用(如Unix/Linux的read和write系统调用)直接进行。
文件IO操作可能涉及到文件系统的交互,如文件的打开、关闭、定位和同步等。

系统IO

open:

int open(const char *pathname, int flags, mode_t mode);
功能:
		参数:
				pathname: 文件的路径 
				flags: 文件打开的标记信息和文件状态信息
					三选一
					O_RDONLY
					O_WRONLY 
					O_RDWR
					文件的创建信息或者文件的状态信息可以或上以上三个宏
					O_APPEND:
						以追加的方式打开文件, 在每次写操作之前将文件的读写位置定位到文件的末尾
					O_CREAT:
						如果文件不存在 则创建文件 如果标识信息中有该宏, 则必须指定mode 
						mode指定了将要创建的文件的权限, mode的权限可能会被进程的umask修改
						mode & ~(umask)
					O_EXCL:
						确信创建文件, 如果和O_CREAT一起指定, 如果要创建的文件存在则报错 EEXIST
					O_TRUNC:
						如果以写的方式打开的是普通文件且文件存在, 则将文件截断为0
		返回值:
			成功 文件描述符
			错误 -1 errno被设置

read:

ssize_t read(int fd, void *buf, size_t count);
功能:
			从文件描述符中读数据
		参数:
			fd:文件描述符
			buf: 保存读到数据
			count: 指定读取的数据的个数
		返回值:
			0 读到文件的末尾
			成功:返回读到的字节个数 < count 
			错误:-1 errno被设置

write(2):

ssize_t write(int fd, const void *buf, size_t count);
			功能:从buf指向的缓存中写最多count个字节到fd 
			参数:fd 要写入的文件描述符
						buf 保存要写入的数据
						count 数据的个数 字节
			返回值:
						成功:成功写入的字节个数 有可能 < count
						错误:-1 errno被设置

lseek (2) :定位

off_t lseek(int fd, off_t offset, int whence); 
		功能:
				定位文件
		参数:	
				offset:
				whence:
				SEEK_SET 将文件的偏移设置到offset的位置
				SEEK_CUR 将文件的偏移设置到当前位置 + offset的位置
				SEEK_END 将文件的偏移设置到文件末尾 + offset的位置
		返回值:
				成功:返回文件的偏移位置
				错误:-1 errno被设置

close(2) :关闭

int close(int fd); 
			功能:关闭文件描述符
			参数:文件描述符
			返回值:成功 0 
			错误 -1 errno被设置
stdin 对应的文件描述符是0 
stdout 对应的文件描述符是1
stderr 对应的文件描述符是2 

系统错误处理:

errno(3)

errno -l 可以查看错误编号和它对应的错误信息

文件描述符

dup(2)

int dup(int oldfd);
功能:复制文件描述符 
  参数:oldfd, 指定了源文件描述符
	返回值:
			成功 新的文件描述符 最小的 未使用的
			错误 -1 errno被设置

dup2(2)

 int dup2(int oldfd, int newfd);  值-结果参数  传入传出 
  功能:复制文件描述符 
  参数:oldfd 指定了源文件描述符
  			newfd 指定了新的文件描述符, 如果原来已经被打开会关闭

五. 文件和目录(文件夹)

  1. 文件的状态信息

    stat filename
    

    image-20240709222715417

  2. 文件的属性信息就是文件的元数据

    1.文件的元数据和文件的数据都在硬盘存放

    大小:4096 字节(B) 一个字节由8个二进制位(bit)组成

    硬盘在分配大小是按照块分配的 :一块=512B

    文件的类型:

    • 普通 d目录文件 c字符文件 b块文件 l 链接文件 p管道文件 s socket文件

    硬链接:
    所谓的硬链接就是文件的文件名个数
    目录文件的硬链接是子目录的个数
    目录文件不允许用户构建软连接文件

    符号链接:
    也叫软连接, 存储源文件的路径, 类似快捷方式
    系统中会为每一个目录文件提供两个子目录 分别是. 和 … . 就是当前目录的硬链接
    … 就是上级目录的硬链接

    文件的拥有者和所属组
    默认创建文件的用户就是文件的拥有者 每个用户都有uid
    用户都会有一个默认的用户组 作为文件的所属组 称为gid

    3.查看文件的元数据

    ls -l filename

    image-20240709234838625

    ls -li filename
    

    image-20240709235005634

​ 第一项:文件inode编号

​ 一个文件只有一个文件编号,如果两个文件编号一样,就说明建立了硬链接

1.软链接的建立

ln -s path name

path:文件或者路径

name:软连接名字

2.硬连接的建立:

ln path name

path:文件或者路径

name:硬连接名字

删除一个硬链接文件的时候, 只是删除了文件的名字, inode节点并没有被删除

4.函数的使用

stat :

int stat(const char *pathname, struct stat *statbuf);
功能:
		获取文件的身份信息(元数据)
	参数:
		pathname:指定文件的名字 
		statbuf:  值-结果参数, 保存文件身份信息
	返回值:
		成功 0 
		错误 -1 errno被设置

getpwuid (3):获取密码

结构体:

struct passwd {
char pw_name; / username */
char pw_passwd; / user password /
uid_t pw_uid; /
user ID /
gid_t pw_gid; /
group ID */
char pw_gecos; / user information */
char pw_dir; / home directory */
char pw_shell; / shell program */

功能:
		找到密码数据库中与uid相匹配的字段
	参数:
		uid 指定要找的uid, 查找该uid的用户名字
	返回值:
		成功 返回passwd结构体的指针  NULL 没有匹配的用户信息
		错误 NULL  
#include <pwd.h>
#include <stdio.h>

int main() {
    // 假设我们想要获取 UID 为 1000 的用户信息
    uid_t user_id = 1000;
    struct passwd *pw;

    pw = getpwuid(user_id);
    if (pw != NULL) {
        printf("Username: %s\n", pw->pw_name);
        printf("Password: %s\n", pw->pw_passwd);
        printf("User ID: %ld\n", (long)pw->pw_uid);
        printf("Group ID: %ld\n", (long)pw->pw_gid);
        printf("User Info: %s\n", pw->pw_gecos);
        printf("Home directory: %s\n", pw->pw_dir);
        printf("Shell: %s\n", pw->pw_shell);
    } else {
        fprintf(stderr, "User not found with UID: %ld\n", (long)user_id);
    }

    return 0;
}

image-20240710015012923

getgrnam(3):

功能:
		返回与组名相匹配的字段	
	参数:
		name 		
	返回值:
		成功 返回group结构体的指针  NULL 没有匹配的用户信息
		错误 NULL  

组名结构体

struct group {
char gr_name; / group name */
char gr_passwd; / group password /
gid_t gr_gid; /
group ID */
char *gr_mem; / NULL-terminated array of pointers
to names of group members */

指针常量和常量指针的区别:
const char *p 常量指针
char const *p 指针常量

1.常量指针:指针本身的值不能被改变的指针。也就是说,一旦指针被初始化之后,你不能让它指向另一个地址。但是,通过这个指针所访问的数据是可以被修改的

2.指针常亮:指针指向的数据是常量,即通过这个指针所访问的数据不能被修改。但是,指针本身的值是可以改变的,也就是说,你可以让这个指针指向另一个不同的常量或数据。

六.文件锁

文件锁分为两种,读锁和写锁

1.访问文件有两种结果

加锁:1.成功,读写文件内容,读写完毕,解锁

​ 2.失败,阻塞等待

加锁函数fcntl 函数来对文件进行锁定

int fcntl(int fd, int cmd, ... /* arg */ ); 
	功能:
		操作/控制文件描述符
	参数:
		fd: 要操作的文件描述符
		cmd: 指定了对文件描述符操作的命令 
		
		文件的状态信息:
		F_GETFL 
		F_SETFL
		
		建议锁的类型:
		F_GETLK  测试锁, 并不实际加锁, 如果可以加锁, 会在l_type中返回F_UNLCK
						 如果不能加锁, 在l_pid返回持有互斥锁进程PID
		F_SETLK  设置锁, 如果锁是互斥锁(写锁), 返回-1, errno被设置 EAGAIN EACCES
		F_SETLKW 设置锁, 如果锁是互斥锁, 等待其他进程释放锁
		
	返回值:
		成功 0 
		错误 -1 errno被设置

实例:

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main() {
    int fd = open("example.txt", O_RDWR); // 打开文件,需要读写权限
    if (fd < 0) {
        perror("open");
        return 1;
    }

    // 锁定文件
    struct flock lock;
    lock.l_type = F_WRLCK;   // 写锁
    lock.l_start = 0;        // 锁的起始位置
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;          // 0 表示锁定整个文件

    if (fcntl(fd, F_SETLK, &lock) == -1) {
        if (errno == EACCES || errno == EAGAIN) {
            perror("fcntl: file is locked");
        } else {
            perror("fcntl");
        }
        close(fd);
        return 1;
    }

    // ... 对文件进行操作 ...

    // 解锁文件
    lock.l_type = F_UNLCK;
    fcntl(fd, F_SETLK, &lock);

    close(fd); // 关闭文件
    return 0;
}

读锁又叫共享锁
写锁又叫互斥锁
lock.l_len = 0; // 0 表示锁定整个文件

if (fcntl(fd, F_SETLK, &lock) == -1) {
    if (errno == EACCES || errno == EAGAIN) {
        perror("fcntl: file is locked");
    } else {
        perror("fcntl");
    }
    close(fd);
    return 1;
}

// ... 对文件进行操作 ...

// 解锁文件
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock);

close(fd); // 关闭文件
return 0;

}


读锁又叫共享锁 
	写锁又叫互斥锁 
	操作文件的类型与加锁的类型必须保持一致
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叁生花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值