您的位置:首页 > 编程语言 > C语言/C++

C语言文件读写操作

2016-04-06 10:29 645 查看
在机器学习研究中,打交道的数据一般都是以矩阵向量的形式存在,而且数据量巨大。因此,数据文件如训练样本、测试样本的读取是编程求解问题的首要一步。本文将介绍C语言中的部分文件操作函数。

文件操作总的步骤为(1)打开文件;(2)读/写文件数据;(3)关闭文件。下面将从这三方面展开阐述。

头文件:#include<stdio.h>

一、打开文件fopen()函数和关闭文件fclose()函数

fopen()函数用来以指定的方式打开文件,函数原型为:

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


【参数】filename为包含了路径的文件名,mode为文件打开方式。

【返回值】成功打开文件返回指向该流的文件指针,否则返回NULL,并把错误代码存在errno中。

mode有以下几种方式:

打开方式说明
r以只读方式打开文件,该文件必须存在。
r+以读/写方式打开文件,该文件必须存在。
rb+以读/写方式打开一个二进制文件,只允许读/写数据。
rt+以读/写方式打开一个文本文件,允许读和写。
w打开只写文件,若文件存在则长度清为0,即该文件内容消失,若不存在则创建该文件。
w+打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留(EOF符保留)。
a+以附加方式打开可读/写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(原来的EOF符 不保留)。
wb以只写方式打开或新建一个二进制文件,只允许写数据。
wb+以读/写方式打开或建立一个二进制文件,允许读和写。
wt+以读/写方式打开或建立一个文本文件,允许读写。
at+以读/写方式打开一个文本文件,允许读或在文本末追加数据。
ab+以读/写方式打开一个二进制文件,允许读或在文件末追加数据。
二进制和文本模式的区别:

在windows系统中,文本模式下,文件以"\r\n"代表换行。若以文本模式打开文件,并用fputs等函数写入换行符"\n"时,函数会自动在"\n"前面加上"\r"。即实际写入文件的是"\r\n" 。
在类Unix/Linux系统中文本模式下,文件以"\n"代表换行。所以Linux系统中在文本模式和二进制模式下并无区别。

注意:(1)打开文件后往往要进行读写操作,若打开文件失败则无法进行读写,所以需要判断文件是否被正确打开;(2)文件操作完成后,一定要将文件关闭,否则会造成文件所占内存泄露以及下次访问文件时会出错。

fclose()函数用来关闭当前被打开的文件流,其原型为:

int fclose(FILE *stream);


【参数】stream为文件流指针。

【返回值】若成功关闭文件则返回0,否则返回EOF(-1),并把错位代码存到errno。

下面是示例代码。

#include <stdlib.h>
#include <stdio.h>

int main() {
FILE *fp=fopen("test.txt", "r");//打开文件
if(fp == NULL)//判断是否成功打开文件
{
printf("can't open file!");
exit(1);
}
else
{
printf("open file successfully!");
}

fclose(fp);//关闭文件

return 0;
}


二、读取文件fgetc()和fgets()函数

1、fgetc()函数

函数原型

int fgetc(FILE *fp);


【函数说明】从参数fp所指向的文件中读取一个字符,若读到文件尾而无数据时返回EOF。

下面代码使用fgetc()函数实现读取一行的功能。

#include <stdlib.h>
#include <stdio.h>
#include <iostream>

using namespace std;

int main() {
FILE *fp=fopen("/home/lsq/Matlab/myFile.txt", "r");//打开文件

char *line = (char*)calloc(1, sizeof(char));

char c;
int len = 0;
if(fp == NULL)//判断是否成功打开文件
{
printf("can't open file!");
exit(1);
}
while ( (c = fgetc(fp) ) != EOF && c != '\n')//直到遇到换行符或者文件结束停止
{
line = (char*) realloc(line, sizeof(char) * (len + 2) );//改变line的内存空间
line[len++] = c;
line[len] = '\0';
}
cout<<line<<endl;
fclose(fp);//关闭文件

return 0;
}


2、fgets()函数

fgets()函数用于从文件流中读取一行或指定个数的字符,其函数原型为:

char *fgets(char  *string, int size, FILE *fp);


【参数】

string为一个字符数组或者字符指针,用来保存读取到的字符。注意,如果定义了字符指针,那么一定要初始化。

size为要读取字符的个数,分两种情况。如果该行字符数大于size-1,则读到size-1个字符时结束,并在最后补充‘\0’;如果该行字符小于等于size-1,则读取所有字符,并在最后补充’\0‘,即最多读取size-1个字符,这时string的长度也为size-1。

fp表示指向被读取的文件。

【返回值】

1、当size<=0时返回NULL,即空指针;

2、当size=1时,返回空串“ ”;

3、读取成功,返回读取到的字符串;

4、读入错误或者遇到文件结尾(EOF),则返回NULL。

因此,不能直接通过fgets()的返回值来判断函数是否是出错还是终止,应该借助feof()函数或者ferror()函数来判断。

使用fgets()函数读取一行,代码如下。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>

using namespace std;
static char *line=NULL;
static int max_line_len=1024;

static char* readline(FILE *input)
{
int len;
if(fgets(line, max_line_len, input)==NULL)//判断第一次是否读取成功
return NULL;

while(strrchr(line,'\n')==NULL)//判断是否将一行全部读取
{
max_line_len*=2;
line=(char*)realloc(line, max_line_len);//动态拓展内存
len=(int)strlen(line);//已读取字符的长度
if(fgets(line+len,max_line_len-len,input)==NULL)//继续读取这一行剩余的数据
break;
}
return  line;
}

int main() {
FILE *fp;//打开文件
line = (char*)malloc(1024);

fp = fopen("test.txt", "r");

while(readline(fp)!=NULL)//读取一行
{
cout<<line<<endl;
}

fclose(fp);//关闭文件

return 0;
}


3、strtok()函数

strtok函数能够简单的实现一行文本的切分操作。函数原型:

char *strtok(char* string, const char* delim);


【参数】

string表示要操作的数据地址或者指针,通常是通过fgets()函数获取的。

delim为分隔符。

当读取string指向的字符串中遇到分隔符时,就会把分隔符改成’\0‘并返回这个片段的指针或地址。

下面给出fgets()和strtok()函数的代码示例。

文件test内容为:

xiaoming 123456 shanghai

zhangming 123 shangdong

hanmeimei 987 beijing

代码如下:

#include<iostream>
#include<stdio.h>
#include<string.h>

using namespace std;

int main()
{
char *strname,*strid,*straddress;
char buff[256];
FILE *p;

p=fopen("test.txt","r");

while(fgets(buff,256,p)!=NULL)
{
strname=strtok(buff," ");//这里要注意的是一行文本中在第一次使用strtok的时候,第一个参数要使用待处理数据的首地址

strid=strtok(NULL," ");//但是在该行的以后使用中第一个参数就要用NULL,这一点很重要,往往被人忽视

straddress=strtok(NULL,"\n");//更加要注意的一点是,在分割该行最后一个属性的时候,很多人对于分隔符的选取仍然是" "(空格)
//这样是不正确的,应该使用"\n"来分割,因为最后的符号是"\n"而不是空格
//如果继续使用空格作为分隔符的话,那么最后一个属性就多了一个"\n"了。

cout<<strname<<" "<<strid<<" "<<straddress<<endl;
}

return 0;
}


三、写入文件函数fputs()

fputs()函数的功能是将指定的字符串写入到文件流中,其原型为:

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


【参数】string为将要写入的字符串,stream为文件流指针。

【返回值】成功返回非负数,失败返回EOF。

fputs()从string的开头往文件写入字符串,直到遇到结束符’\0‘,'\0'不会被写入到文件中。

代码:

#include <stdlib.h>
#include <stdio.h>

int main() {
FILE *fp;//打开文件

fp = fopen("test.txt", "w");
char *line = "hello world!";

if (fp == NULL)//判断是否成功打开文件
{
printf("can't open file!");
exit(1);
}

fputs(line, fp);

fclose(fp);//关闭文件

return 0;
}


参考链接:

http://c.biancheng.net/cpp/u/stdio_h/

http://blog.sina.com.cn/s/blog_75b0e2ad01016xmx.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: