Linux C文件操作

news2025/6/24 13:19:46

文章目录

    • 文件操作函数
    • 文件系统调用
    • 系统调用与标准函数c的调用的区别
    • 文件的读取位置
      • 标准c函数
      • 系统调用
      • 空洞文件
    • 文件的内存映射操作
    • 文件目录

linux下的文件操作包括两种,一种是使用C函数,一种是使用系统调用。

  • gcc 常用来实现c程序的编译
  • gcc filename.c 编译,链接(自动)后输出可执行文件a.out
  • 只是输入./a.out就可以执行filename程序
  • gcc -o filename filename.o 可以生成一个filename的可执行文件,直接执行filename就可以直接执行代码中的内容(与上一条相比,只是执行输出的名称)
  • gcc -S filename.c 可以生成一个filaname.s的汇编文件,汇编文件与底层执行时一一对应的,可以用来调试
  • gcc -O 可以用来编译优化,但是不是所有情况下都可以做编译优化。
  • 还可以使用gcc -c filename.cgcc -o filename filename.o分步编译、链接

文件操作函数

文件操作函数包括fopen、fgetc、fputc函数等,这是标准的C函数

// 把file.in中给的内容输出给file.out
#include<stdio.h>
#include<stdlib.h>

int main(){
	int c;
	FILE *in,*out;//定义两个文件指针类型
	in=fopen("file.in","r");//以只读的方式打开file.in文件,成功后返回文件指针in
	out=fopen("file.out","w");//以只写的方式打开file.out文件,成功后返回文件out
	while((c=fgetc(in))!=EOF)//从in文件中读,把读出来的数据写到out中
		fputc(c,out);
	fclose(in);
	fclose(out);
	exit(0);
}
  • FILE * fopen(char *path,char *mode),第一个参数表示路径,第二个参数表示模式,fopen的返回值是一个文件指针,如果文件打开失败则返回一个NULL,可以使用fclose()函数关闭文件:

    • 模式包括<r,w,a>
    • r表示以只读的方式打开,文件指针指向了文件的起始位置,r表示的文件必须存在。
    • w表示以写入的方式打开,如果文件不存在则创建文件,如果文件存在则先清空文件。
    • a表示以追加模式打开,对一个文件的写入,如果文件不存在就创建文件,如果文件存在就在文件末尾追加内容。
    • 如果后面有+表示可读写;
    • 如果后面有b表示打开的是二进制文件
    • 如果后面有t表示打开的是文本文件。
  • char *fgets(char *s,int size,FILE *stream)表示从指定的文件中读下一个字符,返回一个没有符号的字符,或者EOF(end of file),需要读的文件必须是读或者读写的方式打开的,并且文件存在。

  • fputc(char c,FILE * fp)把内容写入到指定文件。

  • 可以使用diff file.in file.out比较两个文件的内容,没有输出表示两个文件一模一样。

  • fclose,最重要的是把文件从内存中写回磁盘。

为了程序的健壮性,可以把以上的文件改为以下,防止读的文件没有权限或者不存在

// 把file.in中给的内容输出给file.out
#include<stdio.h>
#include<stdlib.h>

int main(){
	int c;
	FILE *in,*out;//定义两个文件指针类型
	if((in=fopen("file.in","r"))==NULL){//以只读的方式打开file.in文件,成功后返回文件指针in
		print("file.in文件不存在!")
		return 0;
	}
	out=fopen("file.out","w");//以只写的方式打开file.out文件,成功后返回文件out
	while((c=fgetc(in))!=EOF)//从in文件中读,把读出来的数据写到out中
		fputc(c,out);
	
	exit(0);
}

文件系统调用

文件描述符以及open、read、write

#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>

int main(){
	char block[1024];
	int in,out;
	int nread;
	
	if((in=open("file.in",O_RDONLY))==-1){// 3
		print("文件打开错误!");
		return 0;}
	out=open("file.out",O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR);// 4
	while((nread=read(in,block,sizeof(block)))>0)
		write(out,block,nread);

	return 0;
}
  • int open(constchar*pathname,int flags,mode_t mode);如果成功则返回一个文件描述符(integer,小的非负整数且没有被使用过),否则返回-1;对于open函数来说,第三个参数当且仅当创建新文件(使用O_RDONLY)才是用,用于指定文件的访问权限,比如权限为777;pathname表示要打开或者创建的文件的路径名;flags表示指定文件的打开模式,flags的值包括以下,打开或者创建文件时,至少要使用一个以下命令:

    • O_RDONLY:只读模式
    • O_WRONLY:只写模式
    • O_RDWR:读写模式
    • O_CREAT:文件不存在时创建文件
  • mode的值包括以下

    • S_IRUSR:允许文件的所有者阅读它
    • S_IWUSR:允许文件所有者写它
    • S_IRGRP:允许文件组读取它
    • S_IWGRP: 允许文件组编写它

linux下任何一个进程都有3个默认打开的文件描述符:0表示标准输入(键盘),1表示标准输出(显示器),2表示标准错误输出(显示器)

  • ssize_t read(int fd, void *buf, size_t count);表示读取指定字节数的数据到缓冲区buff中,同时文件的当前位置向后移动;读取成功返回读取的字节数,出错返回-1并且设置errno,如果在调用read之前已经到达文件末尾则返回0(例如,距文件末尾还有30个字节而请求读100个字节,则read返回30,下次read将返回0);

  • ssize_t write(int fd, const void *buf, size_t count); 成功返回写入的字节数,出错返回-1并设置errno写常规文件时

系统调用与标准函数c的调用的区别

使用time 文件路径,可以知道文件运行所需要的时间
使用scrace 文件路径,可以跟踪文件

  • 使用fgetc或者fputc的时候,它底层的调用还是调用了read和write,但是在读取的时候做了一个系统的优化,也就是一次性读取了多个字节的内容,表面上看起来只读取一个字符,实际上底层中读取的是多个字节的字符。

  • 注意系统调用这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置。比如用fgetc读一个字节,fgetc有可能从内核中预读1024个字节到I/O缓冲区中,再返回第一个字节,这时该文件在内核中记录的读写位置是1024,而在FILE结构体中记录的读写位置是1

文件的读取位置

标准c函数

标准的c函数中,不可以对FILE的文件指针直接进行++,–,可以使用fseek函数来控制文件的读写指针。

  • int fseek(FILE *stream, long offset, int fromwhere);重定位流上的文件指针,函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere为基准,偏移offset个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置;返回值: 成功,返回0,否则返回其他值;第一个参数stream为文件指针;第二个参数offset为偏移量,整数表示正向偏移,负数表示负向偏移;第三个参数origin设定从文件的哪里开始偏移,可能取值为:

    • SEEK_SET: 文件开头,用0表示
    • SEEK_CUR: 当前位置,用1表示
    • SEEK_END: 文件结尾,用2表示
  • fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;
    fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;
    ffseek(fp,-100L,2);把fp指针退回到离文件结尾100字节处。

系统调用

系统调用使用lseek来调用文件的文件位置,与c函数调用相比,c文件调用使用的是文件指针,而系统调用使用的是文件描述符号

  • off_t lseek(int fd, off_t offset, int whence);fd表示函数描述符,参数含义与上面的c函数调用一致。

空洞文件

可以使用以上的fseek和lseek去创建一个空洞文件
① 空洞文件就是这个文件有一段是空的;
② 普通文件中间不能有空,write文件时从前往后移动文件指针,依次写入;
③ 用lseek往后跳过一段,就形成空洞文件;
④ 空洞文件对多线程共同操作文件非常有用。需要创建一个很大文件时,从头开始依次创建时间很长,可以将文件分成多段,多个线程操作每个线程负责其中一段的写入。

文件的内存映射操作

  • mmap是一种内存映射文件的方法,即将一个文件或者其他的映射对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟控件中一段虚拟地址的映射关系。实现这种映射关系之后,进程可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,也就是对文件的操作不必调用read或者write等系统调用函数,相同的,在内核空间内这一段的区域也直接改为用户空间,从而实现不同进程的文件的共享。
  • 使用mmap进行映射,会得到一个磁盘和某一个文件的地址相同的地址,当往这个地址写内容的时候,内容会直接写到文件中,比正常的系统调用要少一次拷贝的过程。
  • 正常调用写文件的流程图
    在这里插入图片描述

  • mmp内存映射写文件的流程图
    在这里插入图片描述

  • void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)第一个参数表示映射的地址,如果地址设置为NULL,内核会自动挑一个地址来进行映射;第二个参数表示映射有多长;第三个参数描述了要求的内存保护,包括PROT_EXEC,PROT_READ,PROT_WRITE,PROT_NONE;最后一个参数表明如果对内存进行修改能否被其他的进程看到,包括MAP_SHARED和MAP_PRIVATE。

#include<stdio.h>
#include<unistd.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<stdlib.h>

typedef strucy{
	int integer;
	char string[24];
}RECORD;

#define NRECORDS(100)

int main(){
	RECORD record,*mapped;
	int i,f;
	FILE *fp;
	
	fp=fopen("records.dat","w+");
	for(i=0;i<NRECORDS;i++){
		record.integer=i;
		sprintf(record.string,"RECORD-%d",i);
		fwrite(&record,sizeof(record),1,fp);//写record的数据,长度为record的大小,写一次,写到fp文件中
	}
	fclose(fp);
	
	fp=fopen("records.dat","r+");
	fseek(fp,43*sizeof(record),SEEK_SET);
	fread(&record,sizeof(record),1,fp);
	//修改fp的数据
	record.integer=143;
	sprintf(record.string,"RECORD-%d",record.integer);
	
	//修改后写回
	fseek(fp,-1*sizeof(record),SEEK_CUR);
	fwrite(&record,sizeof(record),1,fp);
	fclose(fp);

	//----------------------------------------------------------
	//使用mmap
	f=open("records.dat",O_RDWR);
	mapped=(RECORD *)mmap(0,NRECORDS*sizeof(record),PROT_RDAD|PROT_WRITE,MAP_SHARED,f,0);//第一个参数0表示内核挑选映射的地址;第二个参数表示映射的大小;第三个参数表示权限,可读可写;第四个参数表示可以共享;第五个参数表示被映射的文件;第六个参数表示映射从文件起始的位置开始的偏移量。执行完成后,整个文件全部映射到内存中,相当于一个数组mapped
	mapped[43],integer=243;
	sprintf(mapped[43].string,"RECORD-%d",mapped[43].integer);//操作数组一样操作内存
	msync((void*)mapped,NRECORDS*sizeof(record),MS_ASYNC);//把内存和辅存中的文件同步起来
	munmap((void*)mapped,NRECORDS*sizeof(record));//解开映射
	close(f);
	
	return 0;
}

文件目录

文件目录对应的是文件的属性信息,FCB文件控制块,存放文件的属性信息;文件的属性信息与文件的实体不是存在在一个位置上的,把文件的属性信息存放在一个位置,这一类的文件叫做目录文件,也就是windows上的文件夹

#include<unistd.h>
#include<stdio.h>
#include<dirent.h>
#include<string.h>
#include<sys/stat.h>
#include<stdlib.h>

void printdir(char *dir,int depth){
	DIR *dp;
	struct dirent *entry;
	struct stat statbuf;
	if((dp=opendir(dir))==NULL){
		fprintf(stderr,"cannot open directory:%s\n",dir);
		return;
	}
	chdir(dir);
	while((entry=readdir(dp))!=NULL){
		lstat(entry->d_name,&statbuf);
		if(S_ISDIR(statbuf.st_mode)){
			if(strcmp(".",entry->d_name)==0||strcmp("..",entry->d_name)==0)
				continue;
		printf("%*s%s/\n",depth,"",entry->d_name);
		printdir(entry->d_name,depth+4);//递归调用,深度优先搜索
		}
		else printf("%*s%s\n",depth,"",entry->d_name);
	}
	chdir("..");
	closedir(dp);
}

int main(){
	printf("Directory scan of /home:\n");
	printdir("/home",0);
	printf("done\n");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1086091.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java正则表达式 及应用场景爬虫,捕获分组非捕获分组

正则表达式 通常用于校验 比如说qq号 看输入的是否符合规则就可以用这个 public class regex {public static void main(String[] args) {//正则表达式判断qq号是否正确//规则 6位及20位以内 0不能再开头 必须全是数子String qq"1234567890";System.out.println(qq…

vscode利用lauch.json和docker中的delve调试本地crdb

---- vscode利用delve调试crdb 创建了一个delve容器用于debug crdbdelve&#xff1a; Delve是一个用于Go编程语言的调试器。它提供了一组命令和功能&#xff0c;可以帮助开发人员在调试过程中检查变量、设置断点、单步执行代码等操作。Delve可以与Go程序一起使用&#xff0c;…

自定义spring-boot-starter

自定义加载spring-boot-starter 第一步 创建一个Maven空项目 luban-spring-boot-starter 引入基础依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.5.0</ve…

Linux下安装DM8

上传iso文件到服务器 文件路径放在 /works/tools/dm8_20230511_x86_rh6_64.iso mount镜像文件 执行mount命令 mkdir /mntdm8mount -t iso9660 /works/tools/dm8_20230511_x86_rh6_64.iso /mntdm8cd /mntdm8 创建数据库用户 groupadd dinstalluseradd -g dinstall -m -d …

测试面试官会做些什么?

虽然没有了金九银十&#xff0c;但是公司的测试HC&#xff08;headcount&#xff0c;指公司HR预计招聘的员工人数&#xff09;还是没有完全锁死&#xff0c;断断续续的也在帮着面试一些人。本文就以自己的经验&#xff0c;从面试官的角度&#xff0c;聊聊面试测试过程中的那些事…

【C/C++】STL——深度剖析list容器

​&#x1f47b;内容专栏&#xff1a; C/C编程 &#x1f428;本文概括&#xff1a;list的介绍与使用、深度剖析及模拟实现。 &#x1f43c;本文作者&#xff1a; 阿四啊 &#x1f438;发布时间&#xff1a;2023.10.12 一、list的介绍与使用 1.1 list的介绍 cpluplus网站中有关…

fastjson-BCEL不出网打法原理分析

FastJson反序列化漏洞 与原生的 Java 反序列化的区别在于&#xff0c;FastJson 反序列化并未使用 readObject 方法&#xff0c;而是由 FastJson 自定一套反序列化的过程。通过在反序列化的过程中自动调用类属性的 setter 方法和 getter 方法&#xff0c;将JSON 字符串还原成对…

低代码提速应用开发

低代码介绍 低代码平台是指一种能够帮助企业快速交付业务应用的平台。自2000年以来&#xff0c;低代码市场一直充斥着40大大小小的各种玩家&#xff0c;比如国外的Appian、K2、Pega Systems、Salesforce和Ultimus&#xff0c;国内的H3 BPM。 2015年以后&#xff0c;这个市场更是…

《3D 数学基础》几何检测-相交性检测

目录 1. 2D直线相交 2. 3D射线相交点 3. 射线和平面的交点 4. 3个平面的交点 5. 射线和圆或者球交点 6. 两个圆或者球是否相交 7. 球和平面的相交性检测 8. 射线和AABB的相交性&#xff08;13.17&#xff09; 9. 射线和三角形的相交性&#xff08;13.16&#xff09; …

visual studio设置主题和背景颜色

visual studio2019默认的主题有4种&#xff0c;分别是浅白色、深黑色、蓝色、蓝(额外对比度)&#xff0c;背景颜色默认是纯白色RGB(255,255,255)。字体纯白色看久了&#xff0c;眼睛会感到酸痛、疲劳&#xff0c;建议改成浅白RGB(250,250,250)、豆沙绿RGB(85,123,105)、透明蓝白…

为什么要用回馈式电子负载

回馈式电子负载主要作用是模拟真实负载情况下的电流和电压变化&#xff0c;它在电子设备的开发、测试和调试过程中起到重要的作用。回馈式电子负载可以模拟各种负载条件&#xff0c;包括不同的电流和电压变化&#xff0c;这对于测试和验证电子设备的性能非常重要&#xff0c;可…

ios UI 基础开发一

目录 第一节&#xff1a;基础库 第二节&#xff1a;弹出模拟器的键盘 第三节&#xff1a;模拟器回到桌面 第四节&#xff1a;Viewcontroller 与 View 的关系 第五节&#xff1a;快捷键 第六节&#xff1a;键盘召回 ​第七节&#xff1a;启动流程xcode介绍 第八节&#xf…

英国金融科技公司【kennek】完成1250万美元融资

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于英国伦敦的金融科技公司kennek今日宣布已完成1250万美元种子轮融资。 本轮融资由HV Capital领投&#xff0c;荷兰创始人基金、AlbionVC、FFVC、Plug Play Ventures和Syndicate One参与。 …

java Maven入门笔记

后端Web开发技术的学习&#xff0c;我们要先学习Java项目的构建工具&#xff1a;Maven 目录 Maven概述Maven介绍及其作用Maven模型介绍Maven仓库Maven安装 IDEA集成Maven配置Maven环境当前工程设置全局设置 Maven项目创建Maven项目POM配置详解Maven坐标详解 导入Maven项目 依赖…

脂质代谢+预后模型+WGCNA+单细胞多种要素分析

今天给同学们分享一篇脂质代谢预后模型WGCNA单细胞的生信文章“A Novel Lipid Metabolism and Endoplasmic Reticulum Stress-Related Risk Model for Predicting Immune Infiltration and Prognosis in Colorectal Cancer”&#xff0c;这篇文章于2023年9月8日发表在Int Mol S…

在服务器上解压.7z文件

1. 更新apt sudo apt-get update2. 安装p7zip sudo apt-get install p7zip-full3. 解压.7z文件 7za x WN18RR.7z

ETL数据转换方式有哪些

ETL数据转换方式有哪些 ETL&#xff08;Extract&#xff0c; Transform&#xff0c; Load&#xff09;是一种常用的数据处理方式&#xff0c;用于从源系统中提取数据&#xff0c;进行转换&#xff0c;并加载到目标系统中。 数据清洗&#xff08;Data Cleaning&#xff09;&am…

github 中关于Pyqt 的module view 操作练习

代码摘自&#xff0c;Pyside6 中的示例代码部分 # -*- coding: utf-8 -*- import sys from PySide6.QtWidgets import * from PySide6.QtGui import * from PySide6.QtCore import * from PySide6.QtSql import QSqlDatabase, QSqlQueryModel, QSqlQuery import os os.chdir(os…

C++学习——“面向对象编程”的涵义

以下内容源于C语言中文网的学习与整理&#xff0c;非原创&#xff0c;如有侵权请告知删除。 类是一个通用的概念&#xff0c;C、Java、C#、PHP 等很多编程语言中都支持类&#xff0c;都可以通过类创建对象。我们可以将类看做是结构体的升级版&#xff0c;C语言的晚辈们看到了C…

Linux网络编程:UDP协议和TCP协议

目录 一. 对于端口号的理解 1.1 网络通信五元组 1.2 端口号的划分策略 二. 网络通信中常用的指令 2.1 netstat指令 2.2 pidof指令 三. udp协议 3.1 udp的概念及特点 3.2 udp协议端格式 3.3 对于面向数据报及应用层发送与读取数据的理解 四. tcp协议的概念及特点 五.…