如何用C读取100Kc语言文本文件读取

C语言中的各种文件读写方法小结
作者:低调小一
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了C语言中的各种文件读写方法小结,是C语言入门学习中的基础知识,需要的朋友可以参考下
&&& 找工作的时候,曾经用C语言练习过一段时间的算法题目,也在几个还算出名的OJ平台有过还算靠谱的排名。之前以为C语言只限于练习一下算法,但是工作中的一个问题解决让我意识到C语言的用处还是非常广泛的。下面介绍一下,如果用C语言来操作文件保存一个字符串,和读取一个字符串。算法中往往都是printf来打印出结果,但是真实工作中往往通过文件来进行一些持久化的存储工作。
C-File I/O
&&& 文件的I/O操作是每一门语言的重点,因此这里我先来介绍一下如何用C语言去进行文件的I/O操作。
&&& 就C语言程序而言,所有的I/O操作只是简单地从程序移进或移出字节的事情。因此,这种字节流便被称为流(stream)。程序只需要关心创建正确的输出字节数据,以及正确地解释从输入读取的字节数据。特定I/O设备的细节对程序员是隐藏的。绝大多数流是完全缓冲的(fully buffered),这意味着“读取”和“写入”实际上是从一块被称为缓冲区(buffer)的内存区域来回复制数据。从内存中来回复制数据是非常快速的。用于输出流的缓冲区只有当它写满时才会被刷新(flush,物理写入)到设备或文件中。一次性把写满的缓冲区写入和逐片把程序产生的输出分别写入相比效率更高。输入缓冲区也是类似的原理。
&&& 流分为两种类型,分别是文本流和二进制流。
打开流和关闭流
&&& fopen函数打开一个特定的文件,并把一个流和这个文件相关联。它的原型如下所示:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
FILE* open(const char* name, const char* mode);
&&& name参数是你希望打开的文件或设备的名字。mode参数标识流用于只读、只写还是既读又写,以及它是文本流还是二进制流。下面表格里列出了一些常用的模式:
&&&& 如果fopen函数执行成功,它将返回一个指向FILE结构的指针,该结构代表这个新创建的流。如果函数执行失败,它将返回一个NULL指针,error会提示问题的性质。
&&& 流是用函数fclose关闭的,它的原型如下:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
int fclose(FILE *f);
&&& 对于输出流,fclose函数在文件关闭之前刷新缓冲区。如果它执行成功,fclose返回零值,否则返回EOF。
&&& 由于fopen和fclose打开和关闭的都是FILE结构体指针,而在stdio.h头文件中,包含了对文件结构体FILE的描述。这里介绍一下FILE结构体定义:
struct _iobuf {
char *_ // 下一个要被读取的字符的地址
int _ // 剩余的字符
char * // 缓冲区基地址
int _ // 读写文件标志位
int _ // 文件号
int _ // 检查缓冲区的状况
int _ // 文件的大小
char *_ // 临时文件名
typedef struct _iobuf FILE;
&&& 当一个流被打开之后,它可以用于输入和输出。它最简单的形式是字符I/O。字符输入是由getchar函数家族执行的,它们的原型如下所示:
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
&&& 需要操作的流作为参数传递给getc和fgetc,但是getchar始终是从标准输入读取。每个函数从流中读取下一个字符,并把它作为函数的返回值返回。如果流中不存在更多的字符,函数就返回常量值EOF(-1)。
&&& 为了把单个字符写入到流中,可以使用putchar函数家族。它的原型如下:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
int fputc(int character, FILE* stream);
int putc(int character, FILE* stream);
int putchar(int character);
&&& 行I/O其实可以用两种方式执行——未格式化的或者格式化的。这两种形式都用于操纵字符串。区别在于未格式化的I/O只是通过fgets和fputs简单读取或写入字符串,而格式化的I/O则执行数字和其他变量的内部或外部表示形式之间的转换。由于日常工作中操作的一般都是格式化I/O,因此这里不讲fgets和fputs这种非格式化I/O操作了。(当然,还有一个重要的原因,fgets无法判断缓冲区长度,容易导致溢出等情况)
&&& scanf函数家族的原型如下所示。每个原型中的省略号表示一个可变长度的指针列表。从输入转换而来的值逐个存储到这些指针参数所指向的内存位置。
int fscanf(FILE* stream, const char* format, ...);
int scanf(const char* format, ...);
int sscanf(const char* string, const char* format, ...);
&&& 这些函数都从输入源读取字符并根据format字符串给出的格式化代码对它们进行转换。当格式化字符串到达末尾或者读取的输入不再匹配格式字符串所指定的类型时,输入就停止。在任何一种情况下,被转换的输入值的数目作为函数的返回值返回。如果在任何输入值被转换之前文件就已经到达尾部,函数就返回常量值EOF。
printf家族
&&& printf函数家族用于创建格式化的输出。它们的函数原型如下:
int fprintf(FILE *stream, const char* format, ...);
int printf(const char* format, ...);
int sprintf(char* buffer, const char* format, ...);
&&& 把数据写到文件里效率最高的方法是用二进制形式写入,而且Android系统里也有很有用二进制文件通过位来存储数据的应用场景。介绍一下操纵二进制I/O的函数原型。
&&& fread函数用于读取二进制数据,fwrite函数用于写入二进制数据。它们的原型如下所示:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
size_t fread(void* buffer, size_t size, size_t count, FILE* stream);
size_t fwrite(void* buffer, size_t size, size_t count, FILE* stream);
&&& buffer是一个指向用于保存数据的内存位置的指针,size是缓冲区中每个元素的字节数,count是读取或写入的元素数,stream是数据读取或写入的流。
刷新和定位函数
&&& 在处理流时,另外还有一些函数也较为有用。首先,是fflush,它迫使一个输出流的缓冲区内的数据进行物理写入,不管它是不是已经写满。它的原型如下所示:
int fflush(FILE* stream);
&&& 当我们需要立即把输出缓冲区的数据进行物理写入时,应该使用这个函数。
&&& 在正常的情况下,数据以线性的方式写入,这意味着后面写入的数据在文件中的位置是在以前所有写入数据的后面。C同时支持随机访问I/O,也就是以任意顺序访问文件的不同位置。随机访问是通过在读取或写入前先定位到文件中需要的位置来实现的。一般使用fseek函数来实现,函数原型如下:
int fseek(FILE* stream, long offset, int from);
&&& fseek函数允许你在一个流中定位。这个操作将改变下一个读取或写入的位置。它的第一个参数是需要改变的流,它的第二个和第三个参数标识文件中需要定位的位置。下表描述了fseek参数的使用方法。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
有一个15G左右的日志文件,文件中每一行都是一串数字。长度在3——12位之间不等。现在需要算出在日志文件中数字出现次数最多的前10个。**
遇到的问题:
while(!feof(fp)){
fgets(mid,1000,fp); //读取一行内容
我用这种方法读取文件,一直报 Segmentation fault (core dumped)。gbd调试情况如下:
需要能读取大文件的方法。求高手支招。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
你这个文件写法效率实在太低了,而且场合也不使用。超大文本文件单词频率排序是Hadoop解决的最典型问题。
这里是类似功能的源程序写法:
如果实在不愿意学习Hadoop,那么针对你这种情况即使不用Hadoop,直接用管道命令一样可以运行:cat numbers.txt | ./mapper | sort | ./reducer其中的mapper和reducer分别是原文的那两个映射器和总结器。
你如果坚持想知道怎么用文件读取这种数据,还有两种选择,其一是使用64位整数:
while(!feof(fp)) {
long long x = 0; // 定义一个64位整型变量
fscanf(fp, "%lld", &x);
// .... 可以处理数据了
另外一种方式是用字符串:
while(!feof(fp)) {
char mid[256];
memset(mid, 0, 256);
fscanf(fp, "%s", mid);
总之不要用行读取。我很好奇读完了之后你是怎么处理的?我感觉是在内存分配时崩的,难道是你打算把所有内容读到内存来处理吗?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
按撸主的题目要求Linux+C,提供一种思路,如下:可以考虑使用共享内存(mmap),每次映射文件的一部分,依次处理即可
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
可以考虑用split分割文件,然后sort排序:
#large.txt文件每100行进行分割,分割后文件前缀为prefix_
split -l 100 large.txt prefix_
#对文件里的行按数字逆序排序
sort -rn prefix_ab
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:

我要回帖

更多关于 文本文件读取 的文章

 

随机推荐