Linux下C语言实现文件读写操作(包含在应用层与驱动层)

前言:

第1节是笔者基于公司的“祖传”C语言操作模板上做相应修改的程序,当做自己以后使用C语言文件操作的模板。
第2节与第3节是笔者之前需要配合团队内的小伙伴做数据转换,他需要我将保存在.txt文件内的字符数据(十六进制)转换为二进制,也需要我将.Bin文件内的二进制数据转换为字符数据(十六进制)。当然这两节程序有很大的优化空间,弊端为每次读取数据的量太小,需要频繁IO操作,导致运行速度变得很慢。解决方法为使用malloc函数一次性将文件的内容读取到内存空间上,可大幅提高程序的运行速度。
第4节是笔者一直很好奇32位操作系统下的C语言的数据类型所占空间进行测试的例子,方便自己在后面的开发中准确的使用数据类型,不至于让数据小而空间大,或者数据大而空间小。
第5节是笔者想通过C语言为工程项目中修改配置文件中的参数,通过匹配配置文件中指定的变量去替换参数。但该节程序最后并未用于工程项目中,笔者想表达,C语言实现真的好麻烦,这就是更高级的编程语言强大之处。
第6节是笔者想为嵌入式Linux产品的开机Logo动态读取指定路径下的.ppm图片,原本考虑修改Kernel中显示Logo部分,将图片的数据写入相应的地方。但后面在内核源码中找不到内核编译时怎么将logo_linux_clut224.ppm编译为logo_linux_clut224.c的方法,不清楚.ppm文件是怎么将数据转化到struct linux_logo结构体中的clut和data成员,后面不得不放弃这种想法。但也让笔者改变思路,让驱动程序读取指定路径下的配置文件,让驱动定向运行。
第7节为应用层的常规文件操作。
第8节为获取挂载在文件系统下节点的存储情况。
第9节摘抄自《Linux程序设计 第4版》中第3、4节的C语言进行文件/目录、系统操作
第10节为记录程序运行的时间

下面的程序参考了网上的许多例子,测试可用,若需要使用,需要修改部分参数。

1. C语言文件操作的模板:

// 编译与运行命令:
// gcc xxxx.c -o xxxx
// ./xxxx

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

int OpenFile(char *ReadFile, char *WriteFile, unsigned int *FileLength,
					FILE **fpRead, FILE **fpWrite);
void CloseFile(FILE *fpRead, FILE *fpWrite);
int FileOperation(unsigned int FileLength, FILE *fpRead, FILE *fpWrite);

int main(int argc, char *argv[])
{
	char ReadFile[] = "ReadFile.txt";
	char WriteFile[] = "WriteFile.txt";
	
	FILE *fpRead = NULL, *fpWrite = NULL;
	unsigned int FileLength = 0;
	
	int ret = 0;
	
	// 打开需要读、写的文件
	ret = OpenFile(ReadFile, WriteFile, &FileLength, &fpRead, &fpWrite);
	if(ret < 0)
	{
		return 0;
	}
	
	// 文件操作
	FileOperation(FileLength, fpRead, fpWrite);
	
	// 关闭文件
	CloseFile(fpRead, fpWrite);
	
	return 0;
}

int OpenFile(char *ReadFile, char *WriteFile, unsigned int *FileLength,
					FILE **fpRead, FILE **fpWrite)
{
	// 打开需要读的文件
	*fpRead = fopen(ReadFile, "r+");
	if(*fpRead == NULL)
	{
		printf("open %s error \n", ReadFile);
		return -1;
	}
	
	// 打开需要写的文件
	*fpWrite = fopen(WriteFile, "wb");
	if(*fpWrite == NULL)
	{
		printf("open %s error \n", WriteFile);
		fclose(*fpRead);
		return -1;
	}
	
	// 将读文件指针定位于文件的末尾处,获取文件大小
	fseek(*fpRead, 0, SEEK_END);
	*FileLength = ftell(*fpRead);
	printf("FileLength = %dB (%.2fMB) \n", *FileLength,
					((double)*FileLength / (1024 * 1024)));
	
	return 1;
}

void CloseFile(FILE *fpRead, FILE *fpWrite)
{
	fclose(fpRead);
	fclose(fpWrite);
}

int FileOperation(unsigned int FileLength, FILE *fpRead, FILE *fpWrite)
{
	unsigned int i = 0;
	unsigned char Array[3];
	unsigned char CharLen = 2;
	
	// 将读、写文件指针指向文件头
	fseek(fpRead, 0, SEEK_SET);
	fseek(fpWrite, 0, SEEK_SET);
	
	// 进行文件读写
	for(i = 0; i < FileLength; i += 2)
	{
		if((i != 0) && (i % 16 == 0))
		{
			fwrite("\n", sizeof(unsigned char), 1, fpWrite);
		}
		
		memset(Array, '\0', sizeof(Array));
		
		fread(Array, sizeof(unsigned char), CharLen, fpRead);
		
		fwrite(Array, sizeof(unsigned char), CharLen, fpWrite);
		fwrite(" ", sizeof(unsigned char), 1, fpWrite);
	}
	
	return 1;
}
FILE结构体:
// 位于stdio.h,笔者在Linux底下找不到定义FILE结构体,只在Visual Studio内找到了定义
// 不同编译器下的FILE结构体定义不一样
// FILE结构是间接地操作系统的文件控制块 (FCB)来实现对文件的操作

#ifndef _FILE_DEFINED
struct _iobuf {
        char *_ptr;       // 文件输入的下一个位置 
        int   _cnt;       // 当前缓冲区的相对位置 
        char *_base;      // 指基础位置(即是文件的其始位置)
        int   _flag;      // 文件标志
        int   _file;      // 应该是文件描述符,进入打开文件列表索引的整数
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;
#define _FILE_DEFINED
#endif

2. 将字符(十六进制)转成二进制(C语言的文件操作):

// 编译与运行命令:
// gcc xxxx.c -o xxxx -lm
// ./xxxx

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 
#include <errno.h>
#include <math.h>
#include <unistd.h> 
#include <sys/time.h>

int main(int argc, char *argv[])
{
	char FilePath[] = "/mnt/hgfs/XXXX/";
	char ReadFile[] = "File";
	char WriteFile[] = "FileConvert";
	char TxtUnit[] = ".txt";
	char BinUnit[] = ".bin";
	
	char ReadFilePath[80], WriteFilePath[80];
	char ClearWriteFileCmd[160], TxtToJPEGCmd[160];
	
	unsigned int FileLength = 0;
	
	char array[4];
	unsigned char DataBin = 0;
	unsigned char DataTemp = 0;
	
	int i = 0, j = 0;
	FILE *fpRead = NULL, *fpWrite = NULL;
	unsigned int NumRead = 0, NumWrite = 0;
	unsigned int DataCount = 0;
	int CharLen = 2;		// 每次读取文件的两个字符
	
	memset(ReadFilePath, 0, 80 * sizeof(char));
	memset(WriteFilePath, 0, 80 * sizeof(char));
	memset(ClearWriteFileCmd, 0, 160 * sizeof(char));
	memset(TxtToJPEGCmd, 0, 160 * sizeof(char));
	
	sprintf(ReadFilePath, "%s%s%s", FilePath, ReadFile, TxtUnit);
	sprintf(WriteFilePath, "%s%s%s", FilePath, WriteFile, TxtUnit);
	sprintf(ClearWriteFileCmd, "dd if=/dev/null of=%s%s%s", FilePath, WriteFile, TxtUnit);
	sprintf(TxtToJPEGCmd, "mv %s%s%s %s%s%s", FilePath, WriteFile, TxtUnit, FilePath, WriteFile, BinUnit);
	
	// 打开需要读的文件
	fpRead = fopen(ReadFilePath , "r+");
	if(fpRead == NULL)
	{
		printf("Open %s error \n", ReadFilePath);
		return -1 ;
	}
	// 打开需要写的文件
	fpWrite = fopen(WriteFilePath , "wb");
	if(fpWrite == NULL)
	{
		printf("Open %s error \n", WriteFilePath);
		return -1 ;
	}
	
	printf("Open %s Success \n", ReadFilePath);
	printf("Open %s Success \n", WriteFilePath);
	
	system(ClearWriteFileCmd);
	
	// 定位于文件的末尾处,获取文件大小
	fseek(fpRead, 0, SEEK_END);
	FileLength = ftell(fpRead);
	printf("FileLength = %d (%.2fK %.2fM) \n", FileLength, ((double)FileLength / 1024), ((double)FileLength / 1024 / 1024));
	
	// 将文件指针指向文件头
	fseek(fpRead, 0, SEEK_SET);
	fseek(fpWrite, 0, SEEK_SET);
	
	NumRead = 0;
	NumWrite = 0;
	
	while(NumRead < FileLength)
	{
		memset(&array, '\0', 4 * sizeof(char));
		
		fseek(fpRead, NumRead, SEEK_SET);
		fread(array, sizeof(char), CharLen, fpRead);
		
		// 判断取出的值是否为换行符、空格、制表符、回车符
		//if((array[0] == '\n') || (array[0] == ' ') || (array[0] == '\t') || (array[0] == '\r'))
		if(array[0] <= ' ')
		{
			NumRead += (1 * sizeof(char));
			continue ;
		}
		
		NumRead += (CharLen * sizeof(char));
		
		// 下面这句话不能写,会大大拖慢速度,运行速度降低150倍左右
		//fseek(fpWrite, NumWrite, SEEK_SET);
		
		// 字符转为数据
		for(DataBin = 0 , j = 0 ; j < CharLen ; j ++)
		{
			DataTemp = array[j] ;
			if((DataTemp >= '0') && (DataTemp <= '9'))		DataTemp = DataTemp - '0';
			else if((DataTemp >= 'a') && (DataTemp <= 'z'))	DataTemp = (DataTemp - 'a' + 10);
			else if((DataTemp >= 'A') && (DataTemp <= 'Z'))	DataTemp = (DataTemp - 'A' + 10);
			
			//DataBin += (DataTemp * pow(16, (CharLen - 1 - j)));
			DataBin += (DataTemp << (4 * (CharLen - 1 - j)));
		}
		fwrite(&DataBin, sizeof(char), 1, fpWrite);
		NumWrite += (1 * sizeof(char));
		DataCount ++ ;
		
	}
	
	fclose(fpRead);
	fclose(fpWrite);
	
	system(TxtToJPEGCmd);
	
	return 0 ;
}

3. 将二进制转成字符(十六进制)(C语言的文件操作):

// 编译与运行命令:
// gcc xxxx.c -o xxxx -lm
// ./xxxx

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 
#include <errno.h>
#
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值