学习C(十七)

文件IO

一般用到文件操作时,主函数都加上参数(int argc,char** argv)
  到目前位置,我们将所有数据存储在内存中。内存中的数据虽然读取速度非常快,但是一旦程序结束或者意外中断,内存中的数据全都丢失。
  为了解决这个问题,我们通常就会在程序结束之前将内存中的数据写入到文件中去,这个操作就叫文件IO(in and out)

第零组:sprintf/sscanf(字符串间的读取)

sprintf,指定内存数据按格式输出到字符串中

sprintf的使用方法

#include<stdio.h>

//sprintf可以在内存和内存之间复制数据
int main(){
	char buf[512] = "123 456";
	char temp[512] = {0};
	sprintf(temp,"%s",buf);
	//将指针常量buf所指的一段栈内存数据,按照%s的格式复制到指针常量temp所指的一段栈内存空间中,包括空格
	printf("%s\n",temp);//输出:123 456
	return 0;
}

sscanf,从字符串中数据按格式读取到指定内存

sscanf的使用方法

#include<stdio.h>

//ssanf可以在内存和内存之间复制数据
//sscanf():从一个字符串中读进与指定格式相符的数据. 
int main(){
	char buf[512] = "123 456";
	char temp[512] = {0};
	int a = 0;
	char b = 0;
	//将指针常量buf所指的一段栈内存数据,按照%s的格式复制到指针常量temp所指的一段栈内存空间中。注意:遇到空格停止复制。
	sscanf(buf,"%s",temp);
	sscanf(buf,"%d",&a);
	sscanf(buf,"%c",&b);
	printf("%s-%d-%c\n",temp,a,b);//输出:123-123-1
	return 0;
}

第一组:fprintf/fscanf(全读取)

fprintf和fscanf的函数声明的原型是一样的,功能不一样
函数名:fopen
  函数参数:const char* path,char* mod
  返回值:返回一个指向了文件path 文件描述符
  解释: path:具体路径下的文件名。
     mod:该文件的打开方式:
       r:以只读方式打开文件,如果文件不存在,则打开失败。打开文件后,光标处于文件的开头位置
       r+:以读写的方式打开文件,如果文件不存在,则打开失败。打开文件后,光标处于文件的开头位置
       w:以只写的方式打开文件,如果文件不存在,则创建文件后打开,打开文件后,光标处于文件的开头位置
       w+:以读写的方式打开文件,如果文件不存在,则创建文件后打开,打开文件后,光标处于文件的开头位置
       a:以添加的方式打开文件,如果文件不存在,则创建文件后打开,打开文件后,光标处于文件的末尾位置
       a+:以添加和读取的方式打开文件,如果文件不存在,则创建文件后打开,打开文件后,光标处于文件的末尾位置
       b(bin):以二进制的形式打开文件
   只要该文件在一次fopen和fclose之内,他的光标位置总是向后走的

fprintf,将指定内存数据输出到文件中

函数名:fprintf
  函数参数:FILE* stream, const char* format, [argument]
  解释:FILE* fp 为一个文件指针,他能完全代表被他指向的文件,我们把这样的一个文件指针称为文件描述符
  函数功能:将 str中所有的内容写入到fp所代表的文件中去
  函数返回值:返回值是写入文件的字符个数,失败返回-1
  
  那么如何确定fp的指向
  使用函数fopen来确定fp的指向

#include<stdio.h>

//把内存中的数据输出到指定文件中
int main(int argc,char** argv){
	char buf[20] = "你好,中国";
    //FILE* 为声明定义一个文件描述符
    //函数fopen返回值为文件描述符
	FILE* fp = fopen("./test.txt","w");//w为只写的方式打开文件,打开文件后光标处于文件的开头位置
	fprintf(fp,"%s\n",buf);//把内存中的数据输出到文件中
	fclose(fp);
	return 0;
}

fscanf,从文件中读取数据到指定内存

函数名:fscan
  函数参数:FILE * stream, const char * format, [argument…]
  函数功能:根据数据格式(format),从输入流(stream)中读入数据,存储到argument中,遇到空格和换行时结束。
  函数返回值:整型,成功返回读入的参数的个数,失败返回EOF(-1)。

#include<stdio.h>

//从文件中读取数据到指定内存中
int main(int argc,char** argv){
	char buf[20] = "你好,中国";
    //FILE* 为声明定义一个文件描述符
    //函数fopen返回值为文件描述符
	FILE* fp = fopen("./test2.txt","r");//r为只读的方式打开文件,打开文件后光标处于文件的开头位置
	int retval = 0;
	while(1){
		retval = fscanf(fp,"%s",buf);//从文件中读取数据到指定内存中,遇到空格和换行时结束
        //此时文件中的光标停在空格或换行符的后面
		if(retval==-1){break;}//当文件读取完或出差错时返回-1
		printf("%s\n",buf);
	}
	fclose(fp);
	return 0;
}

使用fprintf和fscanf完成学生数组的加载保存

/*
	编写一个加载保存学生信息的程序:
	要求:先手动完善3个学生的信息,然后将3个学生添加入数组中。
		将整个数组保存到文件中去
		从文件中读取所有信息进入整个数组

		要求:当第一次运行完成个程序后,第二次再次运行程序,同名学生添加失败
		学生信息有:姓名,年龄,成绩,要求姓名唯一
*/
#include<stdio.h>
#include<string.h>

typedef struct Stu{
	char name[20];
	int age;
	int score;
}stu_t;

//函数参数:stu_t* DB,int* len
//函数功能:添加学生信息到数组中
void insertStu(stu_t* DB,int* len){
	char name[20] = {0};
	int age = 0;
	int score = 0;
	printf("请输入学生的姓名,年龄及分数:\n");
	scanf("%s %d %d",name,&age,&score);
	while(getchar()!=10);
	stu_t st = {0};
	strcpy(st.name,name);
	st.age = age;
	st.score = score;
	DB[*len] = st;//结构体之间整体赋值
	(*len)++;
}

//函数参数:stu_t* DB,int len
//函数功能:将整个学生数组保存到文件中
void saveStu(stu_t* DB,int len){
	FILE* fp = fopen("./stuDB.txt","w");
	for(int i=0;i<len;i++){
		fprintf(fp,"%s %d %d\n",DB[i].name,DB[i].age,DB[i].score);
	}
	fclose(fp);
}

//从文件中读取所有信息进入整个数组
void loadStu(stu_t* DB,int* len){
	FILE* fp = fopen("./stuDB.txt","r");
	if(fp == NULL){return;}
	int retval = 0;
	while(1){
		retval = fscanf(fp,"%s %d %d",DB[*len].name,&DB[*len].age,&DB[*len].score);
		if(retval == -1){break;}
		(*len)++;
	}
	fclose(fp);
}

//打印学生信息
void printStu(stu_t* DB,int len){
	int i = 0;
	for(i=0;i<len;i++){
		printf("***********\n");
		printf("姓名:%s\n",DB[i].name);
		printf("年龄:%d\n",DB[i].age);
		printf("成绩:%d\n",DB[i].score);
	}
	printf("***********\n");
}

int main(int argc,char** argv){
	stu_t DB[512] = {0};//结构体数组
	int len = 0;
	loadStu(DB,&len);
	insertStu(DB,&len);
	insertStu(DB,&len);
	insertStu(DB,&len);
	saveStu(DB,len);
	printStu(DB,len);
	return 0;
}

第二组:fputs/fgets(小段读取)

fputs和fgets的函数声明的原型是一样的,功能不一样
fputs和fgets属于行读取,他只会把一行的内容放入缓存区

fputs

函数名fputs
  函数参数:const char *str, FILE *stream
  函数功能:把字符串(str)写入到指定的流( stream) 中,但不包括空字符。指定的文件写入一个字符串(不自动写入字符串结束标记符‘\0’)。成功写入一个字符串后,文件的位置指针会自动后移
  函数返回值:返回值为非负整数,出错则返回EOF(符号常量,其值为-1)。

简单理解就是把内存中的数据按格式输出到文件中

#include<stdio.h>

int main(int argc,char** argv){
	FILE* fp = fopen("./test3.txt","w");
	fputs("你好中国\n中国你好\n",fp);
	fclose(fp);
	return 0;
}

fgets

函数名:fgets
  函数参数:char *str, int n, FILE *stream
  函数功能:从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
  函数返回值:遇到文件结尾和错误的时候,返回一个空指针,在代码中也可以用数字0来代替。如果一切正常,返回与传入的第一个参数相同的地址(char *)。
  
  简单理解就是从文件中读取(n-1)个字符到指定内存中

#include<stdio.h>

int main(int argc,char** argv){
	char buf[50] = {0};
	char* temp = 0;
	FILE* fp = fopen("./test.txt","r");
	while(1){
		//循环调用fgets将整个文件读取完毕
		temp = fgets(buf,50,fp);
		if(temp == NULL){break;}
		printf("%s",buf);
	}
	fclose(fp);
	return 0;
}

使用fgets和fputs实现shell指令中的cp功能

函数名: lstat
  功 能: 获取一些文件相关的信息
  用 法: int lstat(const char *path, struct stat *buf);
  参数:path:文件路径名。buf:结构体的指针,这个结构体的定义在头文件sys/stat.h

/*
	使用fgets和fputs实现shell指令中的cp功能
	第一点:需要获取到终端上输入的文件的名字,并且在代码中使用
	
    例如:cp+f1+f2
	那么用r的方式打开f1并且用fgets读取,读取一次后,用w的方式打开f2并用fputs输出。最后全都完成后将f1和f2关闭

	追加功能:如果f2是一个目录文件,则直接将f1原名拷贝f2中
*/
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>

int main(int argc,char** argv){//argc统计参数个数,(char*)argv[]存储参数名字
	if(argc<3){
		printf("cp: 缺少了文件操作数\nTry 'cp --help' for more information.\n");
		return 0;
	}
	char buf[10] = {0};
	char* retval = 0;
	char tarfile[50] = "./";
	struct stat temp;//结构体
	lstat(argv[2],&temp);//获取一些文件相关的信息
	if(S_ISDIR(temp.st_mode)){//判断是否为.开头
        //假如argv[1]中的数据为demo1.c
        //假如argv[2]中的数据为111
		strcat(tarfile,argv[2]);//./111
		strcat(tarfile,"/");//./111/
		strcat(tarfile,argv[1]);//./111/demo1.c
	}else{
		strcpy(tarfile,argv[2]);
	}
	FILE* rfp = fopen(argv[1],"r");//fopen的灵活使用
	FILE* wfp = fopen(tarfile,"w");
	while(1){
		retval = fgets(buf,10,rfp);//打开文件后读取10个字符到字符串,要函数返回值的目的是判断是否读取完毕
		if(retval == NULL){break;}
		fputs(buf,wfp);//打开文件后把字符串中的数据输出到文件中
	}
	fclose(rfp);
	fclose(wfp);
	return 0;
}

第三组:fwrite/fread(模块读取,结构体中好用)

fwrite 和 fread的函数声明的原型是一样的,功能正好相反
  函数名:fwrite
  函数参数:void* ptr,int size,int num,FILE* fp
  解释:将ptr所指向的地址作为首地址,然后将首地址以及之后的若干个地址封装成整个模块,一个模块size个字节,最后将总共num个模块写入到fp所指向的文件中去的

fwrite和fread的使用

#include<stdio.h>
#include<string.h>

typedef struct Data{
	int age;
	char name[20];
	int score;
}data_t;

int main(){
	data_t st1 = {20,"张三",80};
	data_t st2 = {0};
    //将st所指向的地址作为首地址,
    //然后将首地址以及之后的个地址封装成整个模块,
    //一个模块sizeof(st)个字节,最后将总共1个模块写入到wfp所带表的文件中去的
	FILE* wfp = fopen("test4.txt","w");
    fwrite(&st1,sizeof(st1),1,wfp);
	fclose(wfp);
	
	FILE* rfp = fopen("test4.txt","r");
	fread(&st2,sizeof(st2),1,rfp);
	fclose(rfp);
	printf("%d\n%s\n%d\n",st2.age,st2.name,st2.score);

	return 0;
}

使用fwrite和fread实现shell指令中的cp功能

/*
	使用fread和fwrite实现shell指令中的cp功能
	第一点:需要获取到终端上输入的文件的名字,并且在代码中使用
	
	例如:cp+f1+f2
	那么用r的方式打开f1并且用fread读取,读取一次后,用w的方式打开f2并用fwrite输出。最后全都完成后将f1和f2关闭

	追加功能:如果f2是一个目录文件,则直接将f1原名拷贝f2中
*/
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>

int main(int argc,char** argv){
	if(argc<3){
		printf("cp: 缺少了文件操作数\nTry 'cp --help' for more information.\n");
		return 0;
	}
	char buf[10] = {0};
	int retval = 0;
	char tarfile[50] = "./";
	struct stat temp;
	lstat(argv[2],&temp);
	if(S_ISDIR(temp.st_mode)){
		strcat(tarfile,argv[2]);
		strcat(tarfile,"/");
		strcat(tarfile,argv[1]);
	}else{
		strcpy(tarfile,argv[2]);
	}
	FILE* rfp = fopen(argv[1],"r");
	FILE* wfp = fopen(tarfile,"w");
	while(1){
    //将rfp所指向的文件首地址以及之后的个地址封装成整个模块,
    //一个模块1个字节,最后将总共1个模块写入到指针buf所指向的内存中
    //(就是从文件一个一个字节读取)
		retval = fread(buf,1,1,rfp);
		if(retval == 0){break;}
		fwrite(buf,1,1,wfp);//将指针buf所指向的内存中的数据,一个一个字节写入到文件中
	}
	fclose(rfp);
	fclose(wfp);
	return 0;
}

例如上面的代码的文件名为demo1.c,把demo1.c复制到当前目录下,并且命名为test.c
输入:./a.out demo1.c test.c
把demo1.c复制到名为a的目录下
输入:./a.out demo1.c ./a

使用fwrite和fread完成学生数组的加载保存

/*
	编写一个加载保存学生信息的程序:
	要求:先手动完善3个学生的信息,然后将3个学生添加入数组中。
		将整个数组保存到文件中去
		从文件中读取所有信息进入整个数组

		要求:当第一次运行完成个程序后,第二次再次运行程序,同名学生添加失败
		学生信息有:姓名,年龄,成绩,要求姓名唯一
*/
#include<stdio.h>
#include<string.h>
typedef struct Stu{
	char name[20];
	int age;
	int english;
	int chinese;
	int math;
	int physics;
	int chemics;
	int bio;	
}stu_t;

void insertStu(stu_t* DB,int* len){
	char name[20] = {0};
	int age = 0;
	int english;
	int chinese;
	int math;
	int physics;
	int chemics;
	int bio;
	printf("请输入学生的姓名,年龄:\n");
	scanf("%s %d",name,&age);
	printf("请输入 语数外物化生 成绩:\n");
	scanf("%d %d %d %d %d %d",&english,&chinese,&math,&physics,&chemics,&bio);
	while(getchar()!=10);
	stu_t st = {0};
	strcpy(st.name,name);
	st.age = age;
	st.english = english;
	st.chinese = chinese;
	st.math = math;
	st.physics = physics;
	st.chemics = chemics;
	st.bio = bio;
	DB[*len] = st;
	(*len)++;
}

void saveStu(stu_t* DB,int len){
	FILE* fp = fopen("./stuDB.txt","w");
	int i = 0;
	for(i=0;i<len;i++){
		fwrite(DB+i,sizeof(stu_t),1,fp);
	}
	fclose(fp);
}

void loadStu(stu_t* DB,int* len){
	FILE* fp = fopen("./stuDB.txt","r");
	if(fp == NULL){return;}
	int retval = 0;
	int i = 0;
	while(1){
		retval = fread(DB+i,sizeof(stu_t),1,fp);
		if(retval == 0){break;}
		(*len)++;
	}
	fclose(fp);
}

void printStu(stu_t* DB,int len){
	int i = 0;
	for(i=0;i<len;i++){
		printf("***********\n");
		printf("姓名:%s\n",DB[i].name);
		printf("年龄:%d\n",DB[i].age);
		printf("英语:%d\n",DB[i].english);
		printf("语文:%d\n",DB[i].chinese);
		printf("数学:%d\n",DB[i].math);
		printf("物理:%d\n",DB[i].physics);
		printf("化学:%d\n",DB[i].chemics);
		printf("生物:%d\n",DB[i].bio);
	}
	printf("***********\n");
}

int main(int argc,char** argv){
	stu_t DB[512] = {0};
	int len = 0;
	loadStu(DB,&len);
	insertStu(DB,&len);
	saveStu(DB,len);
	printStu(DB,len);
	return 0;
}
Python是一门高级编程语言,它是一种动态类型、面向对象的语言,支持多种编程范式。Python在科学计算、数据分析、人工智能等领域有广泛的应用,越来越受到业界的关注。Python还有一个优点就是其灵活的扩展性,可以通过编写扩展模块来增强Python的功能。 编写一个Python扩展模块,需要先了解一下Python的C API,这是Python提供的一套C语言的API接口,可以用于编写Python扩展模块或者嵌入Python到其他应用程序中。扩展模块也可以用其他语言如C++、FORTRAN等编写,只要是遵循Python的C API规范即可。 编写Python扩展模块,可以使用Python自带的distutils模块来进行构建和安装。该模块可以用setup.py脚本来配置扩展模块的编译参数、依赖库等,并可以生成可执行文件或者扩展模块所需的动态链接库等文件。 下面是一个简单的Python扩展模块的例子,该模块可以计算两个数字的乘积: // test_module.c #include <Python.h> static PyObject* multiply(PyObject* self, PyObject* args) { int x, y; if (!PyArg_ParseTuple(args, "ii", &x, &y)) { return NULL; } return Py_BuildValue("i", x * y); } static PyMethodDef TestModuleMethods[] = { {"multiply", multiply, METH_VARARGS, "Returns the product of two integers."}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef test_module = { PyModuleDef_HEAD_INIT, "test_module", "A test module that multiplies two integers", -1, TestModuleMethods }; PyMODINIT_FUNC PyInit_test_module(void) { return PyModule_Create(&test_module); } 在该模块中,我们定义了一个multiply函数,用于计算两个整数的乘积。该函数采用Python提供的PyArg_ParseTuple函数解析函数的输入参数,然后返回乘积。我们还定义了一个TestModuleMethods数组,它是一个PyMethodDef结构体的数组,里面记录了我们定义的函数的名称、函数指针、函数的参数类型等信息。最后我们使用PyModule_Create函数生成一个Python模块对象并返回。 我们需要将上面的代码保存到test_module.c文件中,并使用如下命令来构建并安装该模块: $ python setup.py build $ python setup.py install 在安装完成后,我们可以在Python解释器中使用该模块: >>> import test_module >>> test_module.multiply(10, 20) 200 编写Python扩展模块是一项有趣的工作,它可以让我们深入了解Python的内部机制,并且可以为我们解决一些实际问题带来便利。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值