【无标题】

文件描述符

文件描述符实际上是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符,进程使用它来标识打开的文件。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。

Linux系统为程序中每个打开的文件都分配一个文件描述符,文件IO操作通过文件描述符来完成。

文件描述符在形式上是一个顺序分配的非负整数。从0开始分配,依次递增。比如 0,1,2表示 stdin stdout stderr,一般最大打开的文件描述符数量为1024(0~1023)

fdopen

FILE *fdopen(int fd, const char *mode);
功能:文件IO转换成标准IO
参数;
fd: 文件描述符
mode: 打开方式
返回指:
成功:流指针
失败:NULL
例如:
int main(int argc, const char *argv[])
{
FILE *fp = fdopen(1, “w”);
fprintf(fp,“%d-%d-%d”,2023,2,15);
return 0;
}

open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//打开文件,文件已经存在
int open(const char *pathname, int flags);

//创建文件,文件不存在
int open(const char *pathname, int flags, mode_t mode);
参数:
pathname: 文件的路径名
flags: 打开方式
O_RDONLY:只读
O_WRONLY:可写
O_RDWR:读写
O_APPEND:追加
O_TRUNC:清零
O_CREAT:创建
mode: 文件的权限 0666
返回指:
成功:文件描述符fd
失败:-1

标准IO 文件IO
r O_RDONLY
r+ O_RDWR
w O_WRONLY | O_CREAT | O_TRUNC
w+ O_RDWR | O_CREAT | O_TRUNC
a O_WRONLY | O_CREAT | O_APPEND
a+ O_RDWR | O_CREAT | O_APPEND

例如:
int main(int argc, const char *argv[])
{
int fd = open(“./100.txt”, O_RDONLY | O_CREAT, 0666);//以0666权限创建100.txt,并以只读方式打开;
if(fd < 0) //if(fd == -1)
{
perror(“open”);
return -1;
}
printf(“open success!\n”);
close(fd);//关闭文件
return 0;
}

实际创建的文件权限需要经过一个公式计算得到: mode & (~umask)
以上案例为例:
mode = 0666 = 110110110
umask = 2 = 000000010
~umsk = 111111101
mode & ~umask=110110100 = 0664
0664为创建文件的实际权限;

read

ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取count字节的数据到内存
参数:
fd: 文件描述符
buf: 内存地址
count: 读取的字节数 100个字节
返回值:
成功:
>0 返回实际读取到的字节数
== 0 读到文件的末尾
失败:
<0 读取失败

例如:
int main(int argc, const char *argv[])
{
int fd = open(“./1.txt”, O_RDONLY);//以只读方式打开1.txt
if(fd < 0)
{
perror(“open”);
return -1;
}
printf(“open success!\n”);

char buf[100] = {0};
int num = 0;

while(1)
{
int n = read(fd , buf, 100);//在文本中一次读取100个字节到数组中,若读取成功返回值n为100;
if(n <0)
{
perror(“read”);
return -1;
}
else if(n == 0) //读到文件的末尾
{
break;
}

num += n; //num = num + n;

printf("n=%d\n", n);

printf("%s\n", buf);

}

printf(“num=%d\n”, num);//此时的num为文件的大小(总字节数),因此read可用返回值来求文件大小;

close(fd);

return 0;
}

write

ssize_t write(int fd, const void *buf, size_t count);
功能:把内存中的数据写入到文件中
参数:
fd: 文件描述符
buf: 内存地址
count: 写入的字节数 100个字节
返回值:
成功:返回实际写入的字节数
失败:-1

int main(int argc, const char *argv[])
{
int fd = open(“./99.txt”, O_WRONLY | O_CREAT , 0666);
if(fd < 0) //if(fd == -1)
{
perror(“open”);
return -1;
}
printf(“open success!\n”);

char buf[100] = {0};

gets(buf);

write(fd, buf, strlen(buf));//把数组中的内容写到文本中;

close(fd);

return 0;
}

综合练习:copy.c(把一个文件中的内容复制到另一个文件中)

int main(int argc, const char *argv[])
{
if(argc != 3)
{
printf(“%s file1 file2\n”, argv[0]);
return -1;
}
int fd1 = open( argv[1] , O_RDONLY);
if(fd1 < 0)
{
perror(“open”);
return -1;
}
int fd2 = open( argv[2] , O_WRONLY|O_CREAT|O_TRUNC, 0666);
if(fd2 < 0)
{
perror(“open”);
return -1;
}

printf(“open success!\n”);

char buf[100] = {0};
int num = 0;

while(1)
{
int n = read(fd1 , buf, 100);
if(n <0)
{
perror(“read”);
return -1;
}
else if(n == 0) //读到文件的末尾
{
break;
}

write(fd2, buf, n); 

num += n; //num = num + n;

printf("n=%d\n", n);

printf("%s\n", buf);

memset(buf, 0, 100);

}

printf(“num=%d\n”, num);

printf(“copy success!\n”);

close(fd1);
close(fd2);

return 0;
}

lseek

off_t lseek(int fd, off_t offset, int whence);
功能:定位文件指针
参数:
fd: 文件描述符
offset: 偏移量
100:向后偏移100个字节
-100:向前偏移100个字节
whence: 基点
SEEK_SET:文件开头
SEEK_END:文件末尾
SEEK_CUR:文件当前位置
返回值:
成功:0
失败:-1
例如:lseek(fd, 0, SEEK_END);//从文件末尾往后移动100个字节;

综合练习:加密一张图片
int main(int argc, const char *argv[])
{
int fd = open(“./1.jpg”, O_RDWR);
if(fd == -1)
{
perror(“open”);
return -1;
}
//加密图片
char buf[10] = {0};

read(fd, buf,10);//从照片文本中从头读取10个字节到数组中;

int i;
for(i=0; i<5; i++)//在数组中交换第0位和第9位的数字,第1位和第8位,以此类推;
{
buf[i] ^= buf[9-i];
buf[9-i] ^= buf[i];
buf[i] ^= buf[9-i];
}

lseek(fd, 0, SEEK_SET);//把文本指针置为开头

write(fd, buf, 10);//把交换完的数组再写会文本中,完成图片加密,再运行一次则完成照片解密,因为数组中所有的数字已回归原位;
}

【目录操作函数】

opendir

#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name);
功能:打开目录
参数:
name: 目录的路径名
返回值:
成功: DIR *
失败: NULL

readdir

struct dirent *readdir(DIR *dirp);
功能:读取目录信息
参数:
dirp: opendir的返回值
返回值:
成功: struct dirent *
失败: NULL(一直遍历,直到遍历目录完成返回NULL)

struct dirent {
ino_t d_ino; /* inode number /
off_t d_off; /
not an offset; see NOTES /
unsigned short d_reclen; /
length of this record /
unsigned char d_type; /
type of file; not supported
by all filesystem types /
char d_name[256]; /
filename */
};

closedir

int closedir(DIR *dirp);

综合案例:查看目录下的文件

int main(int argc, const char *argv[])
{
DIR *dirp = opendir(“./”);//打开根目录
if(dirp == NULL)
{
perror(“opendir”);
return -1;
}

struct dirent *p;

while(1)
{
p = readdir(dirp);
if(p == NULL) //遍历根目录完成
{
break;
}

if(strncmp(p->d_name, ".", 1) == 0)
{
	continue; //略过这次循环,继续下一次循环(不打印隐藏文件)
}

printf("%s\n", p->d_name);//打印根目录下的文件名字

}

//puts(“”); //printf(“\n”); putchar(‘\n’);

closedir(dirp);//关闭目录

return 0;
}

【文件信息函数】

stat

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

struct stat mybuf;

int stat(const char *path, struct stat *buf);
功能:得到文件的属性
参数:
path:文件路径名
buf: &mybuf

-rw-rw-r-- 1 farsight farsight 593 4月 19 09:26 01picture.c
-rw-rw-r-- 1 farsight farsight 537 4月 19 09:53 02readdir.c
-rw-rw-r-- 1 farsight farsight 161 4月 19 10:23 03stat.c
-rwxrw-rw- 1 farsight farsight 97893 4月 19 09:26 5.jfif
-rwxrwxr-x 1 farsight farsight 7357 4月 19 09:53 a.out

//查看设备号
major minor

struct stat {
dev_t st_dev; /* ID of device containing file /
ino_t st_ino; /
inode number /
mode_t st_mode; 文件的权限、文件的类型 /
protection /
nlink_t st_nlink; /
number of hard links /
uid_t st_uid; 所属用户ID /
user ID of owner /
gid_t st_gid; 所属组ID /
group ID of owner /
dev_t st_rdev; /
device ID (if special file) /
off_t st_size; 文件的大小 /
total size, in bytes /
blksize_t st_blksize; /
blocksize for filesystem I/O /
blkcnt_t st_blocks; /
number of 512B blocks allocated /
time_t st_atime; 最后一次访问时间 /
time of last access /
time_t st_mtime; 最后一次修改时间 /
time of last modification /
time_t st_ctime; 最后一次文件文件属性修改时间 /
time of last status change */
};

getpwuid

struct passwd *getpwuid(uid_t uid);
获取用户名

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 */
};

getgrgid

struct group *getgrgid(gid_t gid);
获取组名

struct group {
char gr_name; / group name */
char gr_passwd; / group password /
gid_t gr_gid; /
group ID */
char *gr_mem; / group members */
};

示例:stat.c
文件类型
{
常规文件:S_ISREG ‘-’
目录:S_ISDIR ‘d’
字符设备:S_ISCHR ‘c’
块设备:S_ISBLK ‘b’
管道:S_ISFIFO ‘p’
套接字:S_ISSOCK ‘s’
符号链接:S_ISLNK ‘l’
}

库的制作

1、什么是库
/lib/i386-linux-gnu
/usr/include

  1. 库是一种加密的二进制文件
  2. 需要被操作系统载入内存运行
  3. 相比于可执行程序,它不可以直接运行
  4. window 和 linux 都有自己的库,但是不兼容
  5. Linux系统的库有两种,1. 静态库 2. 共享库(又叫动态库)
了解: 	静态库		动态库
linux	*.a			*.so

//window 	*.lib		*.dll

2、静态库的制作和使用
1. 制作
$ gcc -c xxx.c -o xxx.o
$ ar -crs libxxx.a xxx.o

​ 静态库的命名规范:
​ 必须以lib开头,紧跟库的名字,跟扩展名 .a
​ 例如: libxxx.a

  1. 使用
    $ gcc main.c -L路径 -lxxx
    -L: 指定静态库所在的目录
    -l: 指定静态库的名字 xxx部分

  2. 运行
    $ ./a.out (7258)

优点:a.out 运行后不需要库,可以直接运行
缺点:
每个a.out都要包含库,体积较大, 浪费资源;
对程序更新,部署,发布带来麻烦;

3、动态库的制作和使用

1. 制作
	$ gcc  -fPIC  -c  xxx.c  -o  xxx.o  
	$ gcc  -shared  -o  libxxx.so    xxx.o    
	
动态库的命名规范:
	必须以lib开头,紧跟库的名字,跟扩展名 .so
	例如: libxxx.so 
  1. 使用
    $ gcc main.c -L路径 -lxxx

    $ ldd a.out # 用于查看可执行程序依赖的动态库有哪些

  2. 运行
    $ ./a.out # 会报错 (7146)

    动态库的搜索方式(3种,任意选一种):

    1. 将动态库拷贝到 /lib/ 或者 /usr/lib/
      $ sudo cp libxxx.so /usr/lib/

    2.export LD_LIBRARY_PATH=.或者so所在的路径 (临时情况)

    pwd
    cd /etc/ld.so.conf.d
    ls
    sudo vi my.conf
    添加路径
    sudo ldconfig 生效

特点:在编译时不会链接到可执行文件中,只是再其中保存一个索引,在运行时,才真正的链接(动态),因此可执行程序体积小。
优点:
a.out 体积较小, 节约资源;
只需要修改.so动态库,有利于程序的更新,部署,发布;
缺点:a.out 运行后需要库,不能直接运行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值