关于文件操作个人比较困惑的地方有两点:

  1. 关于wwb的区别
  2. 如何定位文件的读写位置

文件格式和打开模式

c中的文件打开模式分为:文本模式和二进制模式,分别处理文本格式文件和二进制格式文件。

两个模式的主要区别是在换行符的处理上,利用文本模式在写文本内容到文件的时候,需要将换行符转换成系统对应的编码方式.

系统不同,对换行符的表示方式也是不一样的,例如unix系统是\n,而MS-DOS\r\nMac\rC里面都是用\n作为换行符的,所以在文本写入时,底层需要将C形式换行符\n做对应的转换之后写入文件,读取文件时将对应系统的换行符转成C形式的。因为unix系统的换行符是\n,这和C形式一致,所以unix系统下文本模式和二进制模式没有区别。

C中使用fopen函数创建文件句柄,函数原型如下:

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

filename表示文件路径,mode表示打开模式,成功返回一个文件句柄指针,失败返回null。

mode 有下列几种形态字符串:

  • r 以只读方式打开文件,该文件必须存在。
  • r+ 以可读写方式打开文件,该文件必须存在。
  • rb+ 读写打开一个二进制文件,允许读数据。
  • rw+ 读写打开一个文本文件,允许读和写。
  • w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
  • w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
  • a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
  • a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
  • wb 只写打开或新建一个二进制文件;只允许写数据。
  • wb+ 读写打开或建立一个二进制文件,允许读和写。
  • ab+ 读写打开一个二进制文件,允许读或在文件末追加数据。
  • at+ 打开一个文本文件,a表示append,就是说写入处理的时候是接着原来文件已有内容写入,不是从头写入覆盖掉,t表示打开文件的类型是文本文件,+号表示对文件既可以读也可以写。

上述的形态字符串都可以再加一个b字符,如rbw+bab+等组合,加入b 字符用来告诉函数库以二进制模式打开文件。如果不加b,表示默认加了t,即rt,wt,其中t表示以文本模式打开文件。

windows上分别利用w+wb+模式测试一下文本模式和二进制模式写数据的区别:

#include <stdio.h>
#include <stdlib.h> int main(int argc, char* argv[])
{
// 文件w+.txt
FILE *fp1 = fopen(".\\w+.txt", "w+");
if (!fp1)
{
fputs("文件打开错误!", stdin);
return EXIT_FAILURE;
}
fprintf(fp1, "%s", "The first line!\nThe second line!\n"); // 写入内容中带有换行符
fclose(fp1); // 文件wb+.txt
FILE* fp2 = fopen(".\\wb+.txt", "wb+");
if (!fp2)
{
fputs("文件打开错误!", stdin);
return EXIT_FAILURE;
}
fprintf(fp2, "%s", "The first line!\nThe second line!\n"); // 写入内容中带有换行符
fclose(fp2);
return EXIT_SUCCESS;
}

左侧显示的是w+.txt,右侧显示的是wb+.txt,明显可以看出保存的换行符是有区别的,wb+模式没有将C代码中的\n进行特殊处理:

文件读写位置定位

如果可以在访问文件的时候,能够直接定位到某个位置进行读取,那就可以实现像数组一样随机访问了。

C语言提供了几个相关的函数,他们的原型如下:

int fseek( FILE *stream, long offset, int origin );
long ftell( FILE *stream );
int fgetpos( FILE *restrict stream, fpos_t *restrict pos );
int fsetpos( FILE *stream, const fpos_t *pos );
void rewind( FILE *stream );

其中,rewind 函数用于将文件内部的位置指针重新指向一个流(数据流或者文件)的起始位置。这里需要注意的是,这里的“指针”表示的不是文件指针,而是文件内部的位置指针。即随着对文件的读写,文件的位置指针(指向当前读写字节)向后移动。而文件指针指向整个文件,如果不重新赋值,文件指针不会发生改变。

例如,使用w+模式打开一个文件写入内容之后,再输出文件内容,代码可以这么写:

#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 80 int main()
{
// 打开文件
char filename[MAXLEN] = ".\\test.txt";
FILE* fp = fopen(filename, "w+");
if (!fp)
{
fputs("文件打开失败!", stdout);
exit(EXIT_FAILURE);
}
// 写入文本
char* text = "This is a test file!";
fputs(text, fp);
// 还原位置指针
rewind(fp);
// 读取文件内容
char c;
while ((c = fgetc(fp)) != EOF)
{
putchar(c);
}
// 关闭文件
fclose(fp);
return EXIT_SUCCESS;
}

rewind功能比较简单,只能用于返回到文件开头,如果想要跳转到其他位置,则fseek功能更加强大,它用来设定文件的读写位置,可以实现文件的随机访问。

fseek的三个参数, 第一个是文件句柄,第三个参数是基准位置,第二个是相对于基准位置的偏移处,基准位置有三个:

名称 代表位置 值形式
SEEK_SET 文件首部 0
SEEK_CUR 当前位置 1
SEEK_END 文件尾部 2

示例代码:

#include <stdio.h>
#include <stdlib.h> int main()
{
// 打开文件
FILE* fp = fopen(".\\test.txt", "w+");
if (!fp)
{
fputs("文件打开失败!", stdout);
exit(EXIT_FAILURE);
}
// 先写入123,然后改成abc
fputc('1', fp);
fputc('2', fp);
fputc('3', fp);
// 先将指针转到中间改b
fseek(fp, -2, SEEK_END);
fputc('b', fp);
// 将指针转到开头改a
fseek(fp, 0, SEEK_SET);
fputc('a', fp);
// 将指针转到第三个字符改c
fseek(fp, 1, SEEK_CUR);
fputc('c', fp);
// 关闭文件
fclose(fp);
return EXIT_SUCCESS;
}

需要注意的是,SEEK_END指向了文件结尾,所以需要向前偏移2,才能将指针指到1的后面。

对于以文本模式打开的流,使用fseek函数时候需要注意,因为'\n'换行符与系统换行符之间的转换会导致fseek产生意外的结果。fseek只有在下面两种情况下才能保证当文件以文档模式打开时能正确使用fseek函数:

  • 与起始位置相对偏移为0的重置,即没有改动指针位置
  • origin设置为SEEK_SEToffset为调用ftell返回的值时进行的指针位置重置情况

还有两个函数fsetpos/fgetposfseek/ftell感觉很像,刚开始觉得他们可以用来互相替换,fsetpos也可以用来实现随机访问,后来发现错了,fseek之所以能够实现随机访问文件是因为可以传入一个整型的参数作为文件偏移,而fsetpos接收的参数是fpos_t *,这个fpos_t只能使用通过fgetpost返回的值,不能直接指定,所以两者还是有区别的。

要点4:C的文件操作的更多相关文章

  1. Python基础(三)——集合、有序 无序列表、函数、文件操作

    1.Set集合 class set(object): """ set() -> new empty set object set(iterable) -> n ...

  2. day08 文件操作

    1.三种字符串: (1)u'' 普通字符串 ---> u'abc' ---> 默认的文本方式,以字符作为文本的输出方式 (2)b'' 二进制字符串 ---> b'ASCII码' -- ...

  3. Python爬虫与数据分析之进阶教程:文件操作、lambda表达式、递归、yield生成器

    专栏目录: Python爬虫与数据分析之python教学视频.python源码分享,python Python爬虫与数据分析之基础教程:Python的语法.字典.元组.列表 Python爬虫与数据分析 ...

  4. Java第九次作业--输入输出流和文件操作

    Deadline: 2017-5-25 23:00 一.学习要点 认真看书并查阅相关资料,掌握以下内容: 掌握使用File类访问文件 掌握IO操作的基本原理 掌握字节流和字符流读写文件的操作 二.作业 ...

  5. python基础知识-7-内存、深浅、文件操作

    python其他知识目录 1.一些对内存深入理解的案例 以下列举列表,列表/字典/集合这些可变类型都是一样的原理 变量是个地址,指向存储数据的内存空间的地址,它的实质就相当于c语言里的指针.变量和数据 ...

  6. C# 文件操作(摘抄)

    ——选自<c# 编程兵书>第11章 张志强 胡君 编著 11 文件操作概述 11.1 驱动器 在Windows操作系统中,存储介质统称为驱动器,硬盘由于可以划分为多个区域,每一个区域称为一 ...

  7. C#文件操作 File(静态类)

      操作某一个文件/文件夹,需要一个文件的完整路径 一.使用File的静态方法进行文件操作 1 2 3 4 5 6 7 8 9 //使用file的静态方法进行复制             File.C ...

  8. C#文件操作(IO流 摘抄)

    11 文件操作概述 11.1 驱动器 在Windows操作系统中,存储介质统称为驱动器,硬盘由于可以划分为多个区域,每一个区域称为一个驱动器..NET Framework提供DriveInfo类和 D ...

  9. 【.NET深呼吸】Zip文件操作(1):创建和读取zip文档

    .net的IO操作支持对zip文件的创建.读写和更新.使用起来也比较简单,.net的一向作风,东西都准备好了,至于如何使用,请看着办. 要对zip文件进行操作,主要用到以下三个类: 1.ZipFile ...

随机推荐

  1. .Net微服务实战之CI/CD

    系列文章 .Net微服务实战之技术选型篇 .Net微服务实战之技术架构分层篇 .Net微服务实战之DevOps篇 .Net微服务实战之负载均衡(上) 相关源码:https://github.com/S ...

  2. 02_HTML01

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"软件测试"获取视频和教程资料! b站在线视频 HTML ...

  3. Django学习路3

    1.打开 Data Source alt insert 打开 Data Source 找到 db.sqlite3 确定 Download 下载后 TestConnection 测试是否成功 2.项目下 ...

  4. PHP xml_parser_free() 函数

    定义和用法 xml_parser_free() 函数释放 XML 解析器.高佣联盟 www.cgewang.com 如果成功,该函数则返回 TRUE.如果失败,则返回 FALSE. 语法 xml_pa ...

  5. PHP mysqli_ssl_set() 函数

    实例 创建 SSL 连接: <?php高佣联盟 www.cgewang.com$con=mysqli_init();if (!$con){die("mysqli_init failed ...

  6. C/C++编程笔记:C语言制作情侣必备《爱情电子相册》,源码解析!

    今天是521,就分享一个程序员必会的——情侣回忆杀<爱情电子相册>吧!话不多说,先上思路,后接源码! 具备能力: 1.基本可视化编程 1.1 initgraph(800,600); 1.2 ...

  7. EC R 87 div2 D. Multiset 线段树 树状数组 二分

    LINK:Multiset 主要点一下 二分和树状数组找第k大的做法. 线段树的做法是平凡的 开一个数组实现就能卡过. 考虑如树状数组何找第k大 二分+查询来判定是不优秀的. 考虑树状数组上倍增来做. ...

  8. HiddenHttpMethodFilter进行请求过滤

    基于 HiddentHttpMethodFilter 的示例 作用: 由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE.PUT 等 method 并不支持,Spring3 ...

  9. JAVA编程中你一定要掌握的“快捷键”

    JAVA编程常用快捷键 相信很多编程小白刚开始的时候,看向大神的时候都是双膝跪地满眼泪水的膜拜之情~不因为别的,就是因为他们可以随随便便敲出很多行代码,而且他们没有动鼠标!这时候就有人问了:“怎么才能 ...

  10. 系统UISearchController详解

    原文链接:https://www.jianshu.com/p/aa9a153a5b58