谈到文件,先了解下什么是文本文件和二进制文件的区别吧!
1、文本文件:存储时是将字符的ASCII值存在磁盘中,取的时候将数值(ASCII)翻译成对应的字符;
2、二进制文件:存取的都是二进制;
文件流指针:
当打开一个文件时,系统会返回一个结构体,这个结构体有对此文件操作的所有信息
调用fopen时(fopen的返回值: 如果成功返回FILE结构体地址,失败返回NULL;
返回的文件流指针标识了打开的那个文件),系统返回这个结构体地址,比如如下所示:
FILE*P = fopen("test.txt");
说太多的东西不如代码演示一遍,代码如下所示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
// 打开一个文件,成功则返回这个FLIE结构体地址,失败则返回NULL;
FILE *fp = fopen("./test.txt", "w");
if (NULL == fp) {
perror(""); // 打印输错的信息
return;
}
fclose(fp); // 关闭文件
return 0;
}
以上代码是在相对路径下执行的,为了直接在vs中调试运行。注意:对于相对路径相对的是工程文件。
设备文件:但启动一个程序时,系统会打开三个设备文件,分别是:
1、stdin 标准输入文件:
FILE *stdin = fopen(stdin,"r")
2、stdout 标准输出文件:
FILE *stdout = fopen(stdout,"w")
3、stderr 标准错误文件:
FILE *stderr = fopen(stderr,"w")
1、fputc():
格式:
int fputc(int ch, FILE * stream);
/*
功能:将ch转换为unsigned char后写入stream指定的文件中
参数:
ch:需要写入文件的字符
stream:文件指针
返回值:
成功:成功写入文件的字符
失败:返回-1
*/
作用:写入一个字符到文件当中。
代码演示如下所示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
// 打开一个文件,成功则返回这个FLIE结构体地址,失败则返回NULL;
FILE *fp = fopen("./test.txt", "w");
if (NULL == fp) {
perror(""); // 打印输错的信息
return;
}
char strBuf[] = "abcde";
int n = 0;
while (strBuf[n] != 0) {
fputc(strBuf[n], fp);
n ;
}
fclose(fp); // 关闭文件
return 0;
}
2、fgetc():
格式
int fgetc(FILE * stream);
/*
功能:从stream指定的文件中读取一个字符
参数:
stream:文件指针
返回值:
成功:返回读取到的字符
失败:-1
*/
代码演示如下所示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
// 打开一个文件,成功则返回这个FLIE结构体地址,失败则返回NULL;
FILE *fp = fopen("./test.txt", "r");
if (NULL == fp) {
perror(""); // 打印输错的信息
return;
}
char strBuf[128] = "";
int n = 0;
while ((strBuf[n ] = fgetc(fp)) != EOF);
printf("%s\n", strBuf);
fclose(fp); // 关闭文件
return 0;
}
在上面代码提到了用“EOF”作为文件的结尾,也要提下 feof() 这个函数的使用方法。
为什么要提到这个函数,主要是如果读取文件不是纯文本的时候,有像-1这种数字,那么就不可以使用EOF(-1)作为文件的结尾,就需要用到foef()函数。
格式:
int feof(FILE * stream);
/*
功能:检测是否读取到了文件结尾。判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)。
参数:
stream:文件指针
返回值:
非0值:已经到文件结尾
0:没有到文件结尾
*/
用代码形式演示如下所示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
// 打开一个文件,成功则返回这个FLIE结构体地址,失败则返回NULL;
FILE *fp = fopen("./test.txt", "r");
if (NULL == fp) {
perror(""); // 打印输错的信息
return;
}
char strBuf[128] = "";
int n = 0;
do {
strBuf[n ] = fgetc(fp);
} while (!feof(fp)); // 非0值读到文件末尾,取反则为未读到文件末尾
printf("%s\n", strBuf);
fclose(fp); // 关闭文件
return 0;
}
1、fgets(读取字符串):
作用:从文件读取字符串,fgets读取中遇到\n结束;
格式:
char * fgets(char * str, int size, FILE * stream);
/*
功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 '\0' 作为字符串结束。
参数:
str:字符串
size:指定最大读取字符串的长度(size - 1)
stream:文件指针
返回值:
成功:成功读取的字符串
读到文件尾或出错: NULL
*/
2、fputs(写入字符串):
作用:向文件写入字符串;
格式:
int fputs(const char * str, FILE * stream);
/*
功能:将str所指定的字符串写入到stream指定的文件中,字符串结束符 '\0' 不写入文件。
参数:
str:字符串
stream:文件指针
返回值:
成功:0
失败:-1
*/
1、fprintf():
作用:组包函数,写文件;
格式:
int fprintf(FILE * stream, const char * format, ...);
/*
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0' 为止。
参数:
stream:已经打开的文件
format:字符串格式,用法和printf()一样
返回值:
成功:实际写入文件的字符个数
失败:-1
*/
2、fscanf():
作用:拆包函数(读文件):
格式:
int fscanf(FILE * stream, const char * format, ...);
/*
功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:
stream:已经打开的文件
format:字符串格式,用法和scanf()一样
返回值:
成功:参数数目,成功转换的值的个数
失败: - 1
*/
1、fwrite()写入函数:
格式:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
/*
功能:以数据块的方式给文件写入内容
参数:
ptr:准备写入文件数据的地址
size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb
stream:已经打开的文件指针
返回值:
成功:实际成功写入文件数据的块数目,此值和 nmemb 相等
失败:0
*/
需要注意的是:在第二个参数写1,,返回值即是写入的块数也是写入的字节数。
2、fread()读取函数:
格式:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
/*
功能:以数据块的方式从文件中读取内容
参数:
ptr:存放读取出来数据的内存空间
size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb
stream:已经打开的文件指针
返回值:
成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
失败:0
*/
分别为三个函数:如下所示:
1、fseek():
作用:可以移动光标。
格式:
int fseek(FILE *stream, long offset, int whence);
/*
功能:移动文件流(文件光标)的读写位置。
参数:
stream:已经打开的文件指针
offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。
whence:其取值如下:
SEEK_SET:从文件开头移动offset个字节
SEEK_CUR:从当前位置移动offset个字节
SEEK_END:从文件末尾移动offset个字节
返回值:
成功:0
失败:-1
*/
2、rewind():
作用:将光标移动到开头,和fseek(fp,0,SEEK_SET)一样。
格式:
void rewind(FILE *stream);
/*
功能:把文件流(文件光标)的读写位置移动到文件开头。
参数:
stream:已经打开的文件指针
返回值:
无返回值
*/
3、 ftell():
格式:
long ftell(FILE *stream);
/*
功能:获取文件流(文件光标)的读写位置。
参数:
stream:已经打开的文件指针
返回值:
成功:当前文件流(文件光标)的读写位置
失败:-1
*/
格式:
int stat(const char *path, struct stat *buf);
/*
功能:获取文件状态信息
参数:
path:文件名
buf:保存文件信息的结构体
返回值:
成功:0
失败:-1
*/
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
代码演示一下,如下所示:
#define __CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(){
struct stat stu;
int res = 0;
res = stat("./test.txt", &stu);
if (res < 0) {
printf("没找到文件!\n");
}
printf("文件大小为:%d\n", stu.st_size);
system("pause");
return 0;
}
我这个文件因为是存在,而且文件有内容,所以会打印出文件大小,如下图所示:
remove()与rename():
1、remove():
格式:
int remove(const char *pathname);
/*
功能:删除文件
参数:
pathname:文件名
返回值:
成功:0
失败:-1
*/
2、rename():
格式:
int rename(const char *oldpath, const char *newpath);
/*
功能:把oldpath的文件名改为newpath
参数:
oldpath:旧文件名
newpath:新文件名
返回值:
成功:0
失败: - 1
*/
注意问题:
缓冲区:就是内存中的一块临时的空间,同时普通文件刷新缓冲区的方法,有以下3种:
1、缓冲区满了;2、程序正常退出时;3、利用fflush函数强制刷新。
windows与Linux的区别:
1、Windows下标准输出stdout文件没有缓冲区;
2、Linux有缓冲区;
标准输入不能调用fflush强制刷新;
3、\n换行的问题。
在windows,输入nihao\n时,存储的是nihao\r\n,取出时是nihao\n,当在Linux系统下打开windows存储的文件时,就会多了一个\r。
在Linux,输入nihao\n时,存储和取出都是nihao\n,而在windows下打开Linux存储的文件时,发现没有换行。
,