文件编程


==============================================================================

LINUX

1. LINUX几乎将所有的东西看成是文件(网络稍微特殊点)

文件:一组相关数据的有序集合。

文件按类型分类:

1、常规文件:ASCII码文件、二进制的文件

2、目录

3、字符设备

4、块设备

5、有名管道

6、套接口

7、符号连接

 

2. 应用实现策略,驱动实现机制

 

 

对文件进行操作的两种方式:

------------------------------------------------------------------------------

1.标准IO(标准C库函数)不依赖于系统,建立在系统调用的基础上,带缓冲

2.文件IO(系统调用)依赖于系统,不同的系统有差异

IO: In/Out,输入/输出,对文件进行读写

 

系统调用和库函数的差别

------------------------------------------------------------------------------

LINUX系统中大概有200多个不到300个系统调用函数

库函数可以有很多。 比如数学库,浮点库(不需要系统调用)

系统调用与库函数的比较

    所有的操作系统都提供多种服务的入口点,通过这些入口点,程序向内核请求服务

    从执行者的角度来看,系统调用和库函数之间有重大的区别,但从用户的角度来看,其区别并不非常的重要。

    应用程序可以调用系统调用或者库函数,库函数则会调用系统调用来完成其功能,库函数并不必须需要系统调用,比如数学库,浮点库

   系统调用通常提供一个访问系统的最小界面,而库函数通常提供比较复杂的功能。

 

 

标准IO与文件IO最大差别:

------------------------------------------------------------------------------

  标准IO 有缓冲,文件IO无缓冲 

  

 

标准IO基本概念:

------------------------------------------------------------------------------

  标准IO,由库在内存中开辟一个缓冲区,读写的时候是对缓冲区操作,以提高系统的效能

 

1. 缓冲区分三种类型:一般缓冲区的最佳大小:1024 或者是 4096 (查看系统缓冲的命令:ulimit -n

    全缓冲:

当填满I/O缓冲后才进行实际I/O操作(缓冲区满, 文件关闭调用fflush()

    

行缓冲(当且仅当标准输入和标准输出不涉及交互式设备时是全缓冲

        当在输入和输出中遇到新行符(\n)时,进行I/O操作('\n', fflush(), 进程结束/文件关闭)

        

不带缓冲(标准错误输出就是不带缓冲):

 

标准出错是不带缓冲的,打开至终端设备的流是行缓冲;其他所有流则是全缓冲。

 

  2.改变缓冲的特性:(做了解)

   2.1. setbuf()setvbuf()可以更改缓冲的类型 

   //这两个函数将使得打开文件后,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。

void setbuf(FILE *steam, char *buf);  //把缓冲区与流相联 参数buf必须指向一个长度为BUFSIZ的缓冲区。

程序例

#include <stdio.h> 

 

/* BUFSIZ is defined in stdio.h */ 

char outbuf[BUFSIZ]; 

 

int main(void) 

   /* attach a buffer to the standard output stream */ 

   setbuf(stdout, outbuf); 

 

   /* put some characters into the buffer */ 

   puts("This is a test of buffered output.\n\n"); 

   puts("This output will go into outbuf\n"); 

   puts("and won't appear until the buffer\n"); 

   puts("fills up or we flush the stream.\n"); 

 

   /* flush the output buffer */ 

   fflush(stdout); 

 

   return 0; 

 

int setvbuf(FILE *stream, char *buf, int type, unsigned size); 

type 值含义

  _IOFBF 文件全部缓冲,即缓冲区装满后,才能对文件读写

  _IOLBF 文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写

  _IONBF 文件不缓冲,此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲

程序例

#include <stdio.h> 

 

int main(void) 

   FILE *input, *output; 

   char bufr[512]; 

 

   input = fopen("file.in", "r+b"); 

   output = fopen("file.out", "w"); 

 

   /* set up input stream for minimal disk access, 

  using our own character buffer */ 

   if (setvbuf(input, bufr, _IOFBF, 512) != 0) 

  printf("failed to set up buffer for input file\n"); 

   else 

  printf("buffer set up for input file\n"); 

 

   /* set up output stream for line buffering using space that 

  will be obtained through an indirect call to malloc */ 

   if (setvbuf(output, NULL, _IOLBF, 132) != 0) 

  printf("failed to set up buffer for output file\n"); 

   else 

  printf("buffer set up for output file\n"); 

 

   /* perform file I/O here */ 

 

   /* close files */ 

   fclose(input); 

   fclose(output); 

   return 0; 

 

   2.2.使用fflush()强制刷新    

     形式:   int fflush(FILE *stream);

 

  

  3.文件指针:

    每个被使用的文件都在内存中开辟一个区域,用来存放文件的有关信息,这些信息是保存在一个结构体类型的变量中,该结构体类型是由系统定义的,取名为FILE

FILE *, 文件指针指向FILE结构体 

 

FILE 结构体: /usr/include/libio.h   

    struct _IO_FILE {

      /*读写文件指针位置*/

      char* _IO_read_ptr;   /* Current read pointer */

    char* _IO_read_end;   /* End of get area. */

    char* _IO_read_base;  /* Start of putback+get area. */ 

      //...

       int _fileno;  //文件IO关联

       

   };      

  

  4.流:

    标准I/O库的所有操作都是围绕流(stream)来进行的,在标准I/O中,流用FILE *来描述。

   

    

  5.每个进程在创建的时候,会自动打开3个标准终端:

  ------------------------------------------------------------------------------------------------  

 描述            文件指针(FILE *)    文件描述符(int)  文件描述符对应的宏(int)   

1.标准输入(行缓冲)            stdin                   0                STDIN_FILENO                 

2.标准输出(行缓冲)           stdout                  1                STDOUT_FILENO             

3.标准错误输出(无缓冲)   stderr                  2                STDERR_FILENO             

 

  

  

    

 6.标准IO的库函数

 --------------------------------------------------------------------------------------------------

 6.1.fopen() //按照指定方式打开一个流

   形式:

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

      mode:

   主要特性: r(read),w(write),a(add), b(binary)

       附加特性: + (增加读写的另外特性)

         操作ASCII的文件: r+, w+, a+ 

         操作二进制:rb+, wb+ ab+

freopen()//重定位流

FILE *freopen(const char *path, const char *mode, FILE *stream);

---------------------------------------------------------------

例子:freopen("1.txt", "w+", stdout);//stdout重定位到文件1.txt

思考:如何再定位回来?/dev/tty

 

  

   附:errno: 错误号 /usr/include/asm-generic/errno-base.h

 

全局错误码errno:每个进程或线程独有自己独立一个errno,它记录的是上一次出现错误的原因(错误号)

#include <errno.h>

 EACCES          Permission denied (POSIX.1) //权限不允许

 EAGAIN          Resource temporarily unavailable  //资源临时不可用    

 EBUSY           Device or resource busy   //设备忙

 EEXIST          File exists      //文件已经存在

 EINTR           Interrupted function call, // 被“中断”打断

  相关函数:

error(3), perror(3), strerror(3)  

    

    // FIX!!!   fopen()没有设定创建文件权限的参数,可以通过umask命令修改

创建文件的默认权限:0666&~umask  umask默认为0002  则文件权限是0664

创建目录的默认权限:0777&~umask  umask默认为0002  则目录权限是0775

umask         文件            目录


   

   6.2.int fclose(FILE *stream)//关闭流

   

   6.3.对文件的读写:

   6.3.1.一个字符读:

int fgetc(FILE *stream)//函数

int getc(FILE *stream)//

int getchar()//等价于getc(stdin)//

返回值:出错或到达文件尾均为EOF(-1),正确为读到的字符

注意:不管是出错还是到达文件尾端,这三个函数都返回同样的值。为了区分这两种不同的情况,必须调用ferror()feof()

 

文件结束判断:

   feof()

   判断文件是否结束,可用于二进制文件和ASCII文件

   int  ch;

while (!feof(fp) && !ferror(fp)) {

  ch = fgetc(fp);

   } 

 

 

6.3.2.一个字符写:

int fputc(int c, FILE *stream)//函数

int putc(int c, FILE *stream)//

int putchar(int c)//等价于putc(c,stdout)//

返回值:出错为EOF(-1),正确为写的字符c

***********************************************************************

6.3.3.一行读:

char *gets(char *s)//不含换行符,容易造成缓冲区溢出, 绝对不推荐使用

char *fgets(char *s, int size, FILE *stream)//会加入换行符

返回值:成功返回s指针,处于文件尾端或出错则为NULL

 

6.3.4.一行写:

int  puts(const char *s);//虽然不会溢出但会自动加入一个换行符,不推荐使用

int  fputs(const char *s, FILE *stream);

返回值:若成功则为非负值,若出错则为EOF

 

***********************************************************************

6.3.5.直接读:

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

 

6.3.6.直接写:

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

 

两个函数的返回值:读或写的对象数


 

 

  7.扩展函数:

   ftell(): 

     形式long ftell(FILE *stream);

     ftell()用于取得当前的文件指针位置,并不调整文件指针

   fseek()

    形式:

       int fseek(FILE *stream, long offset, int whence);

       调整文件指针到 whence + offset

       第三个参数:whence

         SEEK_SET:  调整文件指针到文件起始位置

         SEEK_CUR:  调整文件指针到当前位置

         SEEK_END: 调整文件指针到文件结束

         

   void rewind(FILE *stream)等价于(void)fseek(stream, 0L, SEEK_SET)  //把文件指针调整到文件头

     

         

  8.时间相关函数

世界标准时间:格林威治标准时间(1970110)

time_t time(time_t *tloc)//获取日历时间,即从1970110点到现在所经历的秒数。

struct tm *gmtime(const time_t *timep)//将日历时间转化为格林威治时间,并保存至tm结构。

struct tm *localtime(const time_t *timep)//将日历时间转换为本地时间,并保存至tm结构。

/*struct tm分解时间表示*/

struct tm {

int tm_sec;      /* 秒 – 取值区间为[0,59] */

int tm_min;      /* 分 取值区间为[0,59] */

int tm_hour;     /* 时 取值区间为[0,23] */

int tm_mday;     /* 一个月中的日期 取值区间为[1,31] */

int tm_mon;      /* 月份(从一月开始,0代表一月) 取值区间为[0,11] */

int tm_year;     /* 年份,其值等于实际年份减去1900  tm_year+1900=实际年份*/

int tm_wday;     /* 本周第几日,其中0代表星期天,1代表星期一,以此类推 */

int tm_yday;     /* 本年第几日,其中0代表11日,1代表12日,以此类推 */

int tm_isdst;    /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst0;不了解情况时tm_isdst()为负。*/

};

 

char *asctime(const struct tm *tm)//tm格式的时间转化为字符串,如:Sat  Jul  30  08:43:03  2005

char  *ctime(const time_t *timep)//将日历时间转化为本地时间的字符串形式。

 

unsigned int sleep(unsigned int seconds)//使程序睡眠seconds

void usleep(unsigned long usec)//使程序睡眠usec微秒。

 

======================================================================================================

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值