文件IOday02--------时间编程与文件IO

目录

一,时间编程

1,概念: 

2,在程序开发费时,可以获取标准时间(以秒为单位)

将标准时间转换为字符串格式的时间的函数 char *ctime(time_t*timep)

将标准时间转换为本地时间函数:struct tm *localtime(const time_t *timep);

将本地时间转化为字符串格式的时间函数:char * asctime(struct tm *tm);

二、文件IO

1,概念

    1》文件描述符 fd 

    2》当运行程序时,系统会自动打开三个标准文件

    3》程序(静态)

    4》进程(动态)

2,出错处理

     1》全局错误码errno

3,文件IO操作文件的函数

    1》打开文件 

    2》关闭文件 

    3》从文件读数据 

    4》向文件中写数据

    5》设置文件位移量 

补充

1,复制文件描述符 

2,文件描述符的重定向

作业练习:

文件I/O – 作业

任务描述

实现思路

附:一图看懂文件IO与标准IO的区别


一,时间编程

1,概念: 


    世界标准时间以格林威治时间为起点分为24个时区,从格林威治向东时间早,向西时间晚

2,在程序开发费时,可以获取标准时间(以秒为单位)

    #include <time.h>

    time_t time(time_t *tloc);      
    //参数 -----保存秒数的变量地址
    //返回值 --- 成功:秒数, 失败:-1 

        返回值是time_t类型,参数是time_t*类型
    
    秒数: 从1970-01-01 00:00:00 到 此时此刻的秒数
    
    例如: 

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

    int main(int argc,char **argv)
    {
        time_t tm;

        printf("%ld\n",time(&tm));
        printf("tm = %ld\n",tm);

        return 0;
    }

将标准时间转换为字符串格式的时间的函数 char *ctime(time_t*timep)

参数是一个地址,一个time_t类型的地址

	char *ctime(const time_t *timep);
	//参数 ----- time()返回的秒数
	//返回值 ----成功:字符串格式的时间,失败:NULL
	
	例如: 
	int main(int argc,char **argv)
	{
		time_t tm;

		//获取标准数据
		time(&tm);

		//将标准时间转为字符串
		printf("%s",ctime(&tm));

		return 0;
	}

将标准时间转换为本地时间函数:struct tm *localtime(const time_t *timep);

可以根据结构体tm选择性的将内容输出;

	struct tm *localtime(const time_t *timep);
	//参数 -------- time()返回的秒数
	//返回值---- 成功:结构体struct tm的指针 失败:NULL 
		struct tm
		{
		  int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */
		  int tm_min;                   /* Minutes.     [0-59] */
		  int tm_hour;                  /* Hours.       [0-23] */
		  int tm_mday;                  /* Day.         [1-31] */
		  int tm_mon;                   /* Month.       [0-11] */
		  int tm_year;                  /* Year - 1900.  */
		  int tm_wday;                  /* Day of week. [0-6] */
		  int tm_yday;                  /* Days in year.[0-365] */
		  int tm_isdst;                 /* DST.         [-1/0/1]*/
		};
	
	例如: 
		#include <stdio.h>
		#include <stdlib.h>
		#include <time.h>

		#define perr(str) ({ perror(str); exit(1);})

		int main(int argc,char **argv)
		{
			time_t tm;
			struct tm * tmp;

			//获取标准数据
			time(&tm);

			tmp = localtime(&tm);
		#if 0
			if(tmp == NULL){
				perror("localtime");
				exit(1);
			}
		#else
			if(tmp == NULL)
				perror("localtime");
		#endif

			printf("%4d-%02d-%02d\n",tmp->tm_year+1900,tmp->tm_mon+1,tmp->tm_mday);
			printf("%02d:%02d:%02d\n",tmp->tm_hour,tmp->tm_min,tmp->tm_sec);

			return 0;
		}

将本地时间转化为字符串格式的时间函数:char * asctime(struct tm *tm);

参数是结构体tm指针,先通过struct tm *localtime(const time_t *timep);函数获取的本地时间,再通过asctime函数将本地时间转化为字符串格式


	 char *asctime(const struct tm *tm);
	 
	例如: 
		int main(int argc,char **argv)
		{
			time_t tm;
			struct tm * tmp;

			//获取标准数据
			time(&tm);

			tmp = localtime(&tm);
		#if 0
			if(tmp == NULL){
				perror("localtime");
				exit(1);
			}
		#else
			if(tmp == NULL)
				perr("localtime");
		#endif

			printf("%4d-%02d-%02d\n",tmp->tm_year+1900,tmp->tm_mon+1,tmp->tm_mday);
			printf("%02d:%02d:%02d\n",tmp->tm_hour,tmp->tm_min,tmp->tm_sec);

			printf("%s",asctime(tmp));
			return 0;
		}

二、文件IO

1,概念


    1》文件描述符 fd 


        顺序分配的非负整数
        内核用以标识一个特定进程正在访问的文件
        其他资源(socket、pipe等)的访问标识


    2》当运行程序时,系统会自动打开三个标准文件


                    文件指针      文件描述符    
        标准输入      stdin         0 (STDIN_FILENO)
        标准输出      stdout         1 (STDOUT_FILENO)
        标准出错      stderr        2 (STDERR_FILENO)

    3》程序(静态)


        存放在磁盘文件中的可执行代码
        通过exec函数族调用运行


    4》进程(动态)


        程序的一次执行过程
        进程的标识(pid,ppid,…)

 

2,出错处理

 
    1》全局错误码errno


        在linux中,用于标记函数调用失败的信息,定义一个全局的变量errno,把它也称为全局错误码
    
        在linux系统中,给全局错误码定义了以下一些错误值:

        在errno.h中定义,全局可见
        错误值定义为“EXXX”形式,如EACCESS
       

 /usr/include/asm-generic/errno-base.h    // 1-34个错误值 
        #define EPERM            1      /* Operation not permitted */
        #define ENOENT           2      /* No such file or directory */
        #define ESRCH            3      /* No such process */
        #define EINTR            4      /* Interrupted system call */
        #define EIO              5      /* I/O error */
        #define ENXIO            6      /* No such device or address */
        #define E2BIG            7      /* Argument list too long */
        #define ENOEXEC          8      /* Exec format error */
        #define EBADF            9      /* Bad file number */
        #define ECHILD          10      /* No child processes */
        .......
        #define ERANGE          34      /* Math result not representable */
        
        /usr/include/asm-generic/errno.h   // 35 -- 133个错误值
        #define EDEADLK         35      /* Resource deadlock would occur */
        #define ENAMETOOLONG    36      /* File name too long */
        #define ENOLCK          37      /* No record locks available */
        
        .... 
        #define EHWPOISON       133     /* Memory page has hardware error */
        


        当程序中调用某个函数失败时,系统会修改errno的值,将错误值赋给errno
        这是在程序中,可以通过读取errno的值,获取对应的错误信息,有两种方法:
            
    方法一:调用perror()函数 
    
        void perror(const char *s);
        //参数 ---- 字符串,表示错误信息的提示,调用失败的函数名
        当调用某个函数失败时,系统会修改errno,此时调用perror()时,它会读取errno的值,打印出对应的错误信息
        例如: 

        int main(int argc,char **argv)
        {
            FILE *fp;

            if((fp = fopen("1.txt","r"))== NULL){
                printf("errno = %d\n",errno);
                perror("fopen");
                exit(1);
            }
            return 0;
        }

    方法二:调用strerror()函数 
        #include <string.h>
       char *strerror(int errnum);
       //参数 --- 错误值 
       //返回值 ----成功:错误值对应的错误信息,失败:NULL 
        
        例如: 
     

   int main(int argc,char **argv)
        {

        #if 1
            FILE *fp;
            if((fp = fopen("1.txt","r"))== NULL){
                printf("errno = %d\n",errno);
                //perror("fopen");
                fprintf(stderr,"fopen:%s\n",strerror(errno));
                exit(1);
            }

            fprintf(stderr,"%s\n",strerror(200));
        #else
            int i;
            for(i = 1; i <= 133;i++)
                fprintf(stderr,"%d --->%s\n",i,strerror(i));
        #endif
            return 0;
        }

3,文件IO操作文件的函数

    1》打开文件 

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

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


       //参数1 ----- 要打开的文件
       //参数2 ----- 打开的方式:
                        O_RDONLY:只读方式打开文件。
                        O_WRONLY:只写方式打开文件。
                        O_RDWR:读写方式打开文件。

                        (以上三个每次放入int flags参数中只能选其中一个放入,下面的可以任意组合)
                        O_CREAT:如果该文件不存在,就创建一个新的文件,并用第三的参数为其设置权限。
                        O_EXCL:如果使用O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在。
                        O_NOCTTY:使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端。守护进程、后台进程、精灵进程。
                        O_TRUNC:如文件已经存在,并且以读写或只写成功打开,那么先全部删除文件中原有数据。
                        O_APPEND:以添加方式打开文件,在打开文件的同时,文件指针指向文件的末尾。
        //参数3 ------ 文件权限,当参数2中有O_CREAT时,必须要通过参数3设置文件权限,权限 = 0666 & ~umask
        //返回值 ---- 成功:最小且没有被使用的文件描述符,失败:-1 
                        
     例如:

 

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

        #define perr(str) ({perror(str); exit(1);})

        int main(int argc,char **argv)
        {
            int fd;

            if(argc !=2){
                fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
                exit(1);
            }
            
            //打开文件
            if((fd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0)
            //if((fd = open(argv[1],O_WRONLY)) < 0)
                perr("open");

            printf("%s打开成功!\n",argv[1]);
            
            //关闭文件
            close(fd);

            return 0;
        }


    2》关闭文件 
 


		 #include <unistd.h>
         int close(int fd);

    3》从文件读数据 


        #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);   //以字节流方式读取数据
       //参数1 ----- 文件描述符 
       //参数2 ----- 保存数据的空间地址
       //参数3 ----- 空间的大小
       //返回值 ----- 大于0,表示读到的字节数,等于0,表示读到文件末尾,-1,失败。
       
        例如: 

            int main(int argc,char **argv)
            {
                int fd;
                char buf[100];
                int ret;

                if(argc !=2){
                    fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
                    exit(1);
                }

                if((fd = open(argv[1],O_RDONLY)) < 0)
                    perr("open");

                while(1){
                    memset(buf,0,sizeof(buf));
                    if((ret= read(fd,buf,sizeof(buf))) < 0)
                        perr("read");
                    else if(!ret)
                        break;
                    else
                        printf("%s",buf);
                }


                close(fd);

                return 0;
            }

    4》向文件中写数据


        #include <unistd.h>
       ssize_t write(int fd, const void *buf, size_t count);
        //参数1 ----- 文件描述符
        //参数2 ----- 数据空间地址 
        //参数3 ----- 要写的数据长度
        //返回值 ---- 成功:实际写的数据长度,失败: -1
        
    例如: 封装write函数

        void mywrite(int fd,char *buf,int count)
        {
            int ret=0;

            while(1){
                if((ret = write(fd,buf+ret,count)) < 0)
                    perr("write");
                if(ret != count)
                    count = count - ret;
                else
                    break;
            }
        }

    5》设置文件位移量 

         #include <sys/types.h>
         #include <unistd.h>

         off_t lseek(int fd, off_t offset, int whence);
         //参数1 ----- 文件描述符
         //参数2  ----- 相对于参数3的偏移量
         //参数3 ----- 参数2的起始位置: 
                            SEEK_SET  ----- 文件开头
                            SEEK_CUR  ----- 文件位移量的当前位置
                            SEEK_END  ----- 文件末尾
        //返回值 ---- 成功: 文件位移量,失败:-1
        
        创建空洞文件:  ------- //创建空洞文件时,不能以追加方式打开文件
        步骤一: 修改文件位移量到指定的大小
        步骤二: 在修改后的文件位移量位置写一个标签。
        
        int main(int argc,char **argv)
        {
            int fd;
            int n;

            if(argc !=2){
                fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
                exit(1);
            }

            if((fd = open(argv[1],O_WRONLY|O_CREAT,0666)) < 0)
                perr("open");

            printf("请输入文件的大小:");
            scanf("%d",&n);

            //1,设置文件位移量
            lseek(fd,n-3,SEEK_SET);


            //2,写入一个标签
            write(fd,"end",3);


            close(fd);

            return 0;
        }

补充

1,复制文件描述符 

        int dup(int oldfd);
    //参数 --- 要复制的文件描述符
    //返回值 ---成功:最小没有被使用的文件描述符,该文件描述符是ledfd的一个拷贝

     
    int main(int argc,char **argv)
    {
        int fd,newfd;
        char buf[100];

        if(argc !=2){
            fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
            exit(1);
        }

        if((fd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0)
            perr("open");

        printf("请输入一个字符串:");
        fgets(buf,sizeof(buf)-1,stdin);
        write(fd,buf,strlen(buf));

        //复制文件描述符fd,返回新的文件描述符,该文件描述符是fd的一个拷贝
        newfd = dup(fd);

        printf("请输入一个字符串:");
        fgets(buf,sizeof(buf)-1,stdin);
        if(write(newfd,buf,strlen(buf)) < 0)
            perr("write");

        close(fd);

        return 0;
    }

2,文件描述符的重定向


    int dup2(int oldfd, int newfd);   //把newfd重定向到oldfd,在重定向之前,会关闭newfd对应的文件
    //参数1 ---- 目标文件描述符
    //参数2 ---- 需要重定向的文件描述符
    //返回值 ----- 成功:返回重定向后的文件描述符,失败:-1
    
    例如: 
  

 int main(int argc,char **argv)
    {
        int fd,newfd;
        char buf[100];

        if((fd = open("1.txt",O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0)
            perr("open");
        if((newfd = open("2.txt",O_WRONLY|O_CREAT|O_TRUNC,0666)) < 0)
            perr("open");
    #if 0
        //将标准输出重定向到文件中
        dup2(fd,STDOUT_FILENO);
        printf("hello world\n");
    #else
        write(fd,"hello",5);
        dup2(fd,newfd);    //把newfd重定向到fd,同时关闭newfd原来的文件
        write(newfd,"world",5);
    #endif
        close(fd);
        close(newfd);

        return 0;
    }

作业练习:

文件I/O – 作业

任务描述

① 使用非缓冲I/O方式,实现一个copy程序,该程序的第一个命令行参数为
源文件,第二个命令行参数为目标文件,程序实现将源文件中的内容复
制到目标文件。
code:
#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
//封装write,防止有些内容写不全
void mywrite(int fd,char *buf,int count)
{
	int ret=0;
	while(1)
	{
		if((ret=write(fd,buf+ret,count))<0)
			perror("write");
		if(ret!=count)
		{
			count=count-ret;
		}
		else
			break;
	}
}


int main(int argc,char **argv)
{
	int wwq,qww;
	int ret,i=0;
	char buf[1000];
//判断传入文件数是否正常
	if(argc!=3)
	{
		fprintf(stderr,"Usage: %s <filename>\n",strerror(errno));
		exit(1);
	}
//判断传入文件是否打开正常打开
	if((wwq=open(argv[1],O_RDONLY))<0)
	{	
		fprintf(stderr,"Usage: %s <filename>\n",strerror(errno));
		exit(1);
	}
	if((qww=open(argv[2],O_WRONLY))<0)
	{	
		fprintf(stderr,"Usage: %s <filename>\n",strerror(errno));
		exit(1);
	}
	while(1)
	{
        //初始化buf空间,令其内容全部为0
		memset(buf,0,sizeof(buf));
        //读出是否正常,并把内容存入buf
		if(ret=read(wwq,buf,sizeof(buf))<0)
		{
			perror("read");
		}
        //while循环退出的条件,当读至文件末端会返回0,使得ret=0;
		else if(!ret)
			break;
        //将buf内容写入qww
		mywrite(qww,buf,strlen(buf));
	}
	fprintf(stdout,"内容为:%s\n",buf);
	close(wwq);
	close(qww);
	return 0;
	
}

效果:

实现思路

① 打开源文件
② 打开目标文件
③ 循环读取源文件并写入目标文件
④ 关闭源文件
⑤ 关闭目标文件

提示:

① 命令行参数可以使用argv[1]访问第一个参数,argv[2]访问第二个参数
②使用diff工具检查目标文件与源文件是否一致()

附:一图看懂文件IO与标准IO的区别

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值