Java基础练习题(数组)2

ValueError: check_hostname requires server_hostname的可能解决方案

  返回  

Linux-文件IO

2021/8/21 18:34:00 浏览:

当程序执行标准库函数printf时,会用到文件指针FILE *stdout。
stdout主要由三部分构成,如下图。
在这里插入图片描述
stdout实际就对应文件描述符中的1。
执行标准库函数printf时,程序会调用内核提供的系统调用函数write。
在这里插入图片描述

open、close、read、write

open

因为他们都属于系统调用,所以在查看时要加上2,表示查看第二章的。
比如查看第二章open的使用方法,man 2 open
在这里插入图片描述
在这里插入图片描述
参数:

pathname:文件名
flags,
必选项
O_RDONLY, O_WRONLY, or O_RDWR.
可选项
O_APPEND 追加

O_CREAT (文件不存在时)创建
O_EXCL必须和O_CREAT一起使用,(如果文件存在则报错。)
mode:权限位
mode指定创建新文件时使用的权限。
当O_CREAT或O_TMPFILE在flags中指定时必须提供此参数;如果没有指定O_CREAT和O_TMPFILE,则忽略mode。
最终(mode & ~umask)

O_NONBLOCK 非阻塞

必选项和可选项实际上是一个32位的位图在这里插入图片描述
返回值
在这里插入图片描述
成功返回当前最小的可用的文件描述符。失败返回-1.
在这里插入图片描述
默认一个进程启动之后,0、1、2是被使用的,对应标准输入、标准输出和标准错误,此时再打开一个文件,将返回的文件描述符是3。
如果把0,1,2的其中一个或多个给关闭了,则返回被关的最小的那个文件描述符。

close

同样查看open的使用方法,man 2 close
在这里插入图片描述
参数:open打开的文件描述符。
在这里插入图片描述
返回值:成功返回0,失败返回-1.

使用open和close函数实现touch命令的部分功能(打开或新建一个文件,并指定权限。)

//printf需要用
#include <stdio.h>
//open需要用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//close需要用
#include <unistd.h>

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("%s filename.\n",argv[0]);
        return -1;
    }
    int fd = open(argv[1],O_RDONLY|O_CREAT,0666);
    //0666&(~umask) = 0666&(~0002)=0666&7775=0665,rw- rw- r-x,因为是文件,所以x也会被拿走,最后是rw- rw- r--
    close(fd);

    return 0;
}

运行代码:
在这里插入图片描述
只读打开一个名为creat_test的文件,如果文件不存在就创建它,指定权限为rw- rw- r–

read

在这里插入图片描述
从fd中最多读count字节。
read是阻塞等待的

write

在这里插入图片描述

实现一个cat功能

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

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("%s filename\n",argv[0]);
        return -1;
    }

    int fd = open(argv[1],O_RDONLY);

    //读,输出到屏幕
    char buf[256];
    int ret=0;
    do
    {
    	//从fd中读,读到buf中,最多读sizeof(buf)个字节。
    	//fd会递增的,最终指向文件末尾
        ret=read(fd,buf,sizeof(buf));
        //测试是否不管文件中还剩多少字节,每次都读count
        printf("%d\n",ret);//测出的结果是有多少读多少,最多读到count.
        //STDOUT_FILENO是标准输出的宏定义,值为1
        write(STDOUT_FILENO,buf,ret);
    }while(ret>0&&ret==sizeof(buf));//代表读到末尾了

    close(fd);

    return 0;
}

lseek实现文件读写位置改变

需求:打开一个文件,写入内容:helloworld,然后读取下该文件的内容,输出到屏幕。
先来实现下。

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

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("%s filename\n",argv[0]);
        return -1;
    }

    char str[]="hello world";

    int fd = open(argv[1],O_RDWR|O_CREAT,0666);

        //STDOUT_FILENO是标准输出的宏定义,值为1
    write(fd,str,sizeof(str));

    //读,输出到屏幕
    char buf[256];
    memset(buf,0,sizeof(buf));
    int ret=0;
    do
    {
        ret=read(fd,buf,sizeof(buf));
        printf("%d\n",ret);
        //STDOUT_FILENO是标准输出的宏定义,值为1
	        write(STDOUT_FILENO,buf,ret);
    }while(ret>0&&ret==sizeof(buf));

    close(fd);

    return 0;
}

运行一下:
在这里插入图片描述
原因出在哪呢?为什么没有输出出来呢?
有没有写到my_lseek.log这个文件中呢?
打开my_lseek.log这个文件看下。
在这里插入图片描述
写进去了。
那为什么呢?
是因为在write之后,读写文件指针 fd 移动到文件末尾了,如果我们要想输出出内容,就必须将读写文件指针 fd 移动到开头,这需要用到一个函数lseek。
看下lseek这个函数。
在这里插入图片描述
在这里插入图片描述
函数的作用是:根据下面的指令,将与文件描述符fd关联的打开文件的偏移量重新定位到参数offset上:
在这里插入图片描述
返回值
成功:返回当前位置到开始位置的偏移的字节数。
失败:返回 -1。
在上述代码中添加:

lseek(fd,0,SEEK_SET);

lseek实现文件读写位置改变

验证Linux能够打开文件的最大数量

Linux能够打开的最大文件数量为1024(文件描述符为0-1023)个。
在这里插入图片描述
默认一个进程启动之后,0、1、2是被使用的,对应标准输入、标准输出和标准错误,此时再打开一个文件,将返回的文件描述符是3。

因为这里的主要目的是验证能打开多少文件,所以就不关闭文件描述符,正常来说是要打开一个文件关闭一个文件的。

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


//验证Linux能打开的最大文件数量
int main()
{
    //默认再打开的文件是从3开始的
    //前面三个已打开的文件分别是标准输入、标准输出、标准错误
    int num = 3;
    int count = 0;
    char filename[128];
    while(1)
    {
        sprintf(filename,"temp_%04d",num++);
        if(open(filename,O_RDONLY|O_CREAT,0666) < 0 )
        {
            perror("open error");
            break;
        }
        else
        {
            //open sucess
            count += 1;
        }
    }

    printf("count = %04d.\n",count);

    return 0;
}

程序运行输出结果如下:
在这里插入图片描述

stat函数

获得文件信息
在这里插入图片描述
我们使用 ls -l 实现的也是查看文件的详细信息,因此使用这个函数可以实现相同的功能。

函数参数:

const char *pathname, //文件名
struct stat *buf //一个指向struct stat结构体的指针,是传出参数

返回值:

On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

主要看下这个struct stat结构体。

struct stat {
dev_t     st_dev;         /* ID of device containing file */包含该文件的设备号ID
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 */用户的ID
gid_t     st_gid;         /* group ID of owner */ID
dev_t     st_rdev;        /* device ID (if special file) */
off_t     st_size;        /* total size, in bytes */文件大小
blksize_t st_blksize;     /* blocksize for filesystem I/O */块的大小
blkcnt_t  st_blocks;      /* number of 512B blocks allocated */块的个数

/* Since Linux 2.6, the kernel supports nanosecond
   precision for the following timestamp fields.
   For the details before Linux 2.6, see NOTES. */

struct timespec st_atim;  /* time of last access */上一次的访问时间
struct timespec st_mtim;  /* time of last modification */上一次的修改时间
struct timespec st_ctim;  /* time of last status change *//上一次的状态变化的时间

#define st_atime st_atim.tv_sec      /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

说一说这个结构体的一些成员变量

1、st_ino; // inode number

inode是index node,表示索引结点,里面有文件存储在磁盘的哪个位置的信息,以及文件大小、时间等等信息。
在这里插入图片描述
2、st_mode; // 文件类型和权限

判断文件类型可以根据掩码值。其中,第一位的0表示八进制。
也就是说,7代表二进制的111.
在这里插入图片描述
如果不想使用掩码这种处理方式,还可以使用下面的几种宏。
在这里插入图片描述
此外,还有几位数分别用来表示特殊的权限位和三类人的权限。

比如下图中的第一位表示特殊的权限位(很少使用)和另外三位数则表示三类人的权限。

同样都是八进制数。
在这里插入图片描述
在这里插入图片描述
3、再来说一说这个结构体成员变量中的数据类型 struct timespec

先来说一说怎么找这个结构体
假设一开始并不知道这个结构体在哪?只知道有这个结构体名。
那么就可以在根目录中使用grep -rn来搜索。

-r代表递归查找,-n代表显示行号。
此外,找结构体时,有技巧,就是在结构体类型名后加上{,还有就是一般都在/usr目录下。

grep -rn "struct timespec {" /usr/

查找比较慢,需要耐心等待。
在这里插入图片描述
应该是在

/usr/include/linux/time.h:9:struct timespec {

打开查找到的文件。
使用命令
在这里插入图片描述
其中的+9表示可以定位到改行。

struct timeval {
     __kernel_time_t     tv_sec;     /* seconds */
     __kernel_suseconds_t    tv_usec;    /* microseconds */
 };

在这里插入图片描述
除了stat这个函数之外呢,还有stat这个命令。

比如使用stat这个命令来查看daemon.c这个文件的详细信息,就可以使用命令stat daemon.c

输出结果如下:
在这里插入图片描述

应用stat函数–实现ls命令

实现目标:
在这里插入图片描述
实现目标:

获取文件用户的相关信息 – getpwuid

需要传入uid_t uid

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

struct passwd *getpwuid(uid_t uid);

返回值是struct passwd类型的值

The passwd structure is defined in <pwd.h> as follows:

struct passwd {
   char   *pw_name;       /* username */
   char   *pw_passwd;     /* user password */
   uid_t   pw_uid;        /* user ID */
   gid_t   pw_gid;        /* group ID */
   char   *pw_gecos;      /* user information */
   char   *pw_dir;        /* home directory */
   char   *pw_shell;      /* shell program */
};

获取文件组的相关信息 – getgrgid

需要传入gid_t gid

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

struct group *getgrgid(gid_t gid);

返回值是struct group 类型的值

The group structure is defined in <grp.h> as follows:

struct group {
       char   *gr_name;        /* group name */
       char   *gr_passwd;      /* group password */
       gid_t   gr_gid;         /* group ID */
       char  **gr_mem;         /* NULL-terminated array of pointers
                                          to names of group members */
};

时间获取 – localtime

需要传入const time_t * timep

#include <time.h>

struct tm *localtime(const time_t *timep);

返回值是struct tm 类型的值

Broken-down time is stored in the structure tm, which is defined in <time.h> as follows:

struct tm {
  int tm_sec;    /* Seconds (0-60) */
  int tm_min;    /* Minutes (0-59) */
  int tm_hour;   /* Hours (0-23) */
  int tm_mday;   /* Day of the month (1-31) */
  int tm_mon;    /* Month (0-11) */
  int tm_year;   /* Year - 1900 */
  int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
  int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
  int tm_isdst;  /* Daylight saving time */
};

具体的实现代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
//-rw-rw-r-- 1 book book 1353 8月  17 17:31 daemon.c

void file_type(struct stat m,char *buf)
{

    if(S_ISREG(m.st_mode))  //is it a regular file?
        buf[0]='-';
    else if(S_ISDIR(m.st_mode)) //  directory?
        buf[0]='d';
    else if(S_ISCHR(m.st_mode)) // character device?
        buf[0]='c';
    else if(S_ISBLK(m.st_mode))  //block device?
        buf[0]='b';
    else if(S_ISFIFO(m.st_mode)) //FIFO (named pipe)?
        buf[0]='p';
    else if(S_ISLNK(m.st_mode))  //symbolic link?  (Not in POSIX.1-1996.)
        buf[0]='l';
    else if(S_ISSOCK(m.st_mode))  //symbolic link?  (Not in POSIX.1-1996.)
        buf[0]='s';
}

void file_permission(struct stat m,char* buf)
{
    if(m.st_mode & S_IRUSR)
        buf[1]='r';

    if(m.st_mode & S_IWUSR)
        buf[2]='w';

    if(m.st_mode & S_IXUSR)
        buf[3]='x';

    if(m.st_mode & S_IRGRP)
        buf[4]='r';
        
	if(m.st_mode & S_IWGRP)
        buf[5]='w';

    if(m.st_mode & S_IXGRP)
        buf[6]='x';

    if(m.st_mode & S_IROTH)
        buf[7]='r';

    if(m.st_mode & S_IWOTH)
        buf[8]='w';

    if(m.st_mode & S_IXOTH)
        buf[9]='x';
}

//时间获取
struct tm *get_FileAcessTime(const time_t *timep)
{
    struct tm *get_FileTime = localtime(timep);
    return get_FileTime;
}

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("./%s filename.\n",argv[0]);
        return -1;
    }
    //调用stat 得到文件属性信息
    struct stat sb;
    stat(argv[1],&sb);

  //获取文件类型信息和文件权限信息,并保存到数组中
    char stmode[11];
    memset(stmode,'-',sizeof(stmode));
    //文件类型
    file_type(sb,stmode);
	//文件权限位
    file_permission(sb,stmode);
    stmode[10]='\0';

    //硬连接数量--可通过struct stat来获得
    //文件用户名--可通过函数getpwuid来获得
    //文件组用户名--可通过函数getgrgid来获得
    //文件大小--可直接通过struct stat来获得
    //时间可通过函数localtime来获取
    
    //获取文件的时间信息,并保存到数组中
    char timebuf[20];
    struct tm *get_Time = get_FileAcessTime(&sb.st_atim.tv_sec);
    sprintf(timebuf,"%d月  %d %d:%d",get_Time->tm_mon+1,get_Time->tm_mday,get_Time->tm_hour,get_Time->tm_min);

 //-rw-rw-r-- 1 book book 1353 8月  17 17:31 daemon.c
    printf("%s %lu %s %s %lu %s %s\n",stmode,sb.st_nlink,getpwuid(sb.st_uid)->pw_name,getgrgid(sb.st_gid)->gr_name,sb.st_size,timebuf,argv[1]);

    return 0;
}

程序运行结果并验证:
在这里插入图片描述

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号