【启动-嵌入式开发】【第二步】编程基础--Linux下c语言文件操作

1 篇文章 0 订阅
1 篇文章 0 订阅

总结

    文件操作的流程,基本就是四个方面:打开、读、写、关闭,只不过具体细节方面,使用的函数不同。
    其中又细分为文件IO、标准IO、目录IO,接下来,我就从这三个方面,来细细阐明各种相关函数和操作,相关代码,我最后可能会上传github。

一、文件IO

1、 open

1.1 open函数

     int open(const char *pathname,int flags,mode_t mode);
用来打开或创建一个文件

1.2参数解析

三个参数 pathname(文件名和路径) flags(打开文件的方式) mode(权限[真正权限&umask掩码])
其中、最需要说明的是flags

参数意义
O_RDONLY只读
O_WRONLY只写
O_RDWR读写
O_CREAT创建一个文件
O_EXCL如果O_CREAT时,文件存在,择返回错误
O_TRUNC打开文件,删除已经存在的内容
O_APPEND追加,不删除

1.3函数返回

函数返回的是文件句柄,从3开始一直下去,因为标准输入是0,标准输出是1,标准出错是2。

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(){
  int fd = open("./b.txt",O_CREAT,0777);
  printf("fd:%d\n",fd);
  close(fd);
  return 0;
}

2、read

2.1 read函数

ssize_t read(int fd, void *buf, size_t count);

2.2 参数解析

三个参数分别是:从哪读、读到哪,读什么

2.3 函数返回

返回值为实际读的字节数

3、write

3.1 write函数

ssize_t write (int fd, const void * buf, size_t count);

3.2 参数解析

三个参数分别是:从哪读、读到哪,读什么(倒是和read基本一致,只不过,中间的参数修饰符const说明了一切(-_-))

3.3 函数返回

返回值为实际写的字节数

4、close

4.1 close函数

int close(int fd);

4.2 参数解析

见名知意,就是上面open返回的文件句柄。

4.3 函数返回

close() returns zero on success. On error, -1 is returned, and errno is set appropriately. //来自man close (๑•ᴗ•๑)
翻译一下:成功返回0,失败出错返回-1

5、小栗子—实现自己的cp(好吧,既然现实没有cp,那我就自己写一个吧╮(╯_╰)╭)

5.1 功能说明

通过上述四个函数,实现简单的cp功能。main函数接收两个参数,要拷贝的文件,和要拷贝到的文件。具体的,也有一些注释。

5.2 代码实现

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> 
 
int main(int argc,char *argv[]) 
{ 
    int in, out, flag; 
    char buffer[1024];
    //如果输入的参数有误,那就直接返回
    if(argc<3){
      printf("please cin copy file and to copy name!\n");
      return -1;
    }
    //如果打开输入、输出文件出错,那也直接返回
    in = open(argv[1], O_RDONLY,S_IRUSR);
    if (-1 == in) 
    {    
        printf("open copy file failure\n");
        return -2; 
    }   
 
    out = open(argv[2], O_WRONLY|O_CREAT);
    if (-1 == out)
    {   
        printf("open to copy file failure\n");
        return -3; 
    }   
    //循环将in里面的文件读到out里面
    while ((flag = read(in, buffer, 1024)) > 0)
    {   
        write(out, buffer, flag);
    }   
    close(in);
    close(out);
    
    return 0;
}

6、lseek

6.1 close函数

off_t lseek(int fd, off_t offset, int whence);

6.2 参数解析

调谁,偏移多少,当前位置
其中最需要说明的就是whence参数

意义
SEEK_SET当前位置为文件的开头,新位置为偏移量的大小
SEEK_CUR当前位置为文件指针的位置,新位置为当前位置➕偏移量的位置
SEEK_END当前位置为文件的结尾,新位置为当前位置➕偏移量的位置

6.3 函数返回

Upon successful completion, lseek() returns the resulting offset location as measured in bytes from the beginning of the file. On error, the value (off_t) -1 is returned and errno is set to indicate the error.
//来自man lseek (๑•ᴗ•๑)
翻译一下:成功返回当前位置,失败出错返回-1

6.4 小栗子

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

int main(){
  int fd = open("./b.txt",O_CREAT|O_RDWR,0777);
  if(fd<0){
    printf("打开错误!\n");
    return -1;
  }
  char *str="hello linux!";
  char readbuf[128];
  int retval;
  retval=write(fd,str,strlen(str));
  retval=read(fd,readbuf,128);
  printf("第一次读到%d个字节,内容:%s\n",retval,readbuf);
  lseek(fd,0,SEEK_SET);
  retval=read(fd,readbuf,128);
  printf("第二次读到%d个字节,内容:%s\n",retval,readbuf);


  close(fd);
  return 0;
}

好的,到此,简单的文件IO操作就差不多结束了

二、标准IO

    标准IO想要实现的功能,与文件IO也是一致得到,打开(fopen),读(fread),写(fwrite)和关闭(fclose),那么我们为什么有要多次一举的,在已经有了文件IO的基础上,还要来个标准IO呢?……这个我暂时也没想明白((/ □ ))。
    不过呢,文件IO是直接调用内核提供的系统调用函数,头文件是unistd.h。而标准IO是间接调用,头文件是stdio.h(有木有很熟悉,仿佛见到亲人的感觉(o( ̄︶ ̄)o))。
    也正因为如此,所以这两类函数在使用的时候,它们的缓存是有区别的,文件IO的缓存再内核空间,所以

  1. 每打开一个文件,内核在内核空间也会开辟一块缓存,这个缓存就是内核缓存
  2. 文件IO的write就是将用户空间中的缓存写到内核空间的缓存
  3. 文件IO的read就是将内核空间的缓存写到用户空间中的缓存

而标准IO则不一样,遇到一定条件才会写到内核缓存,比如’\n’,或者写满了

1、fopen

1.1 函数

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

1.2 参数解析

第一个是文件名,第二个是模式,以下为man手册内容

   r      Open text file for reading.  The stream is positioned at the beginning of the file.
   r+     Open for reading and writing.  The stream is positioned at the beginning of the file.
   w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.
   w+     Open for reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The stream is positioned at the beginning of the file.
   a      Open for appending (writing at end of file).  The file is created if it does not exist.  The stream is positioned at the end of the file.
   a+     Open for reading and appending (writing at end of file).  
          The file is created if it does not exist.  The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.

总结起来呢,就是只读,读+写,只写、写+读、追加,追加+读

2、fread

2.1 函数

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

2.2 参数解析

第一个是要读的内容的缓存buf,第二个是每一个单元占多少字节,第三个是读的内容有多少单元

3、fwrite

3.1 函数

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

3.2 参数解析

第一个是要写的内容,第二个是每一个单元占多少字节,第三个是要写的内容有多少字节

4、fclose

4.1 函数

int fclose(FILE *stream);
至于参数,就没啥好说的了

5、小栗子

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char *argv[])
{	
	FILE *src_fp, *des_fp;
	if(argc<3)
	{
		printf("please input src and des files\n");
		return -1;
	}
	src_fp = fopen(argv[1],"r");
	if(src_fp==NULL)
	{
		printf("open src file %s failure\n",argv[1]);
		return -2;
	}
	des_fp = fopen(argv[2],"w");
	if(des_fp==NULL)
	{
		printf("open src file %s failure\n",argv[1]);
		return -3;	
	}
	char buf[128]={0};
	int read_ret;
	while(1)
	{
        read_ret=fread(buf,1,128,src_fp);
		fwrite(buf,1,read_ret,des_fp);
        if(read_ret<128){
            break;
        }
	}
	fclose(src_fp);
	fclose(des_fp);
	
	return 0;
}

##最后,需要补充的是,标准IO读写,远不止上面的这一种,还有fputs、fgets,getc,putc,fgetc和fputc,不过上面这种速度最快

6、重定位及刷新缓存

6.1 重定位

int fseek(FILE *stream, long offset, int whence); 调谁,偏移多少,当前位置

whence意义
SEEK_SET当前位置为文件的开头,新位置为偏移量的大小
SEEK_CUR当前位置为文件指针的位置,新位置为当前位置➕偏移量的位置
SEEK_END当前位置为文件的结尾,新位置为当前位置➕偏移量的位置

6.2 刷新缓存

int fflush(FILE *stream); 刷新缓存

补充

需要说明的是,重定位函数也不只上面一个,只不过,这个功能最全,其他还有rewind(FILE *stream) 重置

三、读写函数的三类缓存

最后,在进入目录IO的介绍之前,再对上面做一点补充说明,也就是三类缓存

全缓存

特点

只有写满了缓存,才会调用系统函数
典型的比如 fread和fwrite

行缓存

特点

遇到\n或者缓存写满了,才会调用系统函数

  • 读函数 gets printf fprintf sprintf
  • 写函数 puts scanf
  • 一个字符的读写
    *读 fgetc getc getchar
    *写 fputc putc putchar

无缓存

只要调用这个函数,就会立即将内容写到内核
fputs("……",stderr)

四、目录IO

接下来,也就是本文的最后一节内容,目录IO的操作,其实一样类比文件IO和标准IO的操作流程,打开,写,读,关闭,只不过是具体函数不一样而已。

1、打开

1.1 函数

DIR opendir(const char pathname)
一个参数,也就是目录名

2、写(也就是创建一个目录)

2.1 函数

int mkdir(const char *path, mode_t mode)
两个参数,第一个是目录名,第二个权限

3、读

3.1 函数

struct dirent *readdir(DIR *dirp);
最为复杂,其中返回值为一个结构体,传入的就是open的返回值,而结构体的内容为

 struct dirent {
    ino_t          d_ino;       /* inode number */
    off_t          d_off;       /* not an offset; see NOTES */
    unsigned short d_reclen;    /* length of this record */
    unsigned char  d_type;      /* type of file; not supported
                                   by all filesystem types */
    char           d_name[256]; /* 文件名*/
};

4、关闭

4.1 函数

int closedir(DIR *dirp);

5、重定位

5.1函数

void rewinddir(DIR *dirp);

6、小栗子

实现一个简单读取输入目录,然后输出该目录下全部文件的小demo

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>

int main(int argc,char *argv[]) {
	int ret;
	DIR *dp;
	struct dirent *dir;
	if(argc<2){
		printf("please input open directory name\n");
		return -1;
	}
	dp=opendir(argv[1]);
	if(dp==NULL){
		printf("open mydir failure\n");
		return -2;
	}
	while(1){
		dir = readdir(dp);
		if(dir==NULL){
			break;
		}else{
			printf("inode=%ld\t file_name=%s\n",dir->d_ino,dir->d_name);
		}
	}

	return 0;
}

好的,至此,对于文件IO操作相关的函数,就基本介绍到这了,有空可能会继续丰富吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值