C库是标准的,统一的,我们只要基于C库写代码就可以跑在各种平台上
Linux系统,他用的并不是标准的C库,而是glibc。
标准C库:又称为标准IO
glibc库: 又称为文件IO
一、标准IO:
它是标准C库提供的,可以跑在各个系统上
1.fopen:
(1)函数模型
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
path:指定文件路径
mode:打开方式
r:以只读方式打开
r+:读和写
w:写文件方式打开,写之前将文件清空,如果文件不存在则创建
w+:读写文件方式打开,写之前将文件清空,如果文件不存在则创建
a:追加(w)方式打开文件,如果文件不存在则创建
a+:追加(rw)方式打开文件,如果文件不存在则创建
返回值:文件指针,指向了你要求打开的文件,后续fread fwite fclose都是用该指针访问文件
失败:NULL 错误原因,记录在errno
(2)实现代码
FILE *fp;//定义文件指针fp
fp = fopen("./test.txt","r");//以只读方式打开当前路径下的test.txt文件
if(fp==NULL){//判断
perror("fopen err"); //类似于 printf("fopen err:%s\n",strerror(errno));
return -3;
}
perror:找出错误,自动追加错误原因,类似于printf(“fopen err:5s\n”,strerror(erno));
2.fread:
函数模型
#include<stdio.h>
ret=fread(fp,buf,size)
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
stream:文件指针,表示该文件(硬盘中的文件)
ptr:指向存放数据的内存
size:建议为1,所以number block就是我们读取的大小
nmemb:number block,要读取的大小是size *nmemb
返回值:返回的是成功读取到的块的个数,注意返回的值可能和要求读取的nmemb不一致,因为读到了文件尾部。
如果不等于你要亲自区分 feof ferror
文件结尾了
int feof(fp); 1:文件结束,0文件未结束
错误发生了
int ferror(fp) 1:错误发生
举个例子:
(1)首先,创建一个文件,输入相应内容
(2)然后进行读取,就可看到输入的内容已经完全被读取出来
实现代码:
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc,char **argv)
{
int ret;
FILE *fp;
char buf[17];
fp = fopen("./test.txt","r");
if(fp==NULL){
printf("#fopen err errno=%d des:%s\n",errno, strerror(errno));
perror("fopen err"); //类似于 printf("fopen err:%s\n",strerror(errno));
return -3;
}
while(1){
memset(buf,0,sizeof(buf)) ;
ret = fread(buf,1, sizeof(buf)-1, fp);
if( ret!= (sizeof(buf) -1 ) ){ //两种情况
int rett = feof(fp);
if(rett){
printf("%s\n",buf);;
printf("fread eof\n");
break;
}
rett = ferror(fp);
if(rett){
perror("fread err"); //printf("fread err %s",strerror(errno) );
return 0;
}
}
printf("%s",buf);
}
ret = fclose(fp);
if(ret<0){
printf("fclose err\n");
return -3;
}
return 0;
}
3.fwrite:
函数模型
int fwrite(fp, buf,size )
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
stream: 硬盘上的file
ptr, 存放数据的buf指针
size,nmemb: 将ptr内存中data,写入文件stream, 写入 nmemb块数据,每块大小size
返回值:实际写入的块个数
失败: 如果返回的结果小于要求的nmemb
实现代码:
#include <stdio.h>
#include <errno.h>
#include <string.h>
/*
用法:
./mycopy.out src.txt dst.txt
程序获取这两个文件,然后将src_file内容拷贝到dst_file中.
关键点: 程序如何获取 两个传参
*/
int main(int argc,char **argv)
{
/*
argc 表示参数的个数 , 注意程序本身也算1个
argv 他是一个 字符串数据,存放的参数
argv[0] 表示传递的第0个参数, 表示的是程序本身
...
argv[x] ...............
*/
int ret;
FILE *fp_src, *fp_dst;
char buf[16];
if(argc!=3){
printf("sorry,pls input correct argument\n");
return -3;
}
//打开源文件
fp_src = fopen(argv[1],"r");
if(fp_src==NULL){
perror("fopen src err"); //类似于 printf("fopen err:%s\n",strerror(errno));
return -3;
}
//创建空文件
fp_dst = fopen(argv[2],"w");
if(!fp_dst){
perror("fopen dst err");
return -4;
}
while(1){
memset(buf,0,sizeof(buf)) ;
ret = fread(buf,1, sizeof(buf) , fp_src);
if( ret!= sizeof(buf) ){ //两种情况
int rett = feof(fp_src); //file end,last read
if(rett){
ret = fwrite(buf,1,sizeof(buf), fp_dst);
printf("fread eof\n");
break;
}
rett = ferror(fp_src);
if(rett){
perror("fread err"); //printf("fread err %s",strerror(errno) );
return 0;
}
}
//将buf内容,写入到 fp_dst
ret = fwrite(buf,1,sizeof(buf), fp_dst);
if( ret< sizeof(buf) ){
perror("fwrite err");
return -12;
}
}
ret = fclose(fp_src);
if(ret<0){
printf("fclose err\n");
return -3;
}
fclose(fp_dst);
return 0;
}
4.fclose:关闭文件
函数模型
int fclose(FILE *stream);
stream表示文件指针,fopen 操作的时候来的
返回值:0 success
EOF: -1 表示失败, errno记录失败原因
实现代码:
ret = fclose(fp);
if(ret<0){
printf("fclose err\n");
return -3;
}
了解fgetc/fputc:
fgetc,从文件中读取一个char
fputc,将一个char,写入到文件中
实现代码:
int fputc(int c,FILe *fp)
{
ret = fwrite(&c,1,1, fp);
if(ret < 1){
return EOF;
}
fgets:从文件中读取一行数据
5.文件(位置)指针:
他是一个整数,记录了文件当前的访问位置,open的时候,pos=0;读写函数都会修改它,从而保证了连续读和写,同样,我们可以手动改变它操作
(1)获取文件当前访问 int ftell(fp)
(2)修改文件当前位置
函数模型
int fseek(FILE *stream, long offset, int whence);
offset: 偏移量 负值表示往前挪 正值表示往后挪
whence: 指定相对于 谁(头 尾 当前位置) 便宜
SEEK_SET 相对于文件头 offset恒大于0
SEEK_CUR 相对于当前位置 左右自由移动
SEEK_END 相对于尾部 恒小于0
例如:读取尾部10个字符,获取文件大小
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc,char **argv)
{
FILE *fp = fopen("./test.txt","r+");
if(!fp){
perror("fopen err");
return -34;
}
printf("file access position =%ld\n", ftell(fp));
char buf[16] = {0};
int ret = fread(buf,1,sizeof(buf),fp);
printf("file access position =%ld\n", ftell(fp));
strcpy(buf,"TTTTTTTTTTTTTTTT");
ret = fwrite(buf,1,strlen(buf),fp);
if(ret < strlen(buf) ){
perror("fwrite err");
return -9;
}
printf("file access position =%ld\n", ftell(fp));
return 0;
}
二、文件IO
-
open
函数模型:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
pathname:文件路径和名字 可选:绝对路径和相对路径
flags:打开的模式
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_CREAT 创建,文件不存在则创建
O_RDWR|O_CREAT
O_TRUNC 清空文件
O_TRUNC|O_WRONLY
int open(const char *pathname, int flags, mode_t mode);mode,当且仅当 flags包含 O_CREAT的时候才有效,用来指定 新创建文件的 权限(rwx) ,一般是0666
返回值:
成功返回文件描述符, 他是大于0的整数
-1,失败, 原因记录在errno中
2.read
函数模型:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符
buf: 存放数据的
count: 你要求读取的大小
返回值:
正数: 实际读取的大小
0: 表示文件没数据啦(结束了)
-1/负数: 失败/出错 errno
3.write
函数模型:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd: file descriptor ,代表了这个文件
buf: 要写入的内容
count:要写入的个数
返回值:
正值/0: 实际写入的个数
-1: 错误,errno 表示错误原因
4.fseek/ftell-->lseek
函数模型:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
whence:你想调整文件位置,相对于谁(头,尾,当前位置)开始调整
SEEK_SET 相当于头文件 offset>=0
SEEK_CUR 相当于当前文件 可正可负
SEEK_END相当于尾部 只能是<=0
返回值:正值/0:表示调整之后,距离文件头部的位置
-1:错误,errno
应用:
1.获取文件当前位置
int position = lseek(fd,0,SEEK_CUR);
2.回到文件头部
int pos = lssek (fd,SEEK_SET );
3.获取文件大小
int size = ( fd,0,SEEK_END) ;
4.读取文件尾部
lseek (fd,-XX,SEEK_END);
实现代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd;
fd = open("./test.txt",O_RDONLY);
if(fd <0){
perror("open err");
return -3;
}
printf("open location:%d\n", (int)lseek(fd,0,SEEK_CUR) );
char buf[16];
int ret = read(fd,buf,sizeof(buf));
if(ret <0){
perror("read err");
return -34;
}
printf("read location:%d\n", (int)lseek(fd,0,SEEK_CUR) );
/*获取文件大小*/
printf("file size=%d Byte\n", (int)lseek(fd,0,SEEK_END) );
/*读取尾部的数据*/
lseek(fd, -11,SEEK_END);
memset(buf,0,sizeof(buf));
ret = read(fd,buf,sizeof(buf));
printf("tail read:%s\n",buf);
close(fd);
return 0;
}
fclose-->close
#inclde<unistd.h>
int close(int fd);
三、其它接口
1.删除文件unlink
函数模型:
#include <unistd.h>
int unlink(const char *pathname);
pathname:文件路径
返回值:
0 success
-1 失败 ,errno
实现代码:
#include <stdio.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int ret = unlink(argv[1]);
if(ret<0){
perror("del file err");
return -34;
}
return 0;
}
2.目录的访问
(1)创建目录:
函数模型:
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
pathname:目录的名字
mode: 目录的权限 r4 w2 ,没有x1
返回值:
0-success
-1: errno
实现代码:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc,char **argv)
{
/*
./mkdir.out xxdir
argv[0] argv[1]
*/
int ret;
ret = mkdir(argv[1],0666);
if(ret<0){
perror("mkdir err");
return -34;
}
return 0;
}
(2)删除目录
函数模型:
#include <unistd.h>
int rmdir(const char *pathname);
返回值:
0-success
-1: errno
注意,它只能删除空目录
实现代码:
#include <stdio.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int ret = rmdir(argv[1]);
if(ret<0){
perror("rmdir err");
return -34;
}
return 0;
}
(3)打开指定目录
函数模型:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *dir_name);
dir_name: 目录的路径名
返回值:
成功:目录的指针
失败: NULL, errno
(4)读取目录中的每一项
readdir每次只返回 目录#项目#的一个,so 你要多次读取,直到读取结束
目录项 概念: 它是 文件和目录的统称, 一个目录项可以是 文件,也可以是目录
目录项 = readdir(ptdir)
struct dirent *readdir(DIR *dirp);
dirp:要读取目录的指针
返回值:
每次调用返回 一个目录项 的指针
如果读取完毕,返回NULL
struct dirent { ## 它描述了一个目录项(文件/目录)
ino_t d_ino;
off_t d_off; not an offset; see NOTES
unsigned short d_reclen; length of this record
unsigned char d_type; 目录4,普通文件8, 管道文件, 设备文件
char d_name[256]; 名字
}
(5)关闭目录
函数模型:
int closedir(DIR *ptdir)
ptdir:前面opendir返回的目录指针
返回值:
0-success
-1: errno
实现代码:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
int main(int argc,char **argv)
{
/*
打开目录
*/
DIR *ptdir = opendir("./testdir");
if(!ptdir){
perror("opendir err");
return -34;
}
/*
读取目录的每一项内容
*/
while(1){
struct dirent * ptdirent = readdir(ptdir);
if(ptdirent == NULL){
printf("readdir end\n");
break;
}
if( ( strcmp(ptdirent->d_name,".")==0 ) ||
( strcmp(ptdirent->d_name,"..")==0 ) ){
continue; //如果发现目录是 ./..,则不作任何处理
}
printf("name:%s type:%d\n",ptdirent->d_name,ptdirent->d_type );
}
/*关闭dir
*/
int ret = closedir(ptdir);
if(ret<0){
perror("closedir err");
return -39;
}
return 0;
}