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

  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. AList的具体实现 #CS61B-sp18-2.5

    实现一个Array based list,其功能包括获取长度size,添加元素至最后addLast,得到元素get和去除最后一个元素. 设计思路及其实现: 我们都知道在获取数据的时候,直接调用缓存里面 ...

  2. Python大礼包-安装视频+pycharm编译器|Mac版本+64位+32位版本pycharm安装包+python安装|内附网盘链接带提取码

    pycharm安装包+环境安装打包带走,附带视频教程与pdf教程. (下载链接在本文最下方) 多的不说,直接上图: Python大礼包-安装视频+pycharm编译器详细文件: 点击此处进入下载地址 ...

  3. PHP xml_get_error_code() 函数

    定义和用法 xml_get_error_code() 函数获取 XML 解析器错误代码.高佣联盟 www.cgewang.com 如果成功,该函数则返回错误代码.如果失败,则返回 FALSE. 语法 ...

  4. PHP bin2hex() 函数

    实例 把 "Hello World!" 转换为十六进制值: <?php 高佣联盟 www.cgewang.com$str = bin2hex("Hello Worl ...

  5. windows:shellcode 远程线程hook/注入(二)

    https://www.cnblogs.com/theseventhson/p/13218651.html   上次分享了基本的远程注入方法,遗留了一个问题:shellcode执行完后怎么回到线程su ...

  6. three.js 自制骨骼动画(二)

    上一篇说了一下自制骨骼动画,这一篇郭先生使用帧动画让骨骼动画动起来.帧动画是一套比较完善的动画剪辑方法,详细我的api我们就不多说了,网上有很多例子,自行查找学习.在线案例请点击博客原文.话不多说先上 ...

  7. 2080ti的各种问题

    1.循环登录 https://blog.csdn.net/miclover_feng/article/details/79201865 2.多版本cuda切换 https://blog.csdn.ne ...

  8. Android监听器无法跳转的可能原因之一。。。

    主菜前的厨师前言: 各位大牛,牛崽崽,这是本牛崽第一次写博客,牛崽崽我初出茅庐,但是我会很用心的写自己的每一份随笔,写的不好的大家见谅. 今天就来说说本牛崽在实现监听器时遇到的问题: 本牛崽因为也是刚 ...

  9. 手把手教你使用Python网络爬虫获取招聘信息

    1.前言 现在在疫情阶段,想找一份不错的工作变得更为困难,很多人会选择去网上看招聘信息.可是招聘信息有一些是错综复杂的.而且不能把全部的信息全部罗列出来,以外卖的58招聘网站来看,资料整理的不清晰. ...

  10. 17、Java 三大特性之 多态

    知识点:多态的概念.java中多态的使用(方法重载和重写.子类对象的多态性) .多态使用的好处 1.什么是多态? 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程 ...