学习了很多知识,但是我们都要运用到实际中来,在这里我们就要学习一些有关文件的知识了,提前说一下,这次我用的是vs所以在代码中有些出入。
目录
1.文件
1.初试文件
文件用于存放程序、文档、视频等的。
文件就是存放在磁盘上的,一些数据的集合。
磁盘文件:
指一组相关数据的有序集合,通常存储在外部介质(如磁盘)上,使用时才调入内存。
设备文件:
在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把他们的输入、输出等同于对磁盘文件的读和写。
2.标准io库函数对磁盘文件的读取
文件缓冲区是库函数申请的一段内存,由库函数对其进行操作,程序员没有必要知道存放在哪里,只需要知道对文件操作的时候的一些缓冲特点即可。
3.磁盘文件的分类
一个文件通常是磁盘上一段命名的存储区,计算机的存储在物理上是二进制的,所以物理上所有的磁盘文件本质上都是一样的:以字节为单位进行顺序存储。
从用户或者操作系统使用的角度把文件分为:
文本文件:基于字符编码的文件
二进制文件:基于值编码的文件
文本文件、二进制文件对比
译码:
文本文件编码基于字符定长,译码容易些;
二进制文件编码是变长的,译码难一些(不同的二进制文件格式,有不同的译码方式,一般需要特定软件进行译码)。
空间利用率
二进制文件用一个比特来代表一个意思(位操作);
而文本文件任何一个意思至少是一个字符。
所以二进制文件,空间利用率高。
可读性:
文本文件用通用的记事本工具就几乎可以浏览所有文本文件
二进制文件需要一个具体的文件解码器。
4.文件指针
文件指针在程序中用来表示(代表)一个文件的,在打开的时候得到文件,文件指针就是用来代表咱们打开的文件。
FILE*指针变量标识符;
typedef struct _iobuf {
int cnt;// 剩余的字符,如果是输入缓冲区,那么就表示缓冲区中还有多少个字符未被读取
char *ptr: // 下一个要被读取的字符的地址
char *base:// 缓冲区基地址
int flag;// 读写状态标志位
int fd: // 文件描述符
// 其他成员
} FILE;
对文件操作的步骤:
1、对文件进行读写等操作之前要打开文件得到文件指针
2、可以通过文件指针对文件进行读写等操作
3、读写等操作完毕后,要关闭文件,关闭文件后,就不能再通过此文件指针操作文件了
2.函数
1.fopen与fclose
fopen()
FILE* __cdecl fopen(_In_z_ char const* _FileName, _In_z_ char const* _Mode );
用于打开文件。
第一个文件是待打开文件的名称,包含该文件名称的字符串地址。
第二个函数是字符串,指定带打开文件的模式。
当打开文件后需要判断操作是否成功。
fclose()
fclose( _Inout_ FILE* _Stream );
关闭指定函数,必要时刷新缓存区。后面应需要判断文件关闭时候失败。
如果成功返回0,如果失败返回EOF;
如果磁盘已满,移动硬盘被移除或出现I/O错误,都会导致失败,然后我们需要注意的是一个文件只能关闭一次,多次关闭就会导致失败。
接下来我们把两个函数结合起来用一下。
#include<stdio.h>
#pragma warning (disable:4996)
int main()
{
FILE* fp;
fp = fopen("word.txt", "w");
if (fp == NULL) {
printf("失败\n");
return 0;
}
printf("成功\n");
int eclose = fclose(fp);
if (eclose == 0) {
printf("成功");
}
else
printf("失败");
return 0;
}
2.fgetc和fputc
fgetc()
int fgetc(FILE*stream);
读取一个字节,将字节值返回。
返回值为EOF;
fputc()
inputc(int c,FILE*stream);
将c的值写到stream代表的文件中。
返回值;:
成功,返回字节值;
失败,返回EOF。
while ((ch = fgetc(fp)) != EOF) {
printf("%c", ch);
fputc(ch, stdout);
fputc(ch, fp1);
}
因为这两个都是只能利用一个字符,这样的话,只能用while对他进行利用。大家可以试一下,后面也要介绍可以运用字符串的,
3.fgets和fputs
这两个可以对字符串进行操作,但是当遇到换行符或者文件末尾会停止读取。
fgets()
char* __cdecl fgets(
_Out_writes_z_(_MaxCount) char* _Buffer,
_In_ int _MaxCount,
_Inout_ FILE* _Stream
);
fputs()
int __cdecl fputs(
_In_z_ char const* _Buffer,
_Inout_ FILE* _Stream
);
fgets(str, 100, fp);
fputs(str, fp1);
从这里面可以就看出这两个函数用起来比较方便,但是就是当遇到换行符就会停止,所以后面还要了解到更加强大的函数。
4.fread和fwrite
fread()
size_t __cdecl fread(
_Out_writes_bytes_(_ElementSize * _ElementCount) void* _Buffer,
_In_ size_t _ElementSize,
_In_ size_t _ElementCount,
_Inout_ FILE* _Stream
);
第一的需要传入的是指针,第二个是字节数,第三个是一共有多少个块,第四个是需要读的数据。
虽然觉得这个函数很是麻烦,但是在文件读取的时候却是比较好的,因为它在读取的时候不会因为换行符而停止。
需要注意的是fread在字符串最后面是不会加上'\0'的,所以需要自己主动给他加上,要不然我们就需要
fwrite()
size_t __cdecl fwrite(
_In_reads_bytes_(_ElementSize * _ElementCount) void const* _Buffer,
_In_ size_t _ElementSize,
_In_ size_t _ElementCount,
_Inout_ FILE* _Stream
);
很明显的可以看出来,两个函数在定义方面都是一样的。
所以接下来看一下他们两个结合起来的应用。
fread(str, sizeof(char), 100, fp);
fwrite(str, sizeof(char), 100, fp1);
在这里我们了解到了两个函数的功能,这对我们后面在文件的操作中有很大的帮助。后面也会学习到一些有用的函数。
5.fprintf和fscanf
这两个函数与printf和scanf也都类似,区别在于今天介绍的两个函数需要用第一个参数指定到待处理的文件。都把FILE指针作为第一个参数,而不是最后一个。
fprintf()
int __CRTDECL fprintf(
_Inout_ FILE* const _Stream,
_In_z_ _Printf_format_string_ char const* const _Format,
...)
fscanf()
int __CRTDECL fscanf(
_Inout_ FILE* const _Stream,
_In_z_ _Scanf_format_string_ char const* const _Format,
...)
从定义中可以看出来第一个参数是一个指针。
6.rewind
在开始我们就说到了文件,文件中有一个指针指向下一个要被读取字符的地址,但是当我们存入后,需要再次读取,这个时候我们就需要寻找到最菜是的位置,这个时候rewind()就会帮助我们来完成这个工作。
void __cdecl rewind(
_Inout_ FILE* _Stream
);
可以看出就是要传入文件指针。
rewind可以很好的帮助我们回溯到文件的最开始,但是他不灵活,我们就要学习一些比较灵活的函数帮助我们回到任何一个位置,这样对我们有更好的帮助。
7.fseek和ftell
feek()
int __cdecl fseek(
_Inout_ FILE* _Stream,
_In_ long _Offset,
_In_ int _Origin
);
很明显我们知道第一个是文件指针,第二个是需要偏移的字节数,第三是起始位置;
返回值类型为int。
—Origin
- 文件开头SEEK_SET 0
- 文件当前位置SEEK_CUR 1
- 文件末尾SEEK_END 2
位移量:以起始点为基点,向前,后移动的字节数,整数文件末尾方向偏移,负数往文件开头方向偏移。
ftell()
long __cdecl ftell(
_Inout_ FILE* _Stream
);
ftell的返回值必须是一个long类型的值,表示文件中的当前位置,出错时返回-1.
他的作用是测文件读写位置距离文件开始有多少个字节
long int length;
length=ftell(fp);
上面这些就是关于文件的一些需要了解的函数。