C语言读写文件

这篇博客讲述了在不熟悉C语言的情况下,尝试通过读写文件来记录system call的执行情况,但由于各种限制未能实现。博主分享了学习过程中的思路,包括确定txt文件格式、操作FILE型指针、读写操作的细节以及文件关闭、删除和重命名的方法。尽管最终方案不可行,但博主认为这是一个学习C语言的过程。
摘要由CSDN通过智能技术生成

作业要求在xv6操作系统里面增加一个新的system call,这个system call要将程序执行过程中所有执行过的system call记录下来,以及与kernel进行交互的次数。但一开始对C语言不熟悉(不知道可以通过head file或extent来共享数据),所以只想到每次调用system call的时候进行读写操作,将结果写进txt文本,然后新的system call只负责读取文件。这个最终没有实现。第一,读写本身属于system call,会整的很混乱;第二,没法记录与kernel交互的情况;第三,system call文件太多,而且位置不在一起。。。

虽然做了无用功,但总归顺便学习了C语言,应该记录下来。

总体思路是这样的。

1. 首先txt文档的格式应该确定下来。它应该包含以下数据:a)第一行放system call的种类的个数,或者说行数;b)第二行第一个位置放system call字符串的长度;c)第二行第二个位置放system call的名字;d)第二行第三位置放该system call执行了几次...

如下:

4
8 command1 1
8 command2 2
8 command3 1
8 command4 1

 这样做的目的是为了以后malloc方便一点。

2. 无论读写,首先要准备一个FILE型指针变量,它控制文件的开关以及是可以执行什么操作(fd),就好像是文件和用户交互的中转站。例如 FILE *pointer = fopen("1.txt", "r");表示用pointer来联系到1.txt,并执行读操作。但注意,如果文件不存在,pointer为NULL,不能使用fclose(pointer); 命令,否则报错。但FILE *pointer = fopen("1.txt", "w");的话没关系,因为“w”操作即使没有文件,也会创造一个新文件,保证了pointer不为NULL,因此程序后期必须用到fclose(pointer);。还有写文件的时候,比如1.txt,一定写明白”.“后面文件类型。

3. 读操作:fscanf(pointer, “%i %s”, num, string);表示将pointer(pointer对应的必然是“r”操作)所对应的文件里面的两个物品(必然是整数和字符串),放到早已定义好的num和string变量里面去。之所以是两个物品是因为他们之间用空格或回分隔。

4. 写操作:fprintf(pointer, “%i %s\n”, num, string);表示将两个物品(必然是整数和字符串)放到pointer(pointer对应的必然是“w”操作)所对应的文件里面去。注意“%i %s\n”已经将两个物品用空格加以区分,而且还换行,但是读操作的时候不管回车还是空格都直接跳过。

5. 关闭文件:fclose(pointer);pointer不能为NULL。

6. 删除文件:remove(”1.txt“);

7. 重命名:rename("1.txt", "2.txt");

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

//建立结构体,包含一个字符型指针变量,以及一个整数。
typedef struct
{
	char *commandName;
	int commandNumber;
}commandInfo;


void updateFile(char *inputCommandName)
{
	//开两个文件一个新一个旧。
    FILE *origionalFile = fopen("record.txt", "r");
	FILE *newFile = fopen("newRecord.txt", "w");

	
    //”record.txt“被删除了,或没被建立,在新文件写入上述格式的数据。
    if (origionalFile == NULL)
	{
		fprintf(newFile, "%i\n", 1);
		fprintf(newFile, "%i %s %i", strlen(inputCommandName), inputCommandName, 1);
	}
	//”record.txt“里面有东西,就将他们提取出来放到结构体里面,注意提取的过程中如果发现经要写入的 
    //system call信息原文件里有,那就在后面加一。
    else
	{
		int totalNumber;
		fscanf(origionalFile, "%i", &totalNumber);
		//根据最开始的system call种类数,为结构体开辟足够空间。
        commandInfo *info = (commandInfo*) malloc(sizeof(commandInfo) * (totalNumber));
		//设一个旗帜,如果原文件的内容全部写到结构体后,没法发现新system call,就在新文件最后头            
        //加上它
        int isRepeated = 0;
		//根据开头行数,将每行内容保存到结构体里面。
        for (int i = 0; i < totalNumber; i++)
		{
			int nameLen;
			fscanf(origionalFile, "%i", &nameLen);
			//每行前头的system call长短,就是为了malloc的。
            char *tempName = (char *) malloc(sizeof(char) * (nameLen + 1));
			//string最后需要以‘\0’结尾。
            tempName[nameLen] = '\0';
			int tempNum;

			fscanf(origionalFile, "%s %i", tempName, &tempNum);

			//比较下原文件里面有没有本次的system call,有就设置旗帜,顺便加一。
            if (strcmp(tempName, inputCommandName) == 0)
			{
				isRepeated = 1;
				tempNum++;
			}
			info[i].commandName = tempName;
			info[i].commandNumber = tempNum;
			//结构体还不是很理解,似乎结构体里面保存的是指针,因此这里free的话会导致数据丢失。
            //free(tempName);
		}
		//system call是不新元素,直接从结构体取出信息写到新文件里。
        if (isRepeated == 1)
		{
			fprintf(newFile, "%i\n", totalNumber);
			for (int i = 0; i < totalNumber; i++)
				fprintf(newFile, "%i %s %i\n", strlen(info[i].commandName), info[i].commandName, info[i].commandNumber);
			
		}
		//新system call,行数要首先加一,结构体写完以后,在把新system call信息写到最后面。
        else
		{
			fprintf(newFile, "%i\n", totalNumber + 1);
			for (int i = 0; i < totalNumber; i++)
				fprintf(newFile, "%i %s %i\n", strlen(info[i].commandName), info[i].commandName, info[i].commandNumber);
			fprintf(newFile, "%i %s %i\n", strlen(inputCommandName), inputCommandName, 1);
		}

		//结构体没用了,把它释放。但是前面在heap里开辟的那些Name还没有释放,回头改一下。
        free(info);
		//关掉老文件。
        fclose(origionalFile);
	}
	
	fclose(newFile);

	remove("record.txt");
	rename("newRecord.txt", "record.txt");
}

//读文件,显示在屏幕上。每次执行完以后删除txt文件。
void readFile()
{
	FILE *file = fopen("record.txt", "r");
	if (file == NULL)
	{
		printf("No system call!");
		return;
	}
	else
	{
		int totalNum;
		fscanf(file, "%i", &totalNum);
		printf("System call type: %d\n", totalNum);
		for (int i = 0; i < totalNum; i++)
		{
			int length;
			fscanf(file, "%i", &length);
			char *tempName = (char *) malloc(sizeof(char)*(length+1));
			tempName[length] = '\0';
			int tempNum;
			fscanf(file, "%s %i", tempName, &tempNum);
			printf("System call name: %s   times: %d\n", tempName, tempNum);
		}
		fclose(file);
	}
	remove("record.txt");
}


int main()
{
	char temp1[10] = "command1";
	updateFile(temp1);
	char temp2[10] = "command2";
	updateFile(temp2);
	char temp3[10] = "command3";
	updateFile(temp3);
	char temp4[10] = "command4";
	updateFile(temp4);
	char temp5[10] = "command2";
	updateFile(temp5);

	readFile();

	return 0;
}

执行后的结果: 

System call type: 4
System call name: command1   times: 1
System call name: command2   times: 2
System call name: command3   times: 1
System call name: command4   times: 1

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值