I/O文件操作

一、回顾

之前在C语言中我们也接触到了一些文件操作的函数,因为这些函数都是对流操作的,绝大多数流都是完全缓冲的,读操作和写操作都是在缓冲区进行的,用于输出流的缓冲区只有当被写满的时候才会被舒心到设备或者文件。这样的效率很高。

FILE*fp=fopen(const char*filename,const char*mode);//打开流 filename:文件名  mode:打开的方式
int fclose(FILE*stream)//关闭流
int fgetc(FILE*stream);//字符串输入函数(所有输入流)
int fputc(int c,FILE*stream);//字符串输出函数(所有输出函数)
char*fgets(char*string,int n,FILE *stream)//文本行输入函数  所有输入流
int fputs(const char*string,FILE*stream)//文本行输出流  所有输出流
int fscanf( FILE *stream, const char *format [, argument ]... );//格式化输入函数 所有输入流
int fprintf( FILE *stream, const char *format [, argument ]...);//格式化输出函数  所有输出流
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );//读文件  
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );//写文件

用C语言里面的文件操作函数fopen fscanf实现一个简易版的英语词典,可以帮助记单词的呦!但是首先提前你得自己将单词整理出来写到文件里面,才能从dictionary.txt里面读取向要查看的单词!

 #include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
  typedef struct
  { 
      char yy[50]; 
      char hy[50];
      char cx[6]; 
  }DICT_T;
  DICT_T words[8000];
  int cunt=0; 
  void load_file(void)
  {        
     FILE *fp=fopen("dictionary.txt","r");
    if(fp==NULL)perror("fopen"),exit(1);
      while(!feof(fp)) 
     {
          fscanf(fp,"%s\t%s\t%s",words[cunt].yy,words[cunt].hy,words[cunt].cx);
         cunt++;
      }

     fclose(fp);
  }
 int bin_search(const char*buf)
 {
      int l=0;
     int r=cunt-1;
     while(l<=r)
     {
         int m=l+(r-l)/2;
          if(strcmp(words[m].yy,buf)==0)
         {
             return m;
        }
         else if(strcmp(words[m].yy,buf)<0)
        {
            l=m+1;
         }
         else
        {
            r=m-1;
         }
     }
    return -1;
 }
 int main(void)
 {
    load_file();
    int r;
    char buf[1000];
    do
    {
        printf("please input a word:");
        memset(buf,0x00,sizeof(buf));
        scanf("%s",buf);
       if((r=bin_search(buf))==-1)
      {
            printf("have no this word\n");
        }
         else
        {
           printf("%s :%s %s\n",words[r].yy,words[r].hy,words[r].cx);
        }
     }while(1);
    return 0;
 }

二、Linux的基本I/O函数

在此之前先来认识一下文件描述符。
文件描述符:操作系统通过一个整数代表打开的文件,将这个整数称为文件描述符。
在shell日常操作中,有3个文件描述符是是始终打开的:
- stdin 0 标准输入
- stdout 1 标准输出
- stderr 2 标准错误
文件描述符中所存储的信息:

  • 文件指针
  • 文件的打开次数(引用计数)
  • 文件的磁盘位置
  • 文件的访问权限
    ####打开文件####
int open(const char*path,int flags);
//参数: 
//path:要打开的文件
//flags:要打开的方式
//返回值:
    //成功返回文件描述符
    //失败:返回-1,并将errno置为相应的错误

flags的可能取值:
这里写图片描述

读操作
int read(int fd,char*buff,size_t len);//从文件fd中读取数据到buff所指向的空间,该空间的大小为len
/*
参数:
    buff:用来存放输入数据的内存缓冲区地址,缓冲区至少应该有len个字节,缓冲区的大小至少要比预计读取的最大字符串长度多出1个字节
    len:读取的数据的长度
返回值:
    调用成功返回实际读取的字节数
    遇到文件结束标志返回0
    出现错误返回-1
*/
打开文件/创建文件
int open (const char*path,int flags,mode_t mode);
/*
参数:
    path:要创建的文件名
    mode:权限,会受到默认的umask的影响,mode参数牙可以指定为数字,也可以使用flags的常量区进行逻辑或操作
    flags:O_CREAT | O_RDONLY//创建一个文件只能读
          OCREAT | O_EXECL//O_EXECL只能和CREAT共用   
*/

我们来用一下open函数真切地感受一下它的用法:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
 int main(void)
 {
     int fd=open("open.c",O_RDONLY);
    if(fd==1)
     {
         perror("open");
     }   
     else
    {
        printf("open sucessful\n");
    }   
     while(1)
    {
         char buf[11]={};
         int r=read(fd,buf,10);
         if(r==-1)perror("read"),exit(1);
         if(r==0)
         {
             printf("read over\n");
             break;
        }   
         else
         {
            printf("%s",buf);
            fflush(stdout);
        }
       sleep(1);
     }
    close(fd);
     return 0;
 }
写操作
int write(int fd,const char *buff,size_t len)//向fd所指向的文件中写入数据,数据的起始地址为buff(buff设置为磁盘块的大小读取是最快的),大小为len。
/*
返回值:
    调用成功返回实际写入文件的字节数,该返回值可能小于len参数值,这被称为部分写,对于磁盘来说,造成部分写的原因可能是由于磁盘已满,或是因为进程资源对文件大小的限制
    对于磁盘进行I/O操作时,write()调用成功并不能保证数据已经写入磁盘,因为为了减少磁盘活动量和加快write()系统调用,内核会缓存磁盘的I/O操作。
*/

我们来用一下write函数真切地感受一下它的用法:注意这里这个spider文件要提前创建好,使用touch spider就可以啦!

 #include<string.h>
 #include<stdio.h>
 #include<stdlib.h>
 #include<unistd.h>
 #include<fcntl.h>
int main(void)
  {
     int fd=open("spider",O_CREAT|O_RDWR|O_EXCL,0666);
    if(fd==-1)
     {
         fd=open("spider",O_RDWR);
         if(fd==-1)
            perror("open"),exit(1);
    }
     char*msg="this is mmc";
     int r=write(fd,msg,strlen(msg));
    printf("len=%d,r=%d\n",strlen(msg),r);
     close(fd);
    return 0;
 }
关闭文件
int close(int fd);//close系统调用关闭一个打开的文件描述符,并将其释放回调用进程,供进程继续使用
定位操作
int lseek(int fd,off_t offset,int whence);
/*
参数:
    offset:偏移量
    whence:
        SEEK_SET:将文件偏移量设置为从文件头部起始点开始的offset个字节
        SEEK_CUR:相对于当前文件偏移量,将文件偏移量调整offset个字节
        SEEK_END:将文件偏移量设置为起始于文件尾部的offset个字节
返回值:
    新的相对于文件开头偏移量
    获取文件的大小:lseek(fd,0,END);
*/
  • 文件空洞:
    如果文件的偏移量已经超过了文件的结尾,然后再执行I/O操作,read()调用将会返回0,write()调用可以在文件结尾后的任意位置写入数据。从文件结尾后到新写入数据间的这段空间被称为文件空洞。
  • 注意:

    • 在文件空洞中写入了数据,文件系统才会为之分配磁盘块
    • 空洞的存在意味着一个文件名义上的大小可能要比其占用内存的磁盘存储量大很多,向文件写入字节,内核需要为其分配存储单元,即使文件大小不变,系统的可用磁盘空间也会减少。
    • du:可以查看文件具体占磁盘块的大小,磁盘块是惰性分配的

    文件操作就讲到这里啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值