文件IO与标准IO(超详细 建议收藏)

C库是标准的,统一的,我们只要基于C库写代码就可以跑在各种平台上

Linux系统,他用的并不是标准的C库,而是glibc。

标准C库:又称为标准IO

glibc库:  又称为文件IO

一、标准IO:

它是标准C库提供的,可以跑在各个系统上

1.fopen:

函数模型:

#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

实现代码:

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

1.文件结尾了

int feof(fp); 1:文件结束,0文件未结束

2.错误发生了

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

  1. 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;

}

猜你喜欢

转载自blog.csdn.net/qq_53676406/article/details/129025362