linux——文件编程文件IO

  
  标准IO:
  1.打开 --- fopen ---> hello.c <---> FILE *fp 
  2.读写 
    fgetc/fputc  注: EOF 
    fgets/fputs  
    
    读取结束:
    a.size-1
    b.\n 
    c.EOF 
    
    buf[] =  字符串 '\0'
    
    fputs 
    
    fread/fwrite  
        
  3.关闭
    fclose  
    
    (1).释放堆空间
    (2).fflush 
     
  
  4.定位 
    fseek 
    rewind 
    ftell 
    
 5.其它 
   fflush 
   fprintf 
   sprintf 
   perror 
   feof 
   ferror 
   
 6.缓冲区 
   
   行缓存  满 \n fflush 程序正常结束 
   全缓存  满  fflush 程序正常结束 
   无缓存  
 7.练习 
   touch 
   cat  
   copy  
    
  
文件IO  --- 系统调用 
  1.概念 
    文件描述符 --- 系统调用这组函数中,对打开文件的 标识 
    整型数值 
    0~1023 //1024个 
    
    0 -- stdin 
    1 -- stdout 
    2 -- stderr 
    
  2.基本操作 
    a.打开 --- open  
    b.读写 --- read / write 
    c.关闭 --- close 
    


文件io:
    操作系统为了方便用户使用系统功能而对外提供的一组系统函数。
    称之为 系统调用  
    
    
    其中有个  文件IO
    一般都是对设备文件操作,当然也可以对普通文件进行操作。
    一个基于Linux内核的没有缓存的IO机制
    
    
    
------------------------------------------------------------------
    
文件操作:
         缓存           操作对象                具体操作
标准IO  全缓存/行缓存   文件指针(流指针)FILE *  1.打开 --fopen  
                                                2.读写 
                                                  fgetc/fputc 
                                                  fgets/fputs 
                                                  fread/fwrite 
                                                3.关闭 
                                                  fclose 
                                                4.定位 
                                                  fseek/ftell/rewind 
                                                                                                                                              
                                          
文件IO  不带缓存        文件描述符 (整数)       1.打开 --open 
                                                2.读写 --read/write
                                                3.关闭 --close 
                                                4.定位 --lseek 

    
    


FILE *fp   <--操作系统内核([fileno])--->[1.txt]

//文件IO 
文件描述符 <----------操作系统--------->[1.txt] //硬盘     


stdin  --- 0
stdout --- 1
stderr --- 2

----------------------------------------------------------------        
        
        
        特性:
        .1 没有缓存区 (//可以认为数据直接交给了内核 )
        .2 操作对象不在是流(FILE *),而是文件描述符(整数)
        .3文件描述符
          很小的非负的整数    int   0-1023
          内核每打开一个文件就会获得一个文件    描述符
        
        
    
        
          每个程序在启动的时候操作系统默认为其打开
          三个描述符与流对象匹配:
          0 ==>STDIN_FILENO === stdin
          1 ==>STDOUT_FILENO == stdout
          2 ==>STDERR_FILENO == stderr
          
          stdin,stdout,stderr,===>FILE*
          

库函数:
     优点:
         a.方便,功能多 
         b.可移植性好 
           标准 
     不足:
         c.可能存在 安全性 隐患


系统调用:
     优点:
         a.使用起来,简单 ,功能简单
         b.安全性高 
         c.设备文件 ---- 文件IO      ///dev/video0 ----> fopen();     
     缺点:
         c.很多复杂功能需要自己封装设计
         d.可移植性差 
         


fopen("1.txt","r")
{

   "r"
    open("1.txt",O_RDONLY); 
}


标准IO库:      系统调用 
fopen           open
   r            O_RDONLY
   w            O_WRONLY|O_CREAT|O_TRUNC
   r+           O_RDWR  
   w+           O_RDWR  |O_CREAT|O_TRUNC       
   a            O_WRONLY|O_CREAT|O_APPEND 
   a+           O_RDWR  |O_CREAT|O_APPEND 
   
   
   O_APPEND 
 

封装 

windows NT           
          
          
        ansi c 
         unistd.h ===>POSIX 标准库
fopen    fgetc/s/fread                   system-v  标准
rw-   rw-   r--
110         100
6     6    4
fopen  open 
w           O_WRONLY|O_CREAT|O_TRUNC 
w+          O_RDWR|O_CREAT|O_TRUNC 
r           O_RDONLY 
r+             O_RDWR
a             O_WRONLY|O_CREAT|O_APPEND
a+             O_RDWR|O_CREAT|O_APPEND

open
read /write 
close 
lseek 

库函数 本质上是 对系统调用 的封装 


fopen    open 
r      O_RDONLY 
  r+   O_RDWR
w      //文件存在 
       //文件不存在   fopen(,"w"); ---> open(,O_WRONLY|O_CREAT|O_TRUNC);
       //O_WRONLY|O_CREAT|O_TRUNC 
  w+ 
       //O_RDWR|O_CREAT|O_TRUNC 
a      //O_WRONLY|O_APPEND    
  a+   //O_RDWR|O_APPEND 
a     // O_WRONLY|O_APPEND ==> flags 

2.函数接口
        1.open
       int open(const char *pathname, int flags);

        open("1.c",O_WRONLY|O_CREAT,0666 );
        
        int open(const char *pathname, int flags,int mode);
        功能:
            获得一个文件描述符
        参数:
            pathname:文件名
            flags:
            必须项:他们之间是互斥的,所以有且只能有一个 
                O_RDONLY
                O_WRONLY
                O_RDWR                
                
            可选项:
            O_CREAT, 创建文件  //这个标志量存在,则需要指定参数 mode
            O_EXCL,  需要和O_CREAT同时使用,表示新建的文件不存在,成功,否则open就会失败
            O_TRUNC  文件内容清空
            O_APPEND追加
         
         
          O_RDONLY 
          O_WRONLY|O_APPEND 
          
          
          
          fopen()
          
          r    ---- O_RDONLY
          r+        O_RDWR
          w         O_WRONLY|O_TRUNC|O_CREAT  ,0666 
          w+        O_RDWR|O_TRUNC|O_CREAT ,0666 
          a         O_WRONLY|O_APPEND|O_CREAT ,0666 
          a+        O_RDWR|O_APPEND|O_CREAT ,0666
          
            
eg:
open("hello.c",O_RDONLY); //fopen("hello.c","r");

fopen ----------------open 
"r"                O_RDONLY
"r+"               O_RDWR
"w"                O_WRONLY|O_CREAT |O_TRUNC,0666
"w+"               O_RDWR  |O_CREAT |O_TRUNC,0666
"a"                O_WRONLY|O_APPEND|O_CREAT,0666   
"a+"               O_RDWR  |O_APPEND|O_CREAT,0666

fopen("hello.c","r")  //库函数封装系统调用 
{
    if(strcmp("r",mode) == 0)
    {
       open("hello.c",O_RDONLY);        
    }
    
}
        

r         O_RDONLY 
r+        O_RDWR
w         O_WRONLY|O_CREAT|O_TRUNC 
w+        O_RDWR|O_CREAT|O_TRUNC,0666
a         O_WRONLY|O_APPEND|O_CREAT,0666
a+        O_RDWR|O_APPEND|O_CREAT,0666


        
            
            
fopen     open 
r         O_RDONLY        
r+        O_RDWR

w         O_WRONLY| O_CREAT|O_TRUNC,0666 
w+        O_RDWR| O_CREAT|O_TRUNC,0666

a         O_WRONLY|O_APPEND|O_CREAT,0666 
a+        O_RDWR|O_APPEND|O_CREAT,0666
            
            //后面
            O_NOCTTY,不是终端设备
            O_ASYNC 异步io,什么时候io不确定,
            O_NONBLOCK 非阻塞 
            
         
                        
open("1.txt",O_WRONLY|O_CREAT,0666);

r w x  r w x   r w x  
1 1 0  1 1 0   1 1 0   666 
//0 0 0  0 0 0   0 1 0   umask    
1 1 1  1 1 1   1 0 1   ~002 & 1 1 0
--------------------- 
1 1 0  1 1 0   1 0 0   664

r w x  r w x   r w x  
1 1 1  1 1 1   1 1 1   777
//0 0 0  0 0 0   0 1 0   umask    
1 1 1  1 1 1   1 0 1   ~002 & 1 1 0
--------------------- 
1 1 1  1 1 1   1 0 1   775


最终文件的权限
~umask & 0666 

                         
        返回值:
            成功返回文件描述符 (最近最小未使用)
            失败返回-1
            

练习:
     1.用open实现类似touch的命令 
     

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

int main(int argc, const char *argv[])
{
	int fd=open(argv[1],O_WRONLY|O_CREAT, 0666);

	if(fd < 0)

	{
		perror("open fail");
		return -1;
	}
printf("fd = %d\n",fd);
	return 0;
}

- rw- rw- r--
  110 110 100 //664 
  
  6    6   4 
  
  000 000 010  //002   
  111 111 101 
  110 110 110 
  ------------
  110 110 100 //664 
    
     

      如果文件存在,则 打印提示 
      不存在,则创建       
    
       O_CREAT|O_EXCL 
    
     
touch --- 如果文件不存在,则创建该文件(空文件)
          如果文件存在,则更新文件的时间戳(makefile)       
    
    
    
        2.write
        char buf[1024];
        ssize_t write(int fd,  const  void *buf, size_t count);

        功能:
            通过文件描述符向文件中写一串数据
        参数:
            fd :文件描述符
            buf:要写入文件的字符串的首地址
            count:要写入字符的个数
        返回值: 
            成功返回 实际写入的个数
            失败返回 -1 & errno 被设置 
    

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


int main(int argc, const char *argv[])
{
	char buf[100];
	while(1)
	{
	int ret=read(stdin->_fileno,buf,sizeof(buf));
	write(1,buf,ret);	

	}
	
	return 0;
}


        3.read
        ssize_t read(int fd, void *buf, size_t count);
        功能:
            通过文件描述符读取文件中的数据
        参数:
            fd  :文件描述符
            buf : 存放数据空间的首地址
            count:要读到数据的字节个数
        返回值:
            成功返回读到数据的个数
            失败返回-1
            读到文件结尾返回0
            
            
            注意:
            read读出来的数据,不是字符串,
            如果要输出字符串,需要单独进行处理。

            

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


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

	char buf[100];
	while(1)
	{
	int ret = read(stdin->_fileno,buf,sizeof(buf));
	buf[ret-1]='\0';
	printf("ret = %d,buf=%s\n",ret,buf);
	}
	return 0;
}

   
            
练习:   
     使用read 实现cat命令 
     

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

int main(int argc, const char *argv[])
{
	int fp = open(argv[1],O_RDONLY);

	char buf[1024];
	int ret = read(fp,buf,1024);    
	if(ret!=EOF)
	{
	
	buf[ret-1]='\0';
	printf("%s\n",buf);
	}

	return 0;
}


     
     
     
     


基本操作
打开 - open 
读写 - read/write
关闭 - close 

练习:
      用文件IO方式实现文件拷贝    
      
      
思路:
1.打开 
  fd_s  --src 
  fd_d  --dest 

2.读写 

3.关闭 
  close 

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

int main(int argc, const char *argv[])
{
	int fp_c=open(argv[1],O_RDONLY);
	int fp_d=open(argv[2],O_WRONLY|O_CREAT,0666);

	int ret=0;
	char buf[1024];
	while(ret=read(fp_c,buf,sizeof(buf)))
	{
		write(fp_d,buf,ret);
	}
	close(fp_c);
	close(fp_d);
	
	return 0;
}

         
         
            
    练习:
    1、使用以上文件IO方式测试该模式下的操作过程是否真没有缓存
        终端上是否可以验证直接输出。
        文件中是否可以验证文件直接读写。
        
    2、用以上文件io函数完成一个自己的封装的简单printf函数。
            如果有'\n' 则该函数直接输出
            如果没有'\n'则缓存并能到达数组满的时候一次输出。
        
        int myprintf(const char * str)
        {
             char buff[1024] // 缓存 
            //文件io
        }
        
        myprintf("helloworld\n");
        hello
        world
        
        myprintf("helloworld\n");
        sleep(5);
        
        
        
        思路:
        判断输出的 字符串 有没有 "\n"?
        
        数据写死? 
        s[strlen(str)-1] 判断该位置是否为 '\n'
        
        是?
        write 
        
        不是?
        buff
        
        判断buff有没有满?
        继续等待新的输入
        如果满了,则输出 write 
        
        
    
    作业:
    使用文件io方式完成任意两个文件的比较功能,测试两个文件是否相等。        
        
        
    


    
    使用read,write复制文件。
        fseek  ftell 
        
        4.lseek  //fseek, rewind ftell
        off_t lseek(int fd, off_t offset, int whence);
        功能:
            定位文件的位置
        参数:
            fd    :文件描述符
            offset:偏移量
                        正:向后偏移
                        负:向前偏移
                        零:不偏移
            whence:
                SEEK_SET
                SEEK_CUR
                SEEK_END
                         正 空洞 
        返回值:
            成功返回 偏移量
            失败返回 -1
            
            
            lseek(fd,0,SEEK_END);
   练习计算文件的大小 
       off_t len =lseek(fd,0,SEEK_END); //获取到文件的大小          

练习:
    创建空洞文件 
    a.先偏移  --lseek 
    b.写一下  --write 
    
   
     //空洞文件 
            1.定位 
            lseek(fd,len,SEEK_SET);
            2.写 
            write(fd,"",1);


练习:

    定位到文件开头 
    lseek(fd,0,SEEK_SET);
    
    获取文件大小:
    off_t sizeFile = lseek(fd,0,SEEK_END); //从头到尾的偏移量 就是文件大小                 

练习:
    使用以上lseek函数测试其功能,并验证是否与fseek一样
    有部分不支持的特性。

注意:
    1、不支持O_APPEND的追加模式,无法生成空洞文件。
    2、lseek函数执行失败,文件指针还在偏移前的位置。
    3、lseek函数在设备文件上偏移无效。 /dev/video0 
    4、fifo,socket 也不支持lseek的操作。
    

    
    
  
空洞文件:
    1.偏移 
    2.写操作 
    
练习:用文件IO的方式
    模仿 文件下载 
    首先创建空洞文件,占用磁盘空间,
    然后进行文件的复制。
    
    思路:
    1.打开文件 
      源文件 
      目标文件 
    2.读写 
      从源文件中读取数据 
      写入到目标文件 
    3.关闭 
      
      
      
      
      
    
    --------------------------------------------------

    阻塞:程序因为某种条件没有被触发,而导致
    
    '0'   '\0'


面试题:
    文件IO的文件描述符最大值是多少? ==>1024 个,范围0-1023 《==ulimit -a    
            
  
--------------------------------------------------------------------
        
fileno      FILE* fp -> int fd

int fileno(FILE *stream);
功能:
    获得一个文件流指针中的文件描述符
参数:
    stream:文件流指针
返回值:
    成功返回文件描述符
    失败返回-1

2.fdopen    int fd -> FILE *fp
 FILE *fdopen(int fd, const char *mode);
 功能:
    将文件描述符转化为文件流指针
 参数:
    fd:已经打开的文件描述符
    mode:
        "r"
        "r+"
        "w"
        "w+"
        "a"
        "a+"
 返回值:
    成功返回文件流指针
    失败返回NULL    

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

int lineCnt(FILE *fp)
{
	int cnt = 0; 
	char buf[10];

	while (fgets(buf,sizeof(buf),fp) != NULL)
	{
		if (buf[strlen(buf) - 1] == '\n')
			cnt++;
	}

	return cnt;
}


void do_log(FILE *fp)
{
	//1.统计行数 
	int lines = lineCnt(fp);
	//2.输出数据 
	
	while (1)
	{
		time_t t = time(NULL);
		struct tm *ptm = localtime(&t);

		lines++;
		fprintf(stdout,"%d,%04d-%02d-%02d %02d:%02d:%02d\n",lines,ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec);
		fprintf(fp,"%d,%04d-%02d-%02d %02d:%02d:%02d\n",lines,ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec);
		fflush(fp);
		sleep(1);

	}
}

//./a.out 1.txt 
int main(int argc, const char *argv[])
{
	if (argc != 2)
	{
		printf("Usage: %s <filename>\n",argv[0]);
		return -1;
	}


	FILE *fp = fopen(argv[1],"a+");

	if (fp == NULL)
	{
		perror("fopen fail");
		return -1;
	}

	do_log(fp);

	fclose(fp);
	
	return 0;
}
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

int lineCnt(FILE *fp)
{
	int cnt = 0; 
	char buf[10];

	while (fgets(buf,sizeof(buf),fp) != NULL)
	{
		if (buf[strlen(buf) - 1] == '\n')
			cnt++;
	}

	return cnt;
}


void do_log(FILE *fp)
{
	//1.统计行数 
	int lines = lineCnt(fp);
	//2.输出数据 
	
	while (1)
	{
		time_t t = time(NULL);
		struct tm *ptm = localtime(&t);

		lines++;
		fprintf(stdout,"%d,%04d-%02d-%02d %02d:%02d:%02d\n",lines,ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec);
		fprintf(fp,"%d,%04d-%02d-%02d %02d:%02d:%02d\n",lines,ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec);
		fflush(fp);
		sleep(1);

	}
}

//./a.out 1.txt 
int main(int argc, const char *argv[])
{
	if (argc != 2)
	{
		printf("Usage: %s <filename>\n",argv[0]);
		return -1;
	}


	FILE *fp = fopen(argv[1],"a+");

	if (fp == NULL)
	{
		perror("fopen fail");
		return -1;
	}

	do_log(fp);

	fclose(fp);
	
	return 0;
}


        文件IO 练习:
  用文件IO方式完成任意文件的拷贝。
  
 
文件IO与标准IO的比较:

文件IO 用于底层设备相关的开发,但是
效率和安全性以及移植性没有标准IO方便。

如果是纯上层开发,优先选择使用标准IO 。


作业:
    用文件IO 向终端输出100以内所有偶数数字。
    
    标准io         文件io
    fopen           open
    
    fputc/fgetc     write
    fputs/fgets        read
    fwrite/fread
    
    fclose            close

    fseek            lseek
    ftell    
    rewind
    
    
    fdopen //fd -> FILE*
    fileno //FILE* -> fd

            

//假期作业:    
电话簿
    tel
    struct info
    {
        char name[256];
        char addr[256];
        char phone[15];
    };
    +-----------------------+
    |1,add
    |2,search
    |3.delete
    |3.exit 
    +-----------------------+        
    1
    scanf();
    fgets();
    
    switch (chose)
    case '1':
    add();
    break;
    case '2':
    search();
    break;
    case 3:
    return ;
    
    
    
    
    add()
    {
        fopen(tel,"a");
        fgets(name);
        fgets(age);
        fgets(phone);
        fgets(addr);
        fwrite//fputs();
        fclose();
    
    }
    search()
    {
        fgets(wantname);
        fopen(tel,"r");
        fgets(buf);

        if(buf.name == wantname)
            {
                printf(name,age,phone,addr);
            }
    
            
    }
    
    张三 fgets()    name;
    西安    fgets(); addr,
    110        fgets(); phone;
    22,        int age;
    strcat();
    张1:西安:110:22
    张3:西安:110
    张4:西安:110
    张5:西安:110
    
    
    
    sprintf(buf,"%s:%s:%s:%d\n",name,addr,phone,age);
    fprintf(fp,"%s:%s:%s\n",info.name,info.addr,info.phone);
    
    fprintf();
    sprintf();
    
    
    void(*a)(int,int *)
    
    void(*b(int ))(int,int *) ;
    
    
    int truncate(const char *path, off_t length);
    
    功能:
        截断 文件到指定的长度 
    返回值:
       成功 返回 0
       失败 -1 

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

【回顾】
1.stdio ----> file io 

            stdio       file io 
 操作对象: FILE *       int fd    
 打开    : fopen         open       //1.txt 
 读写    : fget c/fputc  read 
           fgets/fputs   write 
           fread/fwrite 
 关闭    : 
          fclose        close 
          
 定位    : 
          fseek         lseek() 
          ftell 
          rewind    

关联:
        fileno          fdopen(fd,"r");
        FILE * -->fd    fd --->FILE * 
                   
 

      

    
作业:
    1. 使用文件io方式完成任意两个文件的比较功能,测试两个文件是否相等。
      fgets(); // FILE *fp --fdopen();
      //fd --> FILE * 
      strcmp(); //string 
      
    2. 以文件io形式 
      模拟迅雷下载文件 
 

    
        
        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值