直白解读网络编程第一节_文件I/O(入门)

5 篇文章 0 订阅

简介1:标准I/0,和文件I/O

标准I/O:是ansic建立的一个标准i/o模型,就是包含stdio.h头文件的库函数,标准I/O又称为有缓存的I/O,即他对文件I/O的操作做了进一步的处理,包括缓存的分配等。

文件I/O:又叫做无缓存的I/O,例如read/write的操作,是直接调用系统中的系统调用。

首先你要明确linux操作系统函数之间的调用关系,首先是“应用程序”调用“库函数”,“库函数”调用“系统调用”,“系统调用”通过一个函数指针去驱动“设备”

不同点:

1.标准I/O提供了缓冲机制,比如fopen函数,打开一个文件的同时,创建了一个缓冲区,还创建了一个包含文件和缓冲区数据的数据结构,直白讲就是一个结构体

2.操作的对象有差别,文件I/O错做的是文件,读写硬盘,是对文件的描述符操作,而标准I/O操作的是控制台,操作的是字符流,这里就可以解释为什么open的返回值叫文件描述符,而fopen的返回值叫文件流。

需要认识的是:

1.系统调用(sysytem call)是用户进程访问内核的接口,把用户从底层编程解放出来,提高系统的安全性。

2.库函数(lib)是提供统一的编程接口,便于程序移植,为了实现某个功能而封装到应用程序接口的集合,库函数是使用系统调用实现的。

(一) 库函数中针对文件操作的实现,他们是

fopen() :打开

fclose() :关闭

fread() :读

fwrite() :写

fscanf() :输入

fprintf() :输出

fgets(); fputs();gets() puts():针对字符串的读写操作

fgetc();fputc(); :针对字符的读写操作

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

fseek   ftell
1.int fseek(FILE *stream, long offset, int whence); 改变文件的读写位置/文件位置标识符

stream :文件流

offset :偏移量

whence :基准

SEEK_SET :文件开头

SEEK_CUR :当前位置

SEEK_END :文件结尾

2.long ftell(FILE *stream);返回当前文件的读写位置
3.空洞文件:文件中有空字符。因为向后进行文件读写位置的移动。
#include <stdio.h>
int main(int argc,char *argv[]){
    FILE *fp;
    if(argc != 2){
        fprintf(stderr,"usage:%s filename\n",argv[0]);
    }
    if((fp = fopen(argv[1], "r+")) == NULL){
            perror("fopen");
            return -1;
    }
    printf("%ld\n", ftell(fp));	//查看当前位置
    fseek(fp, 10, SEEK_END);	//改变位置,在末尾添加10个空字符
    printf("%ld\n", ftell(fp));	//查看当前位置
    fputc('a', fp);		//向文件内添加字符'a'
    fclose(fp);
    return 0;
}
------------------------------------------------------------------------------------------------

(二) 系统调用中对文件操作的实现

open();close();write();read();.....等,在linux下man 2中,可以看出系统调用与库函数中的函数名比较,少了一个f,其实库函数就是在系统调用的基础上进行了一个包装,这个做个例子:如系统调用中有一个函数为:int set(); 那么库函数中的函数为:int fset(){ return set;},即对系统调用做了一个包装,中间可以进行简单的数据处理和一些其他的操作等,但是不改变原理。

在man 2 中查看某一个系统调用函数时,要按照以下几步来查看和分析

1 头文件

2 函数名和函数的功能(函数名<-->函数功能)

3 参数列表

4 返回值和错误处理

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

1.int open(const char *pathname, int flags, mode_t mode);:打开文件,返回值是文件描述符
pathname:文件的路径
flags:O_RDONLY: O_WRONLY:O_RDWR 三选一

可选:O_CREAT :文件不存在就创建

:O_TRUNC :文件已经存在就截短

:O_APPEND :文件追加
mode:创建文件的时候,文件的模式/权限。普通文件0666 其他的文件0777

2.int close(int fd);:关闭文件

3.ssize_t //有符号整形,就是一个整型数

ssize_t read(int fd, void *buf, size_t count);:读文件

fd :文件描述符

buf :缓冲区的首地址

count :期望/想要读的字节的个数

返回值 :实际读到的字节的个数

4.ssize_t write(int fd, const void *buf, size_t count);:写文件

fd :文件描述符

buf :缓冲区的首地址

count :期望/想要写的字节的个数

返回值 :实际写入的字节的个数

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

时间相关的系统调用:time_t time(time_t *t);
返回从1970年开始到现在的秒数。

char *ctime(const time_t *timep);

将时间转换成字符串,字符串的格式"Wed Jun 30 21:49:08 1993\n"
struct tm *localtime(const time_t *timep);
将时间转换成结构体 struct tm 

程序运行的流程:
进程:一个应用程序的运行实例。
1.创建一个新的进程
2.加载应用程序
3.运行启动例程
                创建空间,初始化。打开3个文件,标准输入/标准输出/标准错误
4.调用main函数
5.退出操作

文件流  文件描述符
标准输入stdin            0
标准输出stdout          1
标准错误stderr          2

文件描述符分配原则:
从当前未被使用的文件描述符中找到最小的那一个。

文件描述符 对应 一个已经打开的文件。

eg1:获取当前日期,并打印日志

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

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

        if(argc != 2){
                fprintf(stderr,"usage:%s logfile\n",argv[0]);
                return -1;
        }

        if(do_log(argv[1])){
                printf("write failed\n");
        }
        return 0;
}
int do_log(char *filename){
        int count=0;
        int fd;
        time_t t;
        char *p;

        fd = open(filename,O_CREAT|O_WRONLY|O_APPEND, 0666);
        if(fd == -1){
                perror("open");
        }
        while(count < 5){
                time(&t);
                p = ctime(&t);
                write(fd,p,strlen(p));
                count++;
                sleep(1);
        }
        close(fd);
        return 0;
}
eg2:实现cat查看指令
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>

#define N 64

int main(int argc, char *argv[]){
        int fd;
        ssize_t n;
        char buf[N];

        if(argc != 2){
                fprintf(stderr, "usage: %s filename\n", argv[0]);
                return -1;
        }
        fd = open(argv[1], O_RDONLY);
        if(fd == -1){
                perror("open");
                return 1;
        }
        while(1){
                bzero(buf, N);
                if((n =read(fd, buf, N-1)) <= 0) break;
                printf("%s", buf);
        }
        printf("\n");
        close(fd);
        return 0;
}
eg3:实现cp拷贝命令

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>


#define N 64

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

        if(argc != 3){
                fprintf(stderr,"usage:%s oldfilename newfilename\n",argv[0]);
                return -1;
        }
        do_cp(argv[1], argv[2]);
        return 0;
}

int do_cp(char *oldfile, char *newfile){
        char buf[N];
        int fod,fed;
        ssize_t n;

        fod = open(oldfile,O_RDONLY);
        if(fod == -1){
                perror("oldfile");
                return 1;
        }
        fed = open(newfile, O_CREAT|O_WRONLY|O_TRUNC, 0666);
        if(fed == -1){
                 perror("newfile");
                 return 2;
        }
        while(1){
                bzero(buf,N);
                if(n = read(fod,buf,1) <= 0){
                        break;
                }
                write(fed,buf,1);
        }
        close(fod);
        close(fed);

        return 0;
}
目录文件操作(库函数)
opendir();
DIR *opendir(const char *name);
打开一个目录文件,返回目录流
readdir();
struct dirent *readdir(DIR *dirp);
读目录流,获取一个目录条目。每个目录条目代表目录中包含的一个文件的相关信息。
struct dirent {
        ino_t  d_ino; /* inode number */
        off_t  d_off;       /* offset to the next dirent */
        unsigned short d_reclen;   /* length of this record */
        unsigned char  d_type; /* type of file; not supported by all file system types */
        char           d_name[256]; /* filename */
};
closedir
int closedir(DIR *dirp);

关闭目录流

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

stat/lstat
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
获取文件的状态信息
path    文件的路径
buf             出参,结构体地址
struct stat {
        dev_t     st_dev;     /* ID of device containing file */
        ino_t     st_ino;     /* inode number */
        mode_t    st_mode;    /* protection */
        nlink_t   st_nlink;   /* number of hard links */
        uid_t     st_uid;     /* user ID of owner */
        gid_t     st_gid;     /* group ID of owner */
        dev_t     st_rdev;    /* device ID (if special file) */
        off_t     st_size;    /* total size, in bytes */
        blksize_t st_blksize; /* blocksize for file system I/O */
        blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
        time_t    st_atime;   /* time of last access */
        time_t    st_mtime;   /* time of last modification */
        time_t    st_ctime;   /* time of last status change */
};

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

eg4:实现ls -a命令

/*
 * opendir
 * while(readdir)
 *              printf(d_name)
 * closedir
 * */

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>

void *do_ls(char *);

int main(int argc, char *argv[]){       // lsa /home/uplooking/
        if(argc == 1){
              do_ls(".");
        }else{
              while(--argc){
			printf("%s:\n", *++argv);
                        do_ls(*argv);
                }
        }

        return 0;
}
void *do_ls(char *dirname){
        DIR *dir_ptr;
        struct dirent *direntp;
        dir_ptr = opendir(dirname);
        if(dir_ptr ==NULL){
                perror("opendir");
                return ;
        }
        while((direntp = readdir(dir_ptr)) != NULL ){
                printf("%s  ",direntp->d_name);
        }
        closedir(dir_ptr);
        
        return ;
}
eg5:实现ls -l命令

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>

#define N 64

void display_time();
void display_file(char *filename, char *showname);
void display_dir(char *dirname);

int main(int argc, char *argv[]){
        struct stat buf;

        if(argc != 2){
                fprintf(stderr,"usage:%s filename",argv[0]);
                return -1;
        }

        lstat(argv[1], &buf);

        if(S_ISDIR(buf.st_mode)){   //如果是目录
                display_dir(argv[1]);
        }else{                      //如果是文件
                display_file(argv[1],argv[1]);
        }

        return 0;
}
void display_time(){
        time_t t;
        struct tm *loc_tm = NULL;
        char arr[12][4] = {"Jan","Feb","Mar","Apr",
                           "May","Jun","Jul","Aug",
                           "Sep","Oct","Nov","Dec"}; 
        time(&t);
        loc_tm = localtime(&t);
        printf(" %-4s %d %d:%d ",arr[loc_tm->tm_mon]
                                ,loc_tm->tm_mday
                                ,loc_tm->tm_hour
                                ,loc_tm->tm_min);
        return ;
}
void display_file(char *filename, char *showname){
        struct stat buf;
        int i=8;
        struct passwd *pas;
        struct group *gid;

        lstat(filename, &buf);
        
        switch(buf.st_mode & S_IFMT){
                case S_IFSOCK: printf("s"); break;
                case S_IFLNK : printf("l"); break;
                case S_IFREG : printf("-"); break;
                case S_IFBLK : printf("b"); break;
                case S_IFDIR : printf("d"); break;
                case S_IFCHR : printf("c"); break;
                case S_IFIFO : printf("p"); break;
        }
        // S_IRUSR    00400     owner has read permission
        //                      100 000 000
        //                      876 543 210
        while(i >= 0){
                if(buf.st_mode & (1<<i)){
                        switch(i%3){
                                case 2: printf("r"); break;
                                case 1: printf("w"); break;
                                case 0: printf("x"); break;
                        }
                }else{
                        printf("-");
                }
                i--;
        }
printf(" %d",(int)buf.st_nlink);   // number of hard links
        
        pas = getpwuid(buf.st_uid);
        printf(" %s",pas->pw_name);       // user ID of owner
        
        gid = getgrgid(buf.st_gid);
        printf(" %s",gid->gr_name);       // user ID of owner

        printf(" %d",(int)buf.st_size);    // total size, in bytes

        display_time();                           // time
        
        printf(" %s\n",showname);     // filename

        return ;
}

void display_dir(char *dirname){
        DIR *dir;
        struct dirent *dir_ent;
        char str[N] = {0};

        dir = opendir(dirname);
        
        while((dir_ent = readdir(dir)) != NULL){
                sprintf(str,"%s/%s",dirname,dir_ent->d_name);
                display_file(str, dir_ent->d_name);
        }

        closedir(dir);
        return ;
}
eg6:实现pwd查看路径命令

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

#define SIZE 1024
void printpathto(ino_t this_inode);
void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen);
ino_t get_inode(char *fname);

int main(int argc, char *argv[]){
        
        printpathto(get_inode("."));
        putchar('\n');

        return 0;
}

/* 递归打印路径:a,打印父目录的路径 b,打印当前目录名
 * 递归:1.终止条件:/ 父目录..和当前目录.的inode结点号一样的
 *               2.步长:移动到上一层目录
 *               3.收敛:向根目录/进行收敛
 * */
void printpathto(ino_t this_inode){
        ino_t my_inode;
        char its_name[SIZE];

        if(get_inode("..") != this_inode){
                // 移动当前路径
                chdir("..");    // cd ..
                inum_to_name(this_inode, its_name, SIZE);
                my_inode = get_inode(".");
                printpathto(my_inode);    //先打印上层目录名,先调用函数
                printf("/%s", its_name);  //在打印当前目录名
        }
}
void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen){
        struct dirent *dir_ent;
        DIR *dir;

        dir = opendir(".");
        if(dir == NULL){
                perror("opendir");
                return ;
        }

        while((dir_ent = readdir(dir)) != NULL){
                if(dir_ent->d_ino == inode_to_find){	//注释掉的为容错的处理,两个buffer大小问题
//                      if(strlen(dir_ent->d_name) < buflen){
                                strcpy(namebuf,dir_ent->d_name);
//                      }else{
//                              strcpy(namebuf,dir_ent->d_name);
//                      }
                closedir(dir);
                return ;
                }
        }
        return ;
}

ino_t get_inode(char *fname){
        struct stat info;

        if(stat(fname, &info) == -1){
                printf("errpr\n");
                return -1;
        }
        return info.st_ino;
}







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值