linux文件 IO

拜拜、爱过 提交于 2020-02-11 01:22:36

系统调用:

由操作系统实现并提供给外部应用程序的编程接口,是应用程序同系统之间数据交换的桥梁

open 函数:

int open (char* pathname,int flags)  #include<unistd.h>
	参数:
	pathname :欲打开的文件路径名

	flags :文件的打开方式 :  O_RDONLY | O_WRONLY | O_RDWR  
	
	O_CREAT|O_APPEND(追加)|O_TRUNC(文件清零)|O_EXCL|O_NONBLOCK(设置非阻塞)

返回值: 

	成功: 打开文件所得到的 对应 文件描述符(整数)

	失败: -1 ,设置 errno

int open(char* pathname,int flags, mode_t mode)

	open(pathname,O_RDONLY |O_CREAT ,0664);

参数:

	pathname:欲打开文件路径名

	flags: 文件打开方式: O_RDONLY | O_WRONLY | O_RDWR  O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK

	mode: 参数3使用前提 惨2指定了 O_CREAT 取值8进制数,用来描述文件的访问权限

		创建文件的最终权限  mode& ~umask

返回值: 

	成功: 打开文件所得到的 对应 文件描述符(整数)

	失败: -1 ,设置 errno

close函数:

int close (int fd)

错误处理函数: 与errno相关

printf(“xxxerrno%d\n”,errno)

char* strerror(int errno)

	printf("xxx error:%s\n",strerror(errno))

void perror(const char* s);

	perror("open error");

read 函数:

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

参数:

	fd:文件描述符

	buf:存数据的缓冲区

	count:缓冲区大小

返回值:

	0:读到文件末尾

	成功: 读到的字节数

	失败:—1 设置errno 并且errno = EAGIN 或 EWOULDBLOCK ,说明不是read 失败, 

		而是read在以非阻塞的方式读一个设备文件或网络文件,并且文件无数据

write 函数:

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

参数:

	fd:文件描述符

	buf:待写出数据的缓冲区

	count:数据大小

返回值:

	成功: 写入的字节数

	失败:—1 设置errno

strace命令:

跟踪程序执行,查看调用的系统函数

read write 实现 cp

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

int main(int argc,char* argv[]){
  (void) argc;

  char buf[1024];

  int n=0;

  int fd1 = open(argv[1],O_RDONLY);
  if (fd1==-1){
    perror("open argv1 error");
    exit(1);
  }
  int fd2 = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);

  if (fd2==-1){
    perror("open argv2 error");
    exit(1);
  }


  while(n=read(fd1,buf,1024)){
    printf("读到字节数:%d\n",n);
    if(n<0){
      perror("read error");
      break;
    }
    write(fd2,buf,n);
  }
  close(fd1);
  close(fd2);

  return 0;

}

库函数和系统调用的比较

#include<stdio.h>
#include<stdlib.h>


int main(){

  FILE* fp,*fp_out;
  int n;

  fp = fopen("dixt.txt","r");
  if(fp==NULL){
    perror("fopen error");
    exit(1);
  }
  fp_out = fopen("dict.cp","w");
  if(fp==NULL){
    perror("fopen error");
    exit(1);
  }
  while((n = fgetc(fp))!= EOF){
    fputc(n,fp_out);


  }
  fclose(fp);
  fclose(fp_out);
  return 0;
}

include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<errno.h>

#define N 1

int main(){
  int fd,fd_out;
  int n;
  char buf[N];

  fd = open("dixt.txt",O_RDONLY);
  if(fd<0){
    perror("open dict.txt error");
    exit(1);
    
  }
  fd_out = open("dict.cp",O_WRONLY|O_CREAT|O_TRUNC,0664);
  if(fd<0){
    perror("open dict.cp error");
    exit(1);
  }
  while((n = read(fd,buf,N))){
    if(n<0){
      perror("read error");
      exit(1);
    }
    write(fd_out,buf,n);
  }
  close(fd);
  close(fd_out);
  return 0;
}

预读入缓输出机制

在这里插入图片描述

结论

1.每一次读写操作都会发生用户态内核态转换 耗费时间较长
2.库函数 还有一个缓冲区 大小4096字节 切换状态少速度快
系统调用 每次读或写一个字节 频繁切换状态 速度慢。

因此 能用库函数尽量用库函数 ,数据较小时库函数 4096 缓冲区没满 通讯实时性无法得到保障 因此当一次性读写数据较少时用系统调用。

文件描述符:

pcb进程控制块 :本质 结构体

成员: 文件描述符表

文件描述符: 0/1/2/3/4/...1023  最小未使用

0 -STDIN__FILENO

1 -STDOUT_FILENO

2 -STDERR_FILENO

阻塞 非阻塞: 是设备文件、 网络文件的属性 不是read write 的属性

	产生阻塞的场景 读设备文件 读网络文件 (常规文件无阻塞概念)

	/dev/tty --终端文件

	open("dev/tty",O_RDWR | O_NOBLOCK)  --设置/dev/tty 非阻塞状态(默认为阻塞状态)

fcntl:

int flgs = fcntl(fd ,F_GETFL)

flgs |= O_NONBLOCK

fcntl(fd,F_SETFL,flgs)

获取文件状态: F_GETFL

设置文件状态: F_SETFL

lseek函数:

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

参数:

	fd:文件描述符

	offset:偏移量

	whence:起始偏移位置,SEEK_SET(起始)/SEEK_CUR(当前)/SEEK_END(末尾)

返回值:

	成功: 较起始位置偏移量

	失败:-1 errno

应用场景:

	1.文件的“读”、“写”使用同一偏移位置
	列如:先read 10字节 再write时  从第11字节开始写
//文件的“读”、“写”使用同一偏移位置
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>

int main(){



  char* buf = "woxiangnile\n";
  int n;
  char ch;
  int fd = open("lseek.txt",O_RDWR | O_CREAT,0664);
  write(fd,buf,strlen(buf));
  //将光标移到起始位置 
  lseek(fd,0,SEEK_SET);
  	

  while(n=read(fd,&ch,1)){
    if(n==-1){
      perror("read errro");
    }
    write(STDOUT_FILENO,&ch,n);

  }

  return 0;

}

	2.使用lseek获取文件大小
//使用lseek获取文件大小
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main(int argc,char* argv[]){
  (void)argc;
  int fd = open(argv[1],O_RDWR);
  if(fd==-1){
    perror("open error");
    exit(1);
  }
  int lenth = lseek(fd,0,SEEK_END);
  printf("file size:%d\n",lenth);


  close(fd);

  return 0;
	3.使用lseek 拓展文件大小 要想使文件大小真正拓展,必须引起IO操作。

		使用 truncate 函数,直接拓展文件 int ret = truncate(“dict.cp”,250)
		将文件的大小拓展为 250
//将文件拓展增加 101个字节
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main(int argc,char* argv[]){
  (void)argc;
  int fd = open(argv[1],O_RDWR);
  if(fd==-1){
    perror("open error");
    exit(1);
  }
  int lenth = lseek(fd,100,SEEK_END);
  printf("file size:%d\n",lenth);

 write(fd,"a",1);
  close(fd);

  return 0;
}

传入参数:

1.指针作为函数参数

2.用const修饰

3.指针指向有效区域,在函数内部做读操作

传出参数:

1.指针作为函数参数

2.在函数调用之前,指针指向的空间可以无意义,但必须有效

3.在函数内部,写操作

4.函数调用结束后,充当函数返回值

传入传出参数:

1.指针作为函数参数

2,在函数调用之前,指针指向的空间有实际意义

3.在函数内部,先做读操作,后做些操作

4.函数调用结束后,充当函数返回值。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!