文件在代码中的运用(上)

简介: 文件在代码中的运用

一,程序文件的基础概述

1,文件的打开与关闭的系统原理

       在平常中我们的输入和输出都是输出在计算机屏幕上,而其实数据也可以输出到文件中,也可从文件中输入数据。

       首先,C/C++程序中运用fopen打开一个文件,而打开文件有使用绝对路径和相对路径两种方式,然后用文件指针FILE的形式来接受文件,FILE会将文件数据存放到专属存放文件的文件信息区里,文件信息区是打开每个文件所生成的存放文件数据的一块内存区域,而文件指针就是指向这块区域,从而调用这块区域的数据,然后就是对文件进行一系列的读写或其他操作,最后就是关闭文件。如图所示(图中用相对路径来打开文件):


2,数据流形式

       流是一种抽象的概念,比如水流,电流等同理,然而在计算机的运行的各种数据也存在数据流,在C程序中,只要运行起来就默认打开三个流:标准输入流stdin,标准输出流stdout,标准错误流stderr,而一但将文件操作和程序联系起来将不再使用标准输入输出流了。有关文件操作的一系列函数如下:


3,文件的概述

       文件划分其实有很多种类,在C程序中,我们主要从文件的编码方式来看。从文件的编码方式中文件可划分为文本文件和二进制文件两种。文本文件在磁盘中存储时每个字符对应一个比特位,即用ASCII码的字符形式存储。这种存储方式是计算机展现给人们能够看懂的。二进制文件在程序中都是以二进制的形式存储的,里面的内容是我们看不懂的,机器处理二进制文件时将其看成字符流,按字节进行处理,在内部处理后能成为机器能够识别的码。


二,文件函数的操作

1,文件的打开与关闭

       打开文件用函数fopen,fopen会从文件缓冲区里拿到数据,如若打开成功会返回文件缓冲区的首地址,如若打开失败会返回NULL,打开失败的原因大多情况下是在此路径下没有此文件或路径错误。而打开文件时,若是文件的路径在此源程序下可直接写文件名,此为相对路径;若是在其它目录下要写全文件路径,此为绝对路径。

       当文件路径问题解决后就要说明要对文件进行什么操作。"r"表示只对文件进行读,"w"表示只对文件进行写,若在此路径下不存在此文件,则在此路径下将会自动建立此文件,"rb"表示只对二进制文件进行读,"wb"表示只对二进制文件进行写,若在此路径下不存在此文件,则在此路径下将会自动建立此文件,.....这几个是常用的操作。

       关闭文件用函数fclose,此操作很简单,具体代码如下:

#include<stdio.h>
int main()
{
//此处应注意,打开文件是绝对路径,若文件在此项目录下,可以用相对目录打开
   FILE* pr=fopen("E:\\text\\test1.txt","w");//往文件中写入,若不存在此文件,则在此路径中建立此文件
   if (pr == NULL)
   {
       printf("兔子兔子");//当打开失败时的提示
       exit(0);
   }
   fclose(pr);//关闭文件
   pr = NULL;
   return 0;
}

2,文件字符的输入与输出

       文件输入函数的形式为int fgetc(FILE* pa),返回值为文件指针此时指向文件的具体位置(注意:这里说的指针并不是地址形式,而是指向数据的具体位置,刚开始的时候指向开头位置,即0,往后移动一位就加一),参数适用于所有流的形式,即即可往文件里输入,又可在标准输入流stdin中输入。

       文件的输出函数形式为int fputc(int ch, FILE* pa),返回值仍为文件指针此时指向文件的具体位置。fputc是把ch输出到pa流中,pa适用于所有流。

       注意,当用完fgetc和fputc时,此时指向文件数据位置的指针就自动会往下一个单元位置前进一位。具体代码如下:

代码一:

#include<stdio.h>
int main()
{
   int a = 10000;
   char b[15] = "zhujunhao";
   FILE* pr=fopen("E:\\text\\test1.txt","w");
   if (pr == NULL)
   {
       printf("兔子");
       exit(0);
   }
   fputc(a,pr);//此数不可以用b,因为fput(a,pr);a只能是一个字符或一个数
   fputc('j', pr);//不能添加字符串
   fputc('h', pr);
   fclose(pr);
   pr = NULL;
   return 0;
}

代码二:

#include<stdio.h>
int main()
{
   FILE* pa =fopen("E:\\text\\test1.txt","r");
   printf("%c", fgetc(pa));//fgetc(pa)从文件中的第一个开始读取,先从第一个读取
   printf("%c", fgetc(pa));//fgetc(pa)从文件中自动读取第二个
   //printf("%c", fgetc(pa));//fget(pa)从文件中自动读取第三个

   fclose(pa);
   pa = NULL;
   return 0;
}

代码三:

#include<stdio.h>
int main()
{
   int ch = fgetc(stdin);//stdin指从键盘中输入,stdin是标准输入流,即键盘
   fputc(ch,stdout);//stdout指从键盘中输出,stdin是标准输出流,即屏幕
   return 0;
}

3,文本的输入和输出

       文本行的输入函数形式为char * fgets ( char * str, int num, FILE * stream ),FILE*参数中也是适用于所有流,函数的功能是从FILE*流中得到num个字节放入数组str中。

#include<stdio.h>
int main()
{
   char arr[50];
   FILE* pr = fopen("E:\\text\\test1.txt","r");
   if (pr == NULL)
   {
       printf("兔子");
       exit(1);
   }
   fgets(arr, 50, pr);//在fgets中,第一个arr是将pr中读取的放到arr中,第二个50指最多读取50个字节,第三个pr指从pr中读取
   printf("%s", arr);//注意:这里最多只能读取一行
   fgets(arr, 50, pr);//第一行数据结束后后有字符\n,所以在读取中也把\n读取到里面了,第二次可不用加\n即自动换行
   fclose(pr);
   pr = NULL;
   return 0;
}

       文本行的输出函数形式为int fputs ( const char * str, FILE * stream );FILE*参数中也是适用于所有流,函数的功能是将数组str直接全部输出到stream流中。

#include<stdio.h>
int main()
{
   FILE* pr = fopen("E:\\text\\test2.txt", "w");
   char a[15] = "aaa";
   if (pr == NULL)
   {
       printf("兔子");
       exit(0);
   }
   fputs(a,pr);//fputs可以添加许多个,fputc只能添加一个有关字符或者数
   fputs("zhujunhao", pr);//fputs可以添加字符串也可以添加字符,fputc只能添加字符
   fclose(pr);
   pr = NULL;
   return 0;
}//总结:对于fputs比fputc更为高级,最好用fputs,可助记为s为字符串,c为字符

4,文件的格式化输入于输出

       文件的格式化输入函数标准形式为int fscanf ( FILE * stream, const char * format, ... );此函数与scanf函数就多了一步控制流,此函数的功能是将函数参数输出到指定流中。fprintf函数与printf函数同理,具体代码如下:

代码一:

#include<stdio.h>
int main()
{
   int a = 666, b = 999;
   char arr[50] = "tuzi";
   FILE* pa = fopen("E:\\text\\test2.txt", "w");
   if (pa == NULL)
   {
       printf("兔子");
       exit(1);
   }
   fprintf(pa, "%d %s %d", a, arr, b);//将a,arr,b全部输出到pa所指向的文件中
   fclose(pa);
   pa = NULL;
   return 0;
}

代码二:

#include<stdio.h>
int main()
{
   char ar[100];
   int a, b;
   FILE* pa = fopen("E:\\text\\test1.txt", "r");
   if (pa == NULL)
   {
       printf("兔子");
       exit(1);
   }
   fscanf(pa, "%s %d %d", ar, &a, &b);//从文件中输入ar,a,b这三个数据,但是文件中必须有这三个类型的数据
   printf("%s %d %d", ar, a, b);
   fclose(pa);
   pa = NULL;
   return 0;
}

代码三:

#include<stdio.h>
int main()
{
   char ar[50], arr[50];
   int a;
   fscanf(stdin,"%s %d %s",ar,&a,arr);//从输入设备中输入这三个类型的数据
   fprintf(stdout,"%s %d %s",arr,a,ar);//从输出设备中输出这三个数据
   return 0;
}//注意:不是每个函数都可以输入到输入设备中或者输出到输出设备中,必须函数满足所以的流才可以

 

5,文件的读写

       文件的输入函数size_t fread ( void * ptr, size_t size, size_t count, FILE * stream )和输出函数size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream )都是以二进制形式来输入和输出的。其中stream不适用于所有流,只适用于文件。两函数是将count个数据ptr中的size字节输入或输出文件流stream中。具体代码如下:

代码一:

#include<stdio.h>
struct p
{
   char a[50];
   char b[50];
   char c[50];
}ar = {"abc","sss","99"},tm;
int main()
{
   char A[500];
   gets(A);
   FILE* pa = fopen("E:\\text\\test1.txt", "wb");
   if (pa == NULL)
   {
       printf("兔子");
       exit(1);
   }
   fwrite(&ar, sizeof(ar), 1, pa);//fwrite函数是往二进制的形式写文件,其中第一个空为要写入的数据地址
   fwrite(A,sizeof(A),1,pa);//第二个空为写入数据所占用内存大小,第三个空为要写几个A,第四个为写进的文件指针      
   fclose(pa);
   pa = NULL;
   return 0;
}

代码二:

#include<stdio.h>
int main()
{
   char a[500],b[500];
   FILE* pa = fopen("E:\\text\\test2.txt", "r");//文件数据为abcdefg数据长度为7
   if (!pa)
   {
       perror("兔子");
       exit(1);
   }
//对于fread和fwrite函数返回值,若其中写入或读入的数已经超出文件数据中的最后一个时,则返回的值会是读或写入时最大的n值                                          
   printf("%d\n", fread(a, sizeof(char), 2, pa));//将2个char大小的数据读入a中,即两个字符,返回值为2
   printf("%c\n", a[0]);//此时a[n]={'a','b'};
   printf("%d\n", fread(b, 4, 1, pa));//此时b[n]={'c','d','e','f'},共四个,在用完fread或fwrite后文件指向会自动移动
   for (int i = 0; i < 4; i++)
       printf("%c", b[i]);
   //注意:不能用puts(b),因为以为fread和fwrite是用于二进制文件,puts会把乱码打印出来
   fclose(pa);
   pa = NULL;
   return 0;
}

代码三:

#include<stdio.h>
int main()
{
   FILE* pa = fopen("E:\\text\\test2.txt", "w");
   if (!pa)
   {
       perror("兔子");
       exit(1);
   }
   char a[5] = { '1','2','3','4','5'};
   fwrite(a, sizeof(char), 1, pa);//只将第一个字符'1'写入进去了,此时文件中数据为1
   fwrite(a, sizeof(a), 1, pa);//将数组a全部元素写入进去了,因为sizeof(a)即为全部元素所占的内存大小
   fclose(pa);//此时文件中数据为11234
   pa = NULL;
   return 0;
}

6,文件的定位

       在C/C++程序中,有个文件定位函数——fseek()函数,函数形式为int fseek ( FILE * stream, long int offset, int origin );其中,当origin宏的名字为SEEK_SET(数值为0)时,此时表示文件的开始;当origin宏的名字为SEEK_CUR(数值为1)时,此时表示文件当前位置的起点;当origin宏的名字为SEEK_CUR(数值为2)时,此时表示文件末尾的位置。stream为文件流,offset表示偏移量。而当函数操作成功时返回数值0,操作失败时返回非零值。在这里需提醒的是偏移位置的定位,具体说明和代码如下:

#include<stdio.h>
int main()
{
   FILE* pa = fopen("E:\\text\\test3.txt", "r");//文件中的数据为123456789abcdef
   if (!pa)
   {
       puts("兔子");
       exit(1);
   }
   fseek(pa, 1, SEEK_SET);//pa是文件指针,1表示偏移1个数据(第二个数据,刚开始偏移量为0)即偏移1位
   printf("%c", fgetc(pa));//其中,SEEK_SET是指向开始位置,SEEK_END指向最后一个位置,SEEK_CUR指向当前的位置
   fclose(pa);
   pa = NULL;
   return 0;
}//注意:对于fseek(pa,-1,SEEK_END)为最后一个字符,默认最后偏移量为-1,偏移量不能为正数

相关文章
|
3月前
|
程序员 开发工具 Android开发
代码审查|这段代码,为什么复制文件夹总是“成功”?
最近开始一个人负责整个项目的全栈开发和维护,工作中没了和同事交叉 code review 的环节,所以就打算,如果工作中遇到一些比较典型的代码,包括好味道和坏味道,就拿出来分析下,与大家一起交流,作为另一种形式的「交叉 review」。
29 1
|
5月前
|
Java
java中实现File文件的重命名(renameTo)、将文件移动到其他目录下、文件的复制(copy)、目录和文件的组合(更加灵活方便)
这篇文章介绍了Java中使用`renameTo()`、`Files.copy()`等方法对文件进行重命名、移动和复制的操作,并提供了代码实例和测试效果。
java中实现File文件的重命名(renameTo)、将文件移动到其他目录下、文件的复制(copy)、目录和文件的组合(更加灵活方便)
|
6月前
|
数据库
获取本地某文件中的以.jpg文件的名字,并导入数据库的测试代码
获取本地某文件中的以.jpg文件的名字,并导入数据库的测试代码
|
8月前
|
JavaScript 前端开发 开发工具
如何编写.gitignore文件
如何编写.gitignore文件
143 1
|
8月前
快速比较两个文件里不同内容的地方
快速比较两个文件里不同内容的地方
175 2
|
8月前
|
JavaScript 前端开发
Gulp 打包压缩 js 文件到指定目录详细流程(修改文件名与后缀)
Gulp 打包压缩 js 文件到指定目录详细流程(修改文件名与后缀)
48 0
|
算法框架/工具 计算机视觉 Docker
YOLOv5源码逐行超详细注释与解读(1)——项目目录结构解析
YOLOv5源码逐行超详细注释与解读(1)——项目目录结构解析
1694 0
|
C++
C++分文件编写:拆类(.h和.cpp文件)
C++分文件编写:拆类(.h和.cpp文件)
147 0
|
C++
VS下源文件中有多个代码时如何指定运行特定的代码(一个源文件下有多个代码时运行指定代码)
VS下源文件中有多个代码时如何指定运行特定的代码(一个源文件下有多个代码时运行指定代码)
320 0