写在开头

  摸鱼摸得昏天黑地,是该炸一炸鱼的本愿了~ 以前总觉得笔记没什么重要的,但有时事到临头,又十分渴求简明的提纲来唤起记忆/提供重学的门路。于是就有了以下的产物,也希望能抑制一下无效摸鱼的堕落,以免不久的将来再次被现实逼下马。

正文

C把文件看作是一系列连续的字节。

文件:存储在外部介质(硬盘、U盘、DVD等)上数据的有命名集合,是操作系统数据管理的单位

  • 正文文件:文本文件,随字节按照某种字符集(如ASCII、Unicode)进行编码,内容均看作字符
  • 二进制文件:数据按照其在内存中的存储形式原样存放

注意不同系统下不同的文件格式

C的文件操作范式

文件类型指针:是一种文件结构体

作业练习而有所得

1. 一些声明

    FILE *fp;
char filename[32],s[81],line[1024];
//文件名一般不超过32个字符,显示器上一行通常80个字符,文件最大物理行长度一般为1024
char buf[BUFSIZE];
//在stdio.h中定义,作用如其意,缓冲存储中间处理的字符串
char ch;

2. 养成好习惯,凡是打开文件,便要确认是否成功打开;配上随手关文件

    if( (fp=fopen(filename,"r"))==NULL )
{
perror(filename);
return -1;
}

3. fgetc()与fputc()

int fgetc(FILE *stream)

返回所读字符,出错则EOF

int fputc(int c,FILE *stream)

返回所输出字符,出错则EOF

//从一端读取,输入到另外一端,若为stdin/stdout,可改为getchar()与putchar()
while((ch=fgetc(fp))!=EOF)
fputc(ch,fp) //'\n'被同样处理,刚刚好

联合使用,灵活运用返回值

    FILE *fin,*fout;
while(!feof(fin))
fputc(fgetc(fin),fout);

4. fopen()中filename的规则

以编译时文件所在目录为起始,格式为路径名称。(“..”表示后从当前目录回退一层)

    char filename[]="..\\testdata\\fileio_example.c";
//当前目录回退一层,再进入testdata目录下的文件xxx 同时注意转义字符表示'\'

5. fscanf()与fprintf()

类比sscanf()与sprintf(),字符串改为文件指针

返回值:成功I/O的个数;EOF

6. 对于返回指针的函数:C不支持调用函数时返回局部变量地址

warning:function returns address of local variable

原因:函数调用完后,存储在栈空间的数据会被自动释放,那指针所指的地方就毫无意义了!

解决办法:

①加static变为局部全局变量,存储在静态区

②使用malloc()分配空间,存储在堆空间

7. 对多维数组的正确理解:以数组为元素的数组

因此,传递参数时的形参不能简单的用多维指针,不要被平时“x维数组”的称呼而轻视了本质

void function(int (*grade)[3][4])//传递一个指向 [3][4]二维数组 的指针
void function(int grade[][3][4]) //也可
void function(int ***grade) //错误!

8. 打表手段'\t'以及认识'\r'

'\t':字符长模8后,不足8个字符的用空格凑足8个字符

'\r':回车后,内容会被覆盖的

9. fgets()与fputs()

函数原型(注意返回值):

char *fgets(char *str,int size,FILE *stream);

返回指向自身的指针,若没有则为NULL,很自然

int *fputs(char *str,FILE *stream);

返回写入的最后一个字符,出错则为EOF

//作业 fileio_schedule.c
//向reminder.txt文档添加事项,打印已有事项于stdout #include<stdio.h> //定义了BUFSIZ,本地是512
#include<ctype.h>
#include<stdlib.h>//定义了exit();直接推出进程,似乎正好用于void返回值的函数打开文件失败 void append_reminder()//添加事项
{
FILE *fp;
char buf[BUFSIZ],filename[]="reminder.txt";
int m,d;
if( (fp=fopen(filename,"a"))==NULL )
{
perror(filename);
exit(-1);
}
printf("Enter to add something to your schedule:\n");
while(1)
{
fgets(buf,BUFSIZ,stdin);//fgets()确保最后一位为'\0'的前提后,会把结尾的'\n'读入。即最大读取数为BUFZISIZE-1,如果读入数<=(BUFSIZE-2)就会读入结尾的'\n'
if(buf[0]=='\n') goto A;
if(sscanf(buf,"%d.%d",&m,&d)!=2)//利用sscanf返回读入个数来判断是否按格式输入
{
fputs("Input format:<month>.<day><message>\n",stderr);//区分stderr和stdout
continue;
}
fputs(buf,fp);//与fgets适配
} A:fclose(fp);
return;
} void print_schedule()//打印已有事项
{
FILE *fp;
char buf[BUFSIZ];
int m,d;
char message[BUFSIZ]={0};//可以不初始化,因为%s会自动补上'\0' 复习
if( (fp=fopen("reminder.txt","r"))==NULL )
{
perror("reminder.txt");
exit(-2);
}
while(fgets(buf,BUFSIZ,fp)!=NULL)
{
sscanf(buf,"%d.%d%[^\n]",&m,&d,message);
printf("%02d.%02d%s\n",m,d,message);
} fclose(fp);
return;
} int main()
{
append_reminder();
print_schedule();
return 0;
}

10. stderr与stdout的理解

stdout有行缓冲,而stderr没有

//trial.c
int main()
{
fprintf(stdout,"first ");
fprintf(stderr,"second");
}

执行时,照理应该是先输出second的,因为stdout行缓冲,遇到'\n'才会从buf中输入到标准输出文件默认设备中。然而本地还是顺序输出的,不知道为何!

但是还是如果给stdout重定向的话,区别就很明显:在命令行中输入 trial.exe > tmp1.txt 再执行,则"first"输入到tmp1.txt中而"second"输入到屏幕上

11. fseek()和ftell()

函数原型:

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

  • 位移量:offset表示以起始点为基准,向前向后移动的字节数 (e.g.1L -2L ftell(fp))
  • 起始点:whence可以是三个符号 SEEK_SET(0) fSEEK_CUR(1) SEEK_END(2)

    成功则返回非0,出错则非0

函数原型:

long ftell(FILE *stream)

成功则返回相对文件头部的偏移量,出错则-1L

void rewind(FILE *stream)

将文件指针移动到起始,等价于fseek(stream,0,SEEK_SET)

//作业 fileio_len.c 求文件的长度(字节数)-片段
fp=fopen(filename,"rb");//用r打开似乎也一样欸
fseek(fp,0L,SEEK_END);
len=ftell(fp);
printf("Lenth of File is %ld bytes\n",len);

12. 文件存储形式深入理解

//作业 fileio_reverse.c
//将文件按行倒序输出 #include<stdio.h>
#define MAXN 100
//对EOF和fgets以及返回值NULL的理解:fgets读到'\n'或EOF或指定数目时停止,返回所读字符串(也就是说若什么都没读就是NULL)
//EOF只是一个表示文件结束的常量(-1),不是特殊字符
int main()
{
FILE *fp;
char buf[BUFSIZ],filename[]="tmp1.txt";
long offset[MAXN]={0};//标记每行offset的值以便跳转;offset[0]本就为0
int i,j;
//gets(filename);
if((fp=fopen(filename,"r"))==NULL)
{
perror(filename);
return -1;
}
for(i=1;fgets(buf,BUFSIZ,fp)!=NULL;i++) //!执行顺序一定要想清楚!
offset[i]=ftell(fp);//刚好为行首偏移量 //3行的文件,i最后为4,指针指在第5行 for(j=i-2;j>=0;j--)
{
fseek(fp,offset[j],SEEK_SET);
fgets(buf,BUFSIZ,fp);
fputs(buf,stdout);
}
fclose(fp);
} /*文件存储形式如下 (换行只是为了显示'\n'效果) abcd\r\n
efghij\r\n
klmnopq\r\n
(EOF) */

13. 读/写操作不能连续交替进行,需要“同步文件状态”

//作业 fileio_substitute 将某字符替换成另一字符-片段
while(!feof(fp))
{
if(fgetc(fp)=='*')
{
fseek(fp,-1L,SEEK_CUR);//回退
putc('&',fp);
fseek(fp,ftell(fp),SEEK_SET);//必不可少,同步文件状态
}
}

14. 二进制方式读写相关

应该注意,此时按数据项数计数,而不是 正文模式 中的字节数(char)

常见配套函数:fread()与fwrite()

size_t fwrite(const void *buf, size_t size, size_t count, FILE *stream)

size_t fread (void *buf, size_t size, size_t count, FILE *stream)

需要中间商buf[]作转接

返回读/写的数据项数(以size长度为单位),出错则为0

一些操作

//写入数字 3*4=12Byte
int a[3]={23222,1132,128};
fp=fopen("in.dat","wb");
fwrite(a,sizeof(int),3,fp);
fclose(fp); //整块读取:一次性读入BUFSIZE个整数(512...)
fp=fopen("bin_file.txt","r");
n=fread(buf,sizeof(int),BUFSIZE,fp);
len=ftell(fp);
printf("%d int read,current position is:%d\n",n,len); //复杂结构的存取
struct d_type{
int size,year,value,group;
double width,height,ratio;
char name[8];
}d_table[MAX_N];
int n; fwrite(&n,sizeof(int),1,fp_out);//直接取地址,不要忘了哟~
fread(&n,sizeof(int),1,fp_in);
fwrite(d_table,sizeof(struct d_type),n,fp_out);
fread(d_table,sizeof(struct d_type),n,fp_in);

15.文件打开方式备忘录

差不多就粗粗是这些了

【记录】C-文件输入输出的更多相关文章

  1. Apache日志不记录图片文件设置方法和来源日志的配置

    Apache日志不记录图片文件设置方法 <FilesMatch "\.(ico|gif|jpg|swf)">SetEnv IMAG 1</FilesMatch&g ...

  2. 也用 Log4Net 之将自定义属性记录到文件中 (三)

    也用 Log4Net  之将自定义属性记录到文件中 (三)  即解决了将自定义属性记录到数据库之后.一个新的想法冒了出来,自定义属性同样也能记录到文件中吗?答案是肯定的,因为Log4Net既然已经考虑 ...

  3. C++IO类&文件输入输出

    C++IO类&文件输入输出 istream(输入流)类型,提供输入操作. ostream(输出流)类型,提供输出操作. cin,一个istream对象,从标准输入读取数据. cout,一个os ...

  4. python 中文件输入输出及os模块对文件系统的操作

    整理了一下python 中文件的输入输出及主要介绍一些os模块中对文件系统的操作. 文件输入输出 1.内建函数open(file_name,文件打开模式,通用换行符支持),打开文件返回文件对象. 2. ...

  5. IO库----IO类,文件输入输出,string流

    一.IO类 1.IO库类型和头文件表: 头文件 类型 iostream istream,wistream 从流读取数据 ostream,wostream 向流写入数据 iostream,wiostre ...

  6. Apache 日志设置不记录指定文件类型的方法和日志轮

    Apache日志精准的记录了Web访问的记录,但对于访问量很大的站来说,日志文件过大对于分析和保存很不方便.可以在http.conf(或虚拟主机设置文件httpd-vhosts.conf)中进行设置, ...

  7. 第五次程序设计作业 C++计算器雏形 调用文件输入输出

    一.C++计算器作业系列链接 第三次作业:C++计算器雏形 第三次作业附加:代码规范 第四次作业:命令行的调用及计算 MyGithub 二.本次作业相关 要求:第五次程序设计作业 根据这一次的作业要求 ...

  8. 文件打包代码更新 使用json记录打包文件信息

    经过之前的几次试验 决定使用json记录打包文件信息 #include "Package.h" #include "json/json.h" #include ...

  9. Linux学习-rsyslog.service :记录登录文件的服务

    rsyslog.service 的配置文件:/etc/rsyslog.conf 我们现在知道 rsyslogd 可以负责主机产生的各个信息的登录,而这些信息本身是有『严重等级』之分的, 而且, 这些资 ...

  10. LNMP-Nginx配置不记录静态文件、过期时间

    用户访问web网站,通常日志文件会记录很多web站点上的一些静态文件信息,如果长期不处理,日志文件会越来越大,占用的系统资源也越大,此时就需要我们配置不记录静态文件和过期时间,减少日志文件记录过多不必 ...

随机推荐

  1. MAC brew install 跳过 update

    相信很多用 MAC 小伙伴的小伙伴都对 HomeBrew 很熟悉. 但是! 都遇到过这样的问题, 每次安装新东西, 它都要先去 update 一下, 那个耗时啊-. 怎么才能不 update, 直接安 ...

  2. VS2010/MFC 获取当前程序路径的方法

    第一种方法 DWORD GetCurrentDirectory( DWORD nBufferLength, // size, in characters, of directory buffer LP ...

  3. 阿里IM技术分享(七):闲鱼IM的在线、离线聊天数据同步机制优化实践

    本文由阿里闲鱼技术团队书闲分享,原题"如何有效缩短闲鱼消息处理时长",有修订和改动,感谢作者的分享. 1.引言 闲鱼技术团队围绕IM这个技术范畴,已经分享了好几篇实践性总结文章,本 ...

  4. itextpdf 找出PDF中 文字的坐标

    目录 添加引用 添加工具类 调用 找到位置,签名的话见:https://www.cnblogs.com/vipsoft/p/18644127 新项目可以尝试一下 iText 7 , 我这边是老项目所以 ...

  5. 今天记录一下uniapp制作小程序时包过大的解决方法

    在开发小程序的时候,如果业务过于复杂就会使得包太大无法上线,在这我总结了几个解决包过大的方法,避免无法上线 1.静态图片使用线上地址,不要放到项目中,除了navBar的icon,因为那个只能使用本地资 ...

  6. 《深入理解Mybatis原理》MyBatis数据源与连接池详解

    MyBatis数据源DataSource分类 MyBatis把数据源DataSource分为三种: UNPOOLED 不使用连接池的数据源 POOLED 使用连接池的数据源 JNDI 使用JNDI实现 ...

  7. Solution -「CF 808E」Selling Souvenirs

    \(\mathscr{Description}\)   Link.   01 背包.   物品种类 \(n\le10^5\),背包容量 \(m\le3\times10^5\),单个物品体积 \(w\i ...

  8. c# 多线程 lock

    模拟10个线程,每个线程模拟100次取钱: 其实就是相当于1000个人来同时取钱.当然实际情况是取钱的人分布在不同的地区的取款机取钱.同一个取款机只能一个人操作. 关键是要保证取钱的余额要准确,不能在 ...

  9. https证书管理系统- 自动化签发

    https证书管理系统- 自动化签发 第一步:前往网站,注册账户 https://www.lingyanspace.com/ 第二步:进入证书服务菜单,点击新增证书 第三步:填写自有的域名,点击创建订 ...

  10. 「CF 123E」Maze

    传送门 题意澄清 对于 dfs 遍历时,在某一个点进入子树的顺序并不是按输入顺序,而是假定随机选择未进入过的子树 (这纠结了我好久) . 破题思路 首先可以明确这题不能推一个 \(O(1)\) 的式子 ...