Linux文件系统【02】creat,open,close,read,write,lseek;ioctl,fcntl,dup,dup2,自定义创建文件命令

目录

前言

1, open()

2,creat()  

3, close()

4,自己写创建文件的命令(可以附加上权限设置,期待后续)

5, read()

6, write()

7, lseek()

8, dup、dup2

9, fcntl

10, ioctl


前言

fopen,fclose,fread,fwrite,fseek;是C语言标准库的,方便移植;
文件的创建,打开,关闭,读,写,光标:
creat,open,close,read,write,lseek;


什么是文件描述符?
文件描述符是Unix特有的,其为一个非负整数,取值范围是0-NR_OPEN,对于Linux,NR_OPEN=255;也就是每个程序只能打开256 个文件;当使用open或者creat打开或者创建一个文件的时候,如果成功则将返回一个文件描述符,在进行读写操作时(read/write),文件描述符作为参数传递给(read/write);
文件描述符0代表标准输入文件,一般就是键盘,1代表标准输出文件,一般就是显示器,2代表标准错误输出,一般也是显示器;


1, open()

#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);


pathname,含路径的文件名
flags文件打开方式:


这三种只能三选一。


O_SYNC,O_NONBLOCK,O_NDELAY同步异步阻塞非阻塞等等(待解决)
当使用O_CREAT时,才使用参数mode,用来说明新文件的权限(权限实际上是mode||umask),mode的取值:

2,creat()  

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int creat(const char *pathname , mode_t mode);

创建或者覆盖原有文件

pathname,含路径的文件名

mode与open的相同

3, close()

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

        fd:文件描述符。

        调用成功返回0,失败返回-1;

        不保证数据全部存回硬盘。

4,自己写创建文件的命令(可以附加上权限设置,期待后续)

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

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

    if(argc<2)
    {
        printf("%s<mode num><target file>\n",argv[0]);
        _exit(0);
    }

    path=argv[1];
    if((fd=open(path,O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1)
    {
        perror("open");
        _exit(1);
    }
    else
    {
        printf("creat a file success");
    }
    close(fd);
    return 0;
}

  

5, read()

#include<unistd.h>
ssize_t read(int fd, void *buf,size_t count);

从文件描述符所指向的文件中读取count个字符到buf所指向的缓存中。

当count=0,read不读取数据,只返回0;

读取成功返回读取到的字节数,与count作比较,如果返回字节数目比count少,则是读到了文件末尾或者读取过程中信号被中断了等等。读取失败则返回-1;存到errno中;

文件读写指针随着读写移动;

6, write()

#include<unistd.h>
ssize_t write(int fd, void *buf,size_t count);

将buf指向的缓冲区中的count个字节写到fd所指示的文件当中。

返回写入的字节数

错误返回-1,存到errno中;

7, lseek()

#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fildes,off_t offset,int whence);

lseek()用来控制该文件的读写文件;

参数fildes为已经打开的文件的文件描述符;

参数offset为根据whence来移动读写位置的位移数;

参数whence:

 lseek允许文件指针的值设置到文件结束符(EOF)之后,但并不会改变文件大小,在此位置写入数据之后,此段数据与之前的(EOF)之间是数据0;

有些设备文件不能使用lseek,比如Linux的tty文件,用lseek会返回错误代码ESPIPE;

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


//报错函数
void my_err(const char *err_string,int line)
{
    fprintf(stderr,"line:%d",line);
    perror(err_string);
    _exit(1);
}

//读数据函数
int my_read(int fd)
{
    int len;
    int ret;
    int i;
    char read_buf[64];

    //指针移到最后
    if(lseek(fd,0,SEEK_END)==-1)
    {
        my_err("lseek",__LINE__);
    }

    //最后位置到文件开始位置字节数
    if((len=lseek(fd,0,SEEK_CUR))==-1)
    {
        my_err("lseek",__LINE__);
    }

    //指针回到文件开始处,下一步方便读取数据
    if(lseek(fd,0,SEEK_SET)==-1)
    {
        my_err("lseek",__LINE__);
    }

    printf("len:%d\n",len);

    //读取数据,返回读取字节数
    if((ret=read(fd,read_buf,len))<0)
    {

        my_err("read",__LINE__);
    }

    //打印
    for(i=0;i<len;i++)
    {
        printf("%c",read_buf[i]);

    }
    printf("\n");
    return ret;

}

int main()
{
    int fd;
    char write_buf[32]="Hello World";
    char write_buf2[32]="Q";

    if((fd=open("test.txt",O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR))==-1)
    {
        my_err("open",__LINE__);
    }
    else
    {
        printf("creat the file success\n");
    }

    if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf))
    {
        my_err("write",__LINE__);
    }
    printf("---------------------------------\n");
    if(lseek(fd,10,SEEK_END)==-1)
    {
        my_err("lseek",__LINE__);
    }
    if(write(fd,write_buf2,strlen(write_buf2))!=strlen(write_buf2))
    {
        my_err("write",__LINE__);
    }
    my_read(fd);
    close(fd);
    return 0;
}

__LINE__内置宏,提示错误位置

类似还有__TIME__,__FUNCTION__,__FILE__等等;

8, dup、dup2

都是用于复制文件描述符(意义不同于平时的复制文本)

#include<unistd.h>
int dup(int oldfd);
int dup2(int oldfd,int newfd);

dup成功返回最小尚未被使用的文件描述符,失败返回-1;新文件描述符等同于旧文件描述符;

dup2返回指定的文件描述符newfd;newfd被占用时先释放newfd,再复制,当oldfd=newfd时,不释放。成功返回newfd,失败返回-1。

输入输出重定向?

9, fcntl

对已经打开的文件描述符进行操作改变其各种属性

#include<unistd.h>
#include<funtl.h>
int fcntl(int fd,int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock *lock);

参数cmd:

(a)F_DUPFD。同dup

(b)F_GETFD。获取文件描述符的close-on-exec标志,成功返回标志值,若其最后一位为0,则表示执行exec相关函数之后文件描述符韩式打开的,不然则是已经该关闭文件描述符;失败返回-1。

(c)F_SETFD。将close-on-exec标志为arg的最后一位,成功返回0,失败返回-1;

(d)F_GETFD。获取文件打开方式。成功返回标志值失败返回-1。见open的参数flags。

(e)F_SETFD。设置打开方式为arg的指定方式(O_APPEND,O_NONBLOCK与O_ASYNC之一)。见open参数flags。

例子:

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

void my_err(const char *err_string,int line)
{
    fprintf(stderr,"line:%d",line);
    perror(err_string);
    _exit(1);
}

int main()
{
    int ret;
    int access_mode;
    int fd;
    if((fd=open("test.txt",O_RDONLY))==-1)
    {
        my_err("open",__LINE__);
    }

    if((ret=fcntl(fd,F_GETFL,0))<0)
    {
        my_err("fcntl",__LINE__);
    }
    access_mode=ret&O_ACCMODE;
    if(access_mode==O_RDONLY)
    {
        printf("test.txt access mode:read only");
    }
    else if(access_mode==O_WRONLY)
    {
        printf("test.txt access mode:read only");
    }
    else if(access_mode==O_RDWR)
    {
         printf("test.txt access mode:read + write");
    }

    if(ret&O_APPEND)
    {
        printf(" ,append");
    }


    if(ret&O_NONBLOCK)
    {
        printf(" ,nonblock");
    }


    if(ret&O_SYNC)
    {
        printf(" ,sync");
    }

    printf("\n");
    return 0;

}

测试结果:

 (f)F_GETLK。参数lock指向一个希望设置的锁的结构体,如果目标位置的锁能够被设置,那么修改结构体的i_type为U_UNLCK,然后返回。如果目标位置有锁且冲突,那么返回一个冲突的锁的结构。

(g)F_SETLK。设置或者释放锁。i_type为F_RDLCK或者F_WRLCK时,指定区域设置锁,当i_type时释放锁。当锁被其他进程占用时,返回-1,且设置errno为EACCES或者EAGAIN。注意文件的打开方式要相应,例如设置读锁要以可读方式打开

(h)F_SETLKW。功能与F_SETLK相似,不过当有其他锁存在而被阻值时,会等待冲突的锁被释放

(i)F_GETOWN

(j)F_SETOWN

(k)F_SETSIG

(l)F_GETSIG

10, ioctl

用来控制设备

#include<sys/ioctl.h>
int ioctl(int fd,int request,...);

第三个参数一般为char *argp,其随reques不同而不同,request决定argp是向ioctl传递数据还是获取数据。

#include<stdio.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<net/if.h>
#include<string.h>


unsigned char g_macaddr[6];
unsigned int g_subnetmask;
unsigned int g_ipaddr;
unsigned int g_broadcast_ipaddr;

void init_net(void)
{
    int i;
    int sock;
    struct sockaddr_in sin;
    struct ifreq ifr;
    char g_eth_name[16];

    sock=socket(AF_INET,SOCK_DGRAM,0);
    if(sock==-1)
    {
        perror("socket");
    }

    strcpy(g_eth_name,"ens33");//注意ens33,应该ifconfig一下在决定是什么,未知原因,没学到网络编程,后续补充
    strcpy(ifr.ifr_name,g_eth_name);
    printf("eth name:\t%s\n",g_eth_name);
    if(ioctl(sock,SIOCGIFHWADDR,&ifr)<0)
    {
        perror("ioctl");
    }
    memcpy(g_macaddr,ifr.ifr_hwaddr.sa_data,6);

    printf("local mac:\t");
    for(i=0;i<5;i++)
    {
        printf("%.2x:",g_macaddr[i]);

    }
    printf("%.2x:\n",g_macaddr[i]);


    if(ioctl(sock,SIOCGIFADDR,&ifr)<0)
    {
        perror("ioctl");
    }
    memcpy(&sin,&ifr.ifr_addr,sizeof (sin));
    g_ipaddr=sin.sin_addr.s_addr;
    printf("local eth0:\t%s\n",inet_ntoa(sin.sin_addr));

    if(ioctl(sock,SIOCGIFBRDADDR,&ifr)<0)
    {
        perror("ioctl");
    }
    memcpy(&sin,&ifr.ifr_addr,sizeof (sin));
    g_broadcast_ipaddr=sin.sin_addr.s_addr;
    printf("broadcast:\t%s\n",inet_ntoa(sin.sin_addr));

    if(ioctl(sock,SIOCGIFNETMASK,&ifr)<0)
    {
        perror("ioctl");
    }
    memcpy(&sin,&ifr.ifr_addr,sizeof (sin));
    g_broadcast_ipaddr=sin.sin_addr.s_addr;
    printf("subnetmask:\t%s\n",inet_ntoa(sin.sin_addr));

    close(sock);
}

int main()
{
    init_net();
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值