文件操作
文件分为二进制文件和文本文件,文本文件里面保存的内容形式是ASCII字符,二进制文件里面内容保存形式是01表示的。文件的主要作用是用来进行数据的持久化,能去长久的保存数据。这里f开头的文件操作命令,大多是c标准库里面的文件操作命令。
每个进程的PCB里面都有一份文件描述符表,文件描述符就是这个表的索引,通过索引可以获取这个文件描述符表中的内容,这个内容就是指向打开文件的FILE结构体指针。不同操作系统定义的FILE结构体不太一样,这里我拿出我的这一种作为参考。
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno; //文件描述符
};
typedef struct _IO_FILE FILE;
1. 文件的打开和关闭
要对文件操作,首先要打开文件,打开文件使用fopen函数,返回的是一个FILE类型指针。这个FILE指针指向的是一个文件节点,里面有文件操作的基本信息。
fopen()/fclose()
文件的打开和关闭
#include <stdio.h>
//filepath 文件路径,mode打开模式
FILE * fopen(const char * filepath, const char * mode);
#include <stdio.h>
//关闭文件
int fclose(FILE * fp);
//mode ,其中b是二进制文件
//r或rb只读模式
//w或wb写模式(文件有内容就清空),文件不存在就新建
//a或ab追加模式,在文件末尾添加内容,文件不存在就创建
//r+或者rb+以可读可写方式打开文件
//w+或者wb+以可读可写方式打开文件,没有就新建
//a+或者ab+以追加可读可写方式打开文件,没有就创建
//案例
FILE *file = fopen("hello.txt", "w+");
if(file==NULL)
{
perror("open");
return -1;
}
fclose(file);
2. 文件读写位置相关
EOF表示文本文件结束符,在读取文件时作为读取文件结束标志。
#define EOF (-1)
feof()
判断是否读取到了文件结尾
#include <stdio.h>
int feof(FILE * stream);
//返回
//非0:已经到文件结尾
//0:没有到文件尾
ftell()
获取文件流的读写位置
#include <stdio.h>
long ftell(FILE *stream);
fseek()
移动文件的读写位置
#include <stdio.h>
//fp是打开的文件指针
//offset是偏移量,正数是基于whence向后偏移,负数是基于whence向前偏移
//whence选取:
//SEEK_SET:文件开头
//SEEK_CUR:当前位置
//SEEK_END:文件末尾
int fseek(FILE *fp, long offset, int whence);
//案例 利用函数获取文件大小
fseek(fp,0,SEEK_END);
int len=ftell(fp);
printf("size is %d\n",len);
rewind()
把文件流的读写位置移动到文件开头
#include <stdio.h>
void rewind(FILE *stream);
3. 文件内容读取
fgetc()/fputc()
按照字符读取文件
#include <stdio.h>
//获取 fp 中的字符数据
int fgetc(FILE *fp);
//将ch转换为unsigned char后写入 fp 指定的文件中
int fputc(int ch, FILE * fp);
//案例 拷贝一个文件
FILE *file = fopen("hello.txt", "a+");
FILE *new = fopen("new.txt", "a+");
char ch;
while(!feof(file))
{
ch = fgetc(file);
fputc(ch,new);
printf("%c",ch);
}
fclose(file);
fclose(new);
fgets()/fputs()
按照行读取文件
#include <stdio.h>
//从 filepath 读入字符,保存到str,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 '\0' 作为字符串结束。
char * fgets(char * str, int size, FILE * filepath);
//将str写入 filepath 中,字符串结束符 '\0' 不写入文件
int fputs(const char * str, FILE * filepath);
//案例 拷贝一个文件
FILE *file = fopen("hello.txt", "r+");
FILE *new = fopen("new.txt", "w+");
char buf[100] = {
0};
while (!feof(file))
{
memset(buf, 0, sizeof(buf));
char *p = fgets(buf, sizeof(buf), file);
if (p != NULL)
{
fputs(buf,new);
printf("%s", buf);
}
}
fclose(file);
fclose(new);
fprintf()/fscanf()
按照格式读写文件。
#include <stdio.h>
//根据 format字符串格式化数据,然后将结果输出到 filepath 文件中,指定出现字符串结束符 '\0'为止。
int fprintf(FILE * filepath, const char * format, ...);
//从 filepath 读取字符串,并根据format字符串来格式化数据。
int fscanf(FILE * filepath, const char * format, ...);
//案例 拷贝一个文件,并且修改内容格式
FILE *file = fopen("hello.txt", "r+");
FILE *new = fopen("new.txt", "w+");
char buf[100] = {
0};
while (!feof(file))
{
memset(buf, 0, sizeof(buf));
int len=fscanf(file, "%s",buf);
if(len>0)
{
fprintf(new,"name is %s\n",buf);
printf("%s\n",buf);
}
}
fclose(file);
fclose(new);
fread()/fwrite()
以数据块的方式读写文件
#include <stdio.h>
//将 filepath 的内容拷贝到 ptr 缓冲区中,如果缓冲区是char数组,那么size为1,nmemb为数组长度
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *filepath);
//将 ptr 缓冲区的内容拷贝到 filepath 中,如果缓冲区是char数组,那么size为1,nmemb为数组的内容长度
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *filepath);
//案例 拷贝一张图片
FILE * bili = fopen("bilibili.png","rb");
FILE * cop = fopen("copy.png","wb");
char buf[1024]={
0};
long sum=0;
while(!feof(bili))
{
memset(buf,0,sizeof(buf));
int ret = fread(buf,1,sizeof(buf),bili);
printf("read size is:%d\n",ret);
sum+=ret;
long pos=ftell(bili);
printf("pos is:%ld, sum is:%ld\n",pos,sum);
fwrite(buf,1,ret,cop);
}
fclose(bili);
fclose(cop);
fflush()
读写缓冲器更新,常用于文件读写到缓冲区后立即输出到文件中,而不是等程序结束去刷新。
#include <stdio.h>
//更新缓冲区数据到文件中保存,避免断电丢失
int fflush(FILE *stream);
4. 其他
stat()/fstat()
获取文件状态信息
#include <sys/types.h>
#include <sys/stat.h>
//filepath 文件路径
//buf 保存文件信息的结构体
int stat(const char *filepath, struct stat *buf);
//fd 是文件描述符
int fstat(int fd, struct stat *statbuf);
//stat结构体定义
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* 总大小Total size, in bytes */
blksize_t st_blksize; /* 文件块大小 Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
//案例 使用 fstat 输出文件属性
FILE * file = fopen("test.txt","r");
struct stat fileStat;
fstat(file->_fileno,&fileStat);
printf("%ld\n",fileStat.st_size);
fclose(file);
remove()
删除文件
#include <stdio.h>
int remove(const char *pathname);
rename()
文件更名
#include <stdio.h>
//oldpath 当前文件名 ; newpath 新文件名 相对路径或者绝对路径
int rename(const char *oldpath, const char *newpath);