Linux下的文件IO编程[通俗易懂]

Linux下的文件IO编程[通俗易懂]Linux中处处皆文件,可以通过终端命令来对文件进行操作,也可以通过编程语言(程序)来对文件进行操作。而在C语言中可以通过标准IO和文件IO对文件进行操作,上一篇文章描述了标准IO,这篇文章当然是关于文件IO的基本操作,同时给予了详细的例程和标准IO进行对比。

大家好,又见面了,我是你们的朋友全栈君。

        Linux 系统调用(system call)是指操作系统提供给用户程序的一组“特殊接口”,用户程序可以通过这组“特殊”接口来获得操作系统提供的特殊服务。
        为了更好的保护内核空间,将程序的运行空间分为内核空间和用户空间,他们运行在不同的级别上,在逻辑上是相互隔离的。在 Linux 中,用户程序不能直接访问内核提供的服务,必须通过系统调用来使用内核提供的服务。
        Linux 中的用户编程接口(API)遵循了 UNIX 中最流行的应用编程界面标准—— POSIX。这些系统调用编程接口主要是通过 C 库(libc)实现的。
        往期传送门
        史上最全的Linux常用命令汇总(超详细!超全面)收藏这一篇就够了
        Linux下标准IO的这些操作你清楚吗(内附有详细的介绍和例程)

文件I/O简介

  • POSIX(可移植操作系统接口)定义的一组函数
  • 不提供缓冲机制,每次读写操作都执行系统调用
  • 核心概念是文件描述符
  • 访问各种类型文件

文件描述符

  • 每个打开文件对应一个文件描述符
  • 文件描述符是一个非负整数,Linux为程序中每个打开的文件分配一个文件描述符
  • 文件描述符从0开始分配,依次递增
  • 文件IO操作通过文件描述符完成

注意每个程序中打开的文件系统会单独分配文件描述符,互相不影响

文件I/O与标准I/O区别

标准I/O 文件I/O
ANSIC POSIX
带缓冲(减少系统调用次数) 无缓冲(读写文件需要进行系统调用
流(FILE结构体)打开文件 文件描述符表示一个打开的文件

打开文件(open)

open函数用来创建或者打开一个文件:

#include <fcntl.h>
int open(const char *path,int oflag,...);
//参数1:打开文件路径 参数2:打开方式
  • 成功时返回文件描述符;出错时返回EOF
  • 打开文件时使用两个参数
  • 创建文件时第三个参数所指定新文件的权限
  • 只能打开设备文件

Alt

示例1:

        以只写的方式打开1.txt。如果文件不存在就创建,如果文件存在就清空。

int fd;
if((fd=open("1.txt",O_WRONLY|O_CREAT|O_TRUNC,0666))<0
{ 
   
	perror("open");
	return -1;
}
示例2:

        以读写方式打开文件1.txt。如果文件不存在则创建,如果文件存在则报错:

int fd;
if((fd=open("1.txt",O_RDWR|O_CREAT|O_EXCL,0666))<0)
{ 
   
	if(errno==EEXIST)
	{ 
   
		perror("exist error");
	}
	else
	{ 
   
		perror("other error");
	}
}

关闭文件(close)

close函数用来关闭一个打开的文件:

#include <unistd.h>
int close(int fd);
  • 成功时返回0;出错时返回EOF
  • 程序结束时自动关闭所有打开的文件
  • 文件关闭以后不能再对文件进行任何操作

读取文件(read)

       read函数用来从文件中读取数据:

#include <unistd.h>
ssize_t read(int fd,void *buf,size_t count);
  • 成功时返回实际读取的字节数;出错时返回EOF
  • 读到文件末尾时返回0
  • buf是接收数据的缓冲区
示例

       从指定的文件(文本文件)中读取内容并统计大小

#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{ 
   
	int fd,n,total=0;
	char buff[64];
	if(argc<2){ 
   
		prinff("Usage:%s<file>\n",argv[0];
		return -1;
	}
	if((fd=open(argv[1],O_RDONLY))<0){ 
   
		perror("open";
		return -1;
	}
	while((n=read(fd,buf,64))>0){ 
   //读取64个字节到buf中并保存返回值到n
		total+=n;//total的值即为文件的大小
	}
	printf("size:%d\n",total);
	return 0;
}

写入文件(write)

       write函数用来向文件写入数据:

#include <unistd.h>
ssize_t write(int fd,void *buf,size_t count);//buf写入内容;count写入大小
  • 成功时返回实际写入的字节数;出错时返回EOF
  • buf是发送数据的缓冲区
  • count不应超过buf的大小
示例

       将键盘输入的内容写入文件,直到输入quit结束:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{ 
   
	int fd;
	char buf[20];
	//只写方式打开文件,如果文件不存在创建,如果文件存在则清空
	if((fd =open(argv[1],O_WRONLY|OCREAT|O_TRUNC,0666))<0{ 
   
		perror("open");
		return -1;
	}
	while(fgets(buf,20,stdin)!=NULL){ 
   
		if(strcmp(buf,"quit\n")==0)break;
		write(fd,buf,strlen(buf));
	}

定位文件(lseek)

       lseek函数用来定位文件:

#include <unistd.h>
off_t lseek(int fd,off_t offset,intt whence);
  • 成功时返回当前文件的读写位置;出错时返回EOF
  • 参数offset和参数whence同fseek完全一样

访问目录(opendir/readdir)

       opendir函数用来打开一个目录文件

#include <dirent.h>
DIR *opendir(const char *name);
  • DIR是用来描述一个打开的目录文件的结构体类型
  • 成功时返回目录流指针;出错时返回NULL

       readdir函数用来读取目录流中的内容

#include <dirent.h>
struct sirent *readdir(DIR *dirp);
  • struct dirent是用来描述目录流中一个目录项的结构体类型
  • 包含char d_name[256]等成员
  • 成功时返回目录流dirp中下一个目录项
  • 出错或到末尾时返回NULL

关闭目录(closedir)

       closedir用来关闭一个目录文件:

#include <dirent.h>
int closedir(DIR *drip);
示例:

       打印指定目录下所有文件的名称:

#include <stdio.h>
#include <dirent.h>
int main(int argc,char *argv[])
{ 
   
	DIR *drip;
	struct dirent *dp;
	if(argc<2){ 
   
		printf("Usage :%s<directory>\n"argc[0]);return -1;
	}
	if((dirp=opendir(argv[1]))==NULL){ 
   
		perror("opendir");
		return -1;
	}
	while((dp=readdir(dirp))!=NULL){ 
   
		printf("%s\n",dp->d_name);
	}
	closedir(dirp);
	return 0;
}

修改文件属性(chmod/fchmod)

       chmod/fchmod函数用来修改文件的访问权限:

#include <sys/stat.h>
int chmod(const char *path,mode_t mode);
int fchmod(int fd,mode_t mode);
  • 成功时返回0;出错时返回EOF
  • root和文件所有者能修改文件的访问权限

获取文件属性(stat/lstat/fstat)

#include <stdio.h>
int stat(const char *path,struct stat *buf);
int lstat(const char *path,struct stat *buf);
int fstat(int fd,struct stat *buf);
  • 成功时返回0;出错时返回EOF;
  • 如果path是符号链接stat获取的是目标文件的属性;而lstat获取的是链接文件的属性

struct stat是存放文件属性的结构体类型:

结构体类型 作用
mode_t st_mode 类型和访问权限
uid_t st_uid 所有者id
uid_t st_gid 用户id
off_t st_size 文件大小
time_t st_mtime 最后修改时间

st_mode通过系统提供的宏来判断文件类型:
通过(st_mode&0170000)计算后得到的值和以下进行匹配

文件类型 计算值
S_ISREG(st_mode) 普通文件 0100000
S_ISDIR(st_mode)目录文件 0040000
S_ISCHR(st_mode) 0020000
S_ISBLK(st_mode) 0060000
示例

       获取并显示文件属性:

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc,char *argv[])
{ 

struct stat buf;
struct tm *tp;//获取本地时间的指针
int n;
if(argc<2)
{ 

printf("Usage:%s <file>\n",argv[0]);
return -1;
}
if(lstat(argv[1],&buf)<0)
{ 

perror("lstat");
return -1;
}
switch(buf.st_mode&S_IFMT)
{ 

case S_IFRGE:
printf("-");
break;
case S_IFDIR:
printf("d");//是一个目录文件
break;
}
for(n=8;n>=0;n--)
{ 

if(buf.st_mode&(1<<n))
{ 

switch(n%3)
{ 

case 2:
printf("r");
case 1:
printf("w");
break;
case 0:
printf("x");
break;
}
}
else
{ 

printf("-");			
}
}
printf("%lu",buf.st_size);
tp=localtime(buf.st_mtime);//转换为本地时间
printf("%d-%02d-%02d",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday);//年月日 天数
printf("%s\n",argc[1]);
return 0;
}

        不积小流无以成江河,不积跬步无以至千里。而我想要成为万里羊,就必须坚持学习来获取更多知识,用知识来改变命运,用博客见证成长,用行动证明我在努力。
       如果我的博客对你有帮助、如果你喜欢我的博客内容,记得“点赞” “评论” “收藏”一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/131846.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Spatial Dropout

    Spatial DropoutSpatialDropout是Tompson等人在图像领域提出的一种dropout方法。普通的dropout会随机地将部分元素置零,而SpatialDropout会随机地将部分区域置零,该dropout方法在图像识别领域实践证明是有效的。dropoutdropout是怎么操作的?一般来说,对于输入的张量x,dropout就是随机地将部分元素置零,然后对结果做一个尺度变换。比如,我们随机初始化一…

  • python进制转换代码_十进制转八进制python

    python进制转换代码_十进制转八进制python本文实例讲述了Python实现的十进制小数与二进制小数相互转换功能。分享给大家供大家参考,具体如下:十进制小数⇒二进制小数乘2取整对十进制小数乘2得到的整数部分和小数部分,整数部分即是相应的二进制数码,再用2乘小数部分(之前乘后得到新的小数部分),又得到整数和小数部分。如此不断重复,直到小数部分为0或达到精度要求为止.第一次所得到为最高位,最后一次得到为最低位如:0.25的二进制0.25*2=…

  • linux vim查看下一页,linuxVIM基本命令大全介绍(2)

    linux vim查看下一页,linuxVIM基本命令大全介绍(2)在vi中添加文本命令插入动作a在光标后插入文本A在当前行尾插入文本i在光标前插入文本I在当前行前插入文本o在当前行的下边插入新行O在当前行的上边插入新行s删除光标所在处字符,并进入插入模式S删除光标所在的行,并进入插入模式:rfile读入文件file内容,并插在当前行后:nrfile读入文件file内容,并插在第n行后Esc回到命令模式在vi中删除文…

  • 笔记本计算机运行程序,这几招让你的笔记本电脑运行速度变快 必学技巧「建议收藏」

    笔记本计算机运行程序,这几招让你的笔记本电脑运行速度变快 必学技巧「建议收藏」很多电脑用户一直都被电脑慢的问题困扰着,而电脑大神根本不把电脑慢当做电脑问题,因为让电脑变快的方法有很多,而且操作都巨简单。提高电脑速度的方法也能很多而且很容易操作,一切的难,只是来源于你没有学过而已,现在就跟着小编来学那些简单又使用的电脑技能吧。让电脑速度快10倍,大概会让人觉得很不可思议吧,而实际上,你羡慕的大神可能也只是因为学会了下面的12种提高电脑速度的方法:1、定期的,对电脑内的灰尘进行…

  • python的三种取整方式_python取整函数-取整函数,PYTHON[通俗易懂]

    python的三种取整方式_python取整函数-取整函数,PYTHON[通俗易懂]本教程分享:《python取整函数》,python有什么办法使得int按照”四舍五入”的方式取…由于小数取整会采用比较暴力的截断方式,即向下取整,所以要想使得int()按照“四舍五入”的方式取整,可以采用如下方法:5.4“四舍五入”结果为:5,int(5.4+0.5)==55.6“四舍五入”结果为:6,int(5.6+0.5)==6python为什么算除法自动取整了。如图…

    2022年10月27日
  • 理解rem实现响应式布局原理及js动态计算rem「建议收藏」

    理解rem实现响应式布局原理及js动态计算rem

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号