C语言基础---文件操作

文件分类:

int num = 2048;

二进制文件:把数据的补码直接写入文件,这种文件叫二进制文件。

优点:读入和写入时不需要进行转换,所以读写速度快。

缺点:不能使用文本编辑器打开,无法阅读。

0000 0000 0000 0000 0000 1000 0000 0000

文本文件:把数据转换成字符串写入文件,这种文件叫文本文件,能被文本编辑器打开,人类能看得懂。

优点:能被文本编辑器打开,人类能看得懂,能够看出数据是否出错。

缺点:读写时需要转换,读写速度慢,数据有被修改的风险。

“2048”

'2' '0' '4' '8'

50 48 52 56

00110010   -50

00110000   -48

00110100   -52

00111000   -56

总结:二进制文件的大小是确定的,文本文件会根据数据的内容而变化,大小不确定。

打开/关闭文件:

FILE *fopen(const char *char,const char *mode);

功能:打开文件

path:文件的路径

mode:文件的打开模式

返回值:文件结构指针,是后续操作文件的凭证,失败的话会返回NULL

文件打开的模式:

"r" 以只读方式打开文本文件,如果文件不存在,或文件没有读权限则打开失败。

"w" 以只写方式打开文本文件,如果文件不存在则创建,如果文件存在则清空文件的内容,如果文件存在但没有写权限,则打开失败。

"a" 以只写方式打开文本文件,如果文件不存在则创建,如果文件存在则新写入的内容追加到文件末尾,如果文件存在但没有写权限,则打开失败。

"r+" 在"r"的基础上增加了写权限。

"w+" 在"w"的基础上增加了读权限。

"a+" 在"a"的基础上增加了读权限。

如果要操作二进制文件,则在以模式的基础上增加b。

以文本方式打开文件时,如果写入要的字符是 '\n' 时,系统会写 '\n' 和 '\r' ,两个字符,在windows系统中以 '\n' + '\r' 表示一个换行,在读取数据时,遇到 '\n'  '\r' 只会读取一个 '\n'。

Unix系统里,每行结尾只有“<换行>”,即"\n";Windows系统里面,每行结尾是“<回车><换行>”,即“\r\n”;

如:在windows系统下,写入数字0x0A时,会写入0x0A0D,在linuxunix系统下加不加b没有区别。

注意:如果要操作二进制文件,则在以上模式的基础上增加b

int fclose(FILE *stream);

功能:关闭文件

返回值:成功返回0,失败返回-1

fclose(file);

file = NULL;

注意:不能重复关闭,否则会出现double free的错误,为了防止出现野指针,文件关闭后最后把文件赋值为空NULL。及时关闭文件可以把缓冲区中的数据写入到文件中。

文本文件的读写:

int fprintf(FILE *stream, const char *format, ...);

功能:把若干个变量以文本格式写入到指定的文件中

stream:要写入的文件

format:占位符+转义字符+提示信息    例如:”%d\n"

...:若干个变量

返回值:写入字符的数量

int fscanf(FILE *stream, const char *format, ...);

功能:从文件中读取数据

stream:要读取的文件

format:占位符

...:若干个变量的地址

返回值:成功读取的变量个数

二进制文件的读写:

注意:以二进制格式读写文件时,最好加上mode,最好包含b。

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:把一块内存处作数组,然后数组中的内容以二进制给是写入到文件中

ptr:数组的首地址

size:一个元素的字节数

nmemb:数组的长度

返回值:实际写入的次数

size_t fread (void *ptr, size_t size, size_t nmemb, FILE *stream) ;

功能:把二进制文件中的内容读取到数组中

ptr:要存储数据的数组的首地址

size:数组元素的字节数

nmemb:数组的容量

返回值:成功读取的次数

注意:如果以fwrite/fread读写的字符串,那么我们操作的依然是文本文件。

练习1:设计一个学生结构,定义结构变量并初始化,把结构变量以文本格式写入到stu.txt文件中。

student.h文件:

#ifndef STUDENT_H

#define STUDENT_H

typedef struct Student

{

char name[20];

char sex;

float score;

int id;

}Student;

#endif//STUDENT_H

main.h文件

#include <stdio.h>

#include "student.h"

int main(int argc,const char* argv[])

{

Student stu = {"hehe",'m',98,10010};

FILE* wfp = fopen("stu.txt","w");

if(NULL == wfp)

{

printf("文件打开失败!");

return 0;

}

int ret=fprintf(wfp,"%s %c %g %d\n",stu.name,stu.sex,stu.score,stu.id);

printf("写入了%d个字符\n",ret);

fclose(wfp);

wfp = NULL;

return 0;

}

练习2:从stu.txt文件中,读取结构变量的值。

student.h文件:

#ifndef STUDENT_H

#define STUDENT_H

typedef struct Student

{

char name[20];

char sex;

float score;

int id;

}Student;

#endif//STUDENT_H

main.h文件:

#include <stdio.h>

#include <stdlib.h>

#include "student.h"

int main(int argc,const char* argv[])

{

Student* stup = malloc(sizeof(Student));

FILE* rfp = fopen("stu.txt","r");

if(NULL == rfp)

{

printf("打开文件失败!\n");

return 0;

}

int ret = fscanf(rfp,"%s %c %g %d",stup->name,&stup->sex,&stup->score,&stup->id);

printf("%s %c %g %d",stup->name,stup->sex,stup->score,stup->id);

printf("成功读取了%d个变量\n",ret);

fclose(rfp);

rfp = NULL;

return 0;

}

文件位置指针:

文件位置指针它记录着读写文件时位置,读取数据时从文件位置指针处开始读取,写入数据时也会写入到文件位置指针所指向的位置,并且它会随着读写操作自动移动。

以“r”、“r+”方式打开文件,文件位置指针指向文件的开头。

以“a”、“a+”方式打开文件,文件位置指针指向文件的末尾。

void rewind(FILE *stream);

功能:把文件的位置指针调整到文件的开头。

long ftell(FILE *stream);

功能:返回文件位置指针指向第几个字节。

int fseek(FILE *stream, long offset, int whence);

功能:设置文件的位置指针

stream要设置的文件

offset偏移值

whence基础位置

SEEK_SET   文件开头

SEEK_CUR  当前位置

SEEK_END  文件末尾

whence+offset就是文件指针最终设置的位置。

返回值:成功返回0,失败返回-1。

练习3:实现计算文件字节数的函数。

size_t file_size(const char* path);

#include <stdio.h>

#include <assert.h>

size_t file_size(const char* path)

{

assert(NULL != path);

FILE* rfp = fopen(path,"r");

if(NULL == rfp)

{

return -1;

}

fseek(rfp,0,SEEK_END);

size_t size = ftell(rfp);

fclose(rfp);

return size;

}

int main(int argc,const char* argv[])

{

printf("%d\n",file_size("stu.txt"));

return 0;

}

文件操作时的局限性:

文件的内容是连续存储在磁盘上的,所以就导致以下操作变得困难:

向文件中插入数据:

1、文件位置指针调整到要插入的位置

2、把后续的数据整体向后拷贝n个(要插入的字节数)字节

3、文件位置指针调整到要插入的位置,写入数据

从文件中删除数据:

1、文件位置指针调整到要删除的数据末尾

2、把后续的数据整体向前拷贝n个(要删除的字节数)字节

3、截取文件的长度/修改文件的长度、大小

所以:程序运行时,先把数据从文件中加载到内存,程序在运行期间只针对内存进行增、删、改、查,程序结束时再把数据从内存写入到文件。

文件管理:

int remove(const char *pathname);

功能:删除文件

int rename(const char *oldpath,const char *newpath);

功能:重命名文件

int access(const char* pathname,int mode);

功能:生成一个与当前文件系统不重名的文件名

int truncate(const char *path,off_t length);

功能:把文件的内容设置为length字节数

mode:(可以用或的方式添加多条mode)

R_OK  读权限

W_OK  写权限

X_OK  执行权限

F_OK  文件是否存在

返回值:

检查的权限

char *tmpnam(char *name);

功能:生成一个与当前文件不重名的文件名

练习2:实现一个文件拷贝的函数

int filecopy(char* dest_path,char* src_path);

练习3:实现一个文件移动的函数

int filemove(char* dest_path,char* src_path);

结构序列化:

把结构体变量转化成字符串的过程叫序列化,反序列化就是把字符串转化成结构变量的过程。

为什么把结构变量转化成字符串:

1、网络通信时传输的是大端序列,而个人计算机使用的是小端序列,为了避免传输时的各成员的大小端转换,所以把结构转换成字符串传递更方便。

2、在使用SQL语言操作数据时,SQL是以字符串形式操作数据库的。

方法一:使用sprintf/scanf对简单的结构变量进行序列化和反序列化。

sprintf(arr,"提示信息+占位符",结构.成员变量);

sscanf(str,"提示信息+占位符",&结构.成员变量);

注意:该方法不适合有复杂嵌套关系的结构变量。

方法二:把结构变量转换成JSON格式的字符串,了解cJSON库的使用即可

阅读开源项目的步骤:

1、阅读README文件

版权信息介绍

使用方法介绍

编译方法介绍

原理、示例、局限性

依赖的工具、库

使用时的注意事项

2、编译项目,执行测试程序,阅读测试代码

3、查看示例代码,学习如何使用

4、查看源码,进行学习

5、照葫芦画瓢

main函数参数:

完整的main函数格式:

int main(int argc,const char* argv[ ])

我们在命令执行程序时,可以附加一些参数,这些参数会以字符串形式传递给main函数。

argc:字符串个数,也就是指针数组的长度。

argv:指针数组,里面存储着每个字符串的首地址。

for(int I=0; i<argc; i++)

{

printf("%s\n",argv[i]);

}

./a.out  执行程序时,argc的值是1

练习4:实现一个带覆盖检测的mymv命令。

if(3 != argc)

{

puts("Use:./mymv src dest");

return 0;

}

filemove(argv[2],argv[1]);

数据加密:

对称加密:

明文    经过加密处理 ------> 密文

密文    经过加密处理 ------> 明文

最简单的加密:

A ^ B = C

C ^ B = A

非对称加密:

明文经过加密处理能得到独一无二的密文,而密文无法还原出明文。

用于用户登录以及验证文件的完整性。

如:MD5算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值