5、设备和文件IO 您所在的位置:网站首页 io设备管理与文件系统的区别 5、设备和文件IO

5、设备和文件IO

2023-11-17 07:32| 来源: 网络整理| 查看: 265

目录 五、设备和文件IO1、linux文件2、什么是设备文件3、系统调用4、C库的文件操作5、文件描述符fd6、open系统调用7、close系统调用8、read系统调用9、write系统调用10、文件的随机读写11、lseek系统调用12、chmod和fchmod系统调用13、chown和fchown系统调用14、mkdir系统调用15、rmdir系统调用16、目录访问(1)opendir(2)readdir(3)closedir(4)示例:目录操作 17、文件记录锁 - fcntl函数

五、设备和文件IO 1、linux文件 在Linux下“一切皆是文件”!不仅普通的文件,目录、字符设备、块设备、套接字等在unix/linux中都是以文件被对待;他们虽然类型不同,但是对其提供的却是同一套操作界面。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tQikHuXm-1588345576629)(file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml8880\wps1.png)]

linux中的设备有2种类型:字符设备(无缓存且只能顺序存取)、块设备(有缓存且可以随机存取)。每个字符设备和块设备都必须有主、次设备号,主设备号相同的设备是同类设备(同一个驱动程序)。这些设备中,有些设备是对实际存在的物理硬件的抽象,而有些设备则是内核自身提供的功能(不依赖于特定的物理硬件,又称“虚拟设备”)。每个设备在 /dev 目录下都有一个对应的文件(节点)。 cat /proc/devices 查看所有的设备,分为字符设备和块设备显示 2、什么是设备文件

设备文件是用来代表物理设备的。多数物理设备是用来进行输出或输入的,所以必须由某种机制使得内核中的设备驱动从进程中得到输出送给设备。这可以通过打开输出设备文件并且写入做到,就象写入一个普通文件。

在Linux系统下,设备文件是种特殊的文件类型,其存在的主要意义是沟通用户空间程序和内核空间驱动程序。换句话说,用户空间的应用程序要想使用驱动程序提供的服务,需要经过设备文件来达成。Linux系统所有的设备文件都位于**/dev**目录下。

ls /dev -l

stat /dev/tty 查看索引节点

Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:

系统找到这个文件名对应的inode号码通过inode号码,获取inode信息根据inode信息,找到文件数据所在的block,读出数据。

ls -i 命令可以查看文件名对应的inode号码

设备工作原理

Linux设备操作

3、系统调用 系统调用是操作系统提供给用户的一组“特殊”接口系统调用并非直接和程序员或系统管理员直接打交道,而是通过软中断的方式向内核提交请求,从而获取内核函数的服务入口(系统调用表)系统调用让系统从用户空间进入内核空间内运行,运行后将结果返回给应用程序(内核态->用户空间)

函数库调用 与 系统调用

4、C库的文件操作 函数名功能fopen( )打开文件fclose( )关闭文件fputc( )将字符写入文件中fgetc( )从文件中读取字符fread()将数据从文件中读到缓冲区fwrite()将数据从缓冲区写入文件fseek( )在文件中搜索指定位置fprintf( )操作类似于 printf(),但是用于文件fscanf( )操作类似于 scanf(),但是用于文件feof( )如果到达文件结尾,返回 trueferror( )如果出错,返回 truerewind( )将文件位置指示器重新置于文件开头remove( )删除文件fflush( )将内部缓冲区的数据写入指定文件

文件系统调用

open系统调用read系统调用write系统调用create系统调用close系统调用mkdir系统调用 5、文件描述符fd

每个进程PCB结构中有文件描述符指针,指向files_struct的文件描述符表,记录每个进程打开的文件列表

系统内核不允许应用程序访问进程的文件描述符表,只返回这些结构的索引即文件描述符ID(File Description)给应用程序

Linux系统中,应用程序通过这些文件描述符来实现让内核对文件的访问

每个进程能够访问的文件描述符是有限制的,通过#ulimit –n可以查看,默认是1024

特殊文件描述符号

标准输入STDIN_FILENO

标准输出STDOUT_FILENO

标准错误STDERR_FILENO

每个进程被加载后,默认打开0,1,2这三个文件描述符

6、open系统调用

有几种方法可以获得允许访问文件的文件描述符。最常用的是使用open()(打开)系统调用

函数原型

int open(const char *path, int flags); int open(const char *path, int flags, mode_t mode);

参数

path:文件的名称,可以包含(绝对和相对)路径lags:文件打开模式mode:用来规定对该文件的所有者,文件的用户组及系统中其他用户的访问权限

返回值

打开成功,返回文件描述符; - 打开失败,返回-1

打开文件的方式

打开方式描述O_RDONLY打开一个供读取的文件O_WRONLY打开一个供写入的文件O_RDWR打开一个可供读写的文件O_APPEND写入的所有数据将被追加到文件的末尾O_CREAT打开文件,如果文件不存在则建立文件O_EXCL如果已经置O_CREAT且文件存在,则强制open()失败O_TRUNC在open()时,将文件的内容清空

所有这些标志值的符号名称可以通过#include访问

访问权限

打开方式描述S_IRUSR文件所有者的读权限位S_IWUSR文件所有者的写权限位S_IXUSR文件所有者的执行权限位S_IRWXUS_IRUSR|S_IWUSR|S_IXUSRS_IRGRP文件用户组的读权限位S_IWGRP文件用户组的写权限位S_IXGRP文件用户组的执行权限位S_IRWXGS_IRGRP|S_IWGRP|S_IXGRPS_IROTH文件其他用户的读权限位S_IWOTH文件其他用户的写权限位S_IXOTH文件其他用户的执行权限位S_IRWXOS_IROTH|S_IWOTH|S_IXOTH

文件打开示例

#include #include #include #include #include int main() { int outfd = 0; outfd = open("myfile",O_WRONLY | O_CREAT | O_TRUNC,S_IRWXU | S_IRGRP); if(outfd == -1){ perror("fail to open file\n"); exit(-1); }else{ perror("success to open file\n"); } close(outfd); return 0; } 7、close系统调用

将进程中fd对应的文件描述表结构释放

函数原型:

int close(int fd); 函数参数: fd :要关闭的文件的文件描述符 返回值 如果出现错误,返回-1调用成功返回0 8、read系统调用

一旦有了与一个打开文件描述相连的文件描述符,只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()系统调用从该文件中读取字节

函数原型:

int read(int fd, void *buf, size_t nbytes); 参数 fd:想要读的文件的文件描述符buf: 指向内存块的指针,从文件中读取来的字节放到这个内存块中nbytes: 从该文件复制到buf中的字节个数 返回值 如果出现错误,返回 -1返回从该文件复制到规定的缓冲区中的字节数 9、write系统调用

用write()系统调用将数据写到一个文件中

函数原型:

int write(int fd,void *buf,size_t nbytes); 函数参数: fd :要写入的文件的文件描述符buf: 指向内存块的指针,从这个内存块中读取数据写入到文件中nbytes: 要写入文件的字节个数 返回值 如果出现错误,返回 -1如果写入成功,则返回写入到文件中的字节个数 #include #include #include #include #include int main() { int fd = 0,size = 0; char buf[] = "Hello world!"; fd = open("first",O_WRONLY | O_TRUNC | O_CREAT,S_IRWXU); if(fd > 0){ size = write(fd,buf,sizeof(buf)); if(size > 0){ printf("write data to file success\n"); } close(fd); } return 0; } 10、文件的随机读写 到目前为止的所有文件访问都是顺序访问。这是因为所有的读和写都从当前文件的偏移位置开始,然后文件偏移值自动地增加到刚好超出读或写结束时的位置,使它为下一次访问作好准备。有个文件偏移这样的机制,在Linux系统中,随机访问就变得很简单,你所需做的只是将当前文件移值改变到有关的位置,它将迫使一次read()或write()发生在这一位置。(除非文件被O_APPEND打开,在这种情况下,任何write调用仍将发生在文件结束处) 11、lseek系统调用 功能说明:通过指定相对于开始位置、当前位置或末尾位置的字节数来重定位 curp,这取决于 lseek() 函数中指定的位置原型: off_t lseek(int fd,off_t offset,int whence); 参数 fd:文件描述符offset:偏移量whence:搜索的起始位置 返回值 返回新的文件偏移值 whence文件位置SEEK_SET从文件开始处计算偏移SEEK_CUR从当前文件的偏移值计算偏移SEEK_END从文件的结束处计算偏移 12、chmod和fchmod系统调用

功能说明:用来改变给定路径名pathname的文件的权限位

原型:

int chmod(char *path,mode_t mode); int fchmod(int fd,mode_t mode); 返回值:调用成功返回0,失败返回-1 13、chown和fchown系统调用

功能说明:用来改变文件所有者的识别号(owner id)或者它的用户组识别号(group ID)

原型:

int chown(char *path, uid_t owner,gid_t group); int fchown(int fd, uid_t owner,gid_t group); 参数 owner:所有者识别号group:用户组识别号 14、mkdir系统调用

功能说明:用来创建一个称为pathname的新目录,它的权限位设置为mode

原型:

int mkdir(char *pathname,mode_t mode); 返回值:调用成功返回0,失败返回-1 15、rmdir系统调用

功能说明:删除一个空目录

原型:

int rmdir(char *pathname); 返回值:调用成功返回0,失败返回-1 16、目录访问 (1)opendir

功能说明:打开一个目录

原型:

DIR* opendir(char *pathname); 返回值 打开成功,返回一个目录指针打开失败,则返回 0 (2)readdir 功能说明:访问指定目录中下一个连接的细节原型: struct dirent* readdir(DIR *dirptr); 返回值: 返回一个指向dirent结构的指针,它包含指定目录中下一个连接的细节;没有更多连接时,返回NULL struct dirent { long d_ino; /* 目录i结点编号 */ off_t d_off; /* 目录文件开关至此目录进入点的位移 */ unsigned short d_reclen; /* d_name的长度 */ char d_name [NAME_MAX+1]; /* 以NULL结尾的文件名 */ } 如果调用opendir打开某个目录之后,第一次调用readdir函数,则返回的是该目录下第一个文件的信息,第二次调用readdir函数返回该目录下第二个文件的信息,依此类推。如果该目录下已经没有文件信息可供读取,则返回NULL。 (3)closedir 功能说明:关闭一个已经打开的目录原型: int closedir (DIR *dirptr); (4)示例:目录操作 #include #include #include #include #include int my_read_dir(const char *path){ DIR * dir; struct dirent *ptr; if((dir = opendir(path)) == NULL){ return -1; } while((ptr = readdir(dir)) != NULL){ printf("file name: %s\n",ptr->d_name); } closedir(dir); return 0; } int main(int argc,char *argv[]){ if(my_read_dir(argv[1]) short l_type; //锁的类型 short l_whence; //偏移量的起始位置 off_t l_start; //从l_whence的偏移量 off_t l_len; //从l_start开始的字节数 pid_t l_pid; //锁所属进程ID(一般不用) } l_type: F_RDLCK读锁、F_WRLCK写锁、F_UNLCK空锁 l_whence: SEEK_SET起始、SEEK_CUR当前、SEEK_END末尾 l_len: 为0时表示从起点开始直至最大可能位置为止

示例

#include #include #include #include #include int main(){ int fd; struct flock lock; fd = open("example",O_CREAT | O_TRUNC | O_RDWR,S_IRWXU); if(fd == -1){ printf("open file error\n"); } memset(&lock,0,sizeof(struct flock)); lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; if(fcntl(fd,F_GETLK,&lock) == 0){ if(lock.l_type != F_UNLCK){//如果有锁,不能上锁 printf("lock can not by set in fd\n"); }else{//上锁 lock.l_type = F_WRLCK; if(fcntl(fd,F_SETLK,&lock) == 0){ printf("set write lock success!\n"); }else{ printf("set write lock fail!\n"); } getchar(); //解锁 lock.l_type = F_UNLCK; fcntl(fd,F_SETLK,&lock); } } close(fd); return 0; }

如果我的文章能够帮到您,可以点个赞! 您的每次 点赞、关注、收藏 都是对我最大的鼓励!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有