二、环境编程001

1、系统Api

\08_Li命基\08d03(-IO)\3-视频12
linux/src/print_where.c
fd文件操作描述符,启动一个进程后,linux系统在进程的进程控制块PCB中,默认开启3个操作,stdin stdout stderr 。对应的文件的文件描述符表(一共1024个数字)的前三个数字012,open函数操作对应的文件描述符表中的最小的可用的那个,下文代码close(1)把文件描述符表的第二个关了,所以open函数返回的fd对应的文件描述符表中的文件描述符就是1,
后边printf()函数调用write(1,“hello”,0644);写在了缓冲区中,如果灭有fflush()函数,此段代码只能生成可执行文件a.out,执行a.out后只能生成一个空的1.log文件,因为需要刷新缓冲区才能把刚才print()写的内容写进刚才open()函数打开的文件中

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

int main()
{
        close(1);
        int fd=open("1.log",O_CREAT|O_TRUNC|O_WRONLY,0644);
        printf("hello world\n");
        fflush(stdout);
//      close(stdout);  // 不能这么写,只能用上面的语句刷新
        close(fd);
        return 0;
}

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

2、文件IO

open
查看 man 2 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_RDONLY 只读
      • O_WRONLY 只写
      • O_RDWR 读写
    • 可选项
      • O_APPEND 追加
      • O_CREAT 创建文件
        • O_EXCL 与O_CREAT 一起使用,如果文件存在则报错
          mode权限位(mode & ~umask) umask0002补码755 再和mode与一下的出该文件的权限
      • O_NONBLOCK 非阻塞
  • 返回值,成功返回打开的描述符表中的对应的文件描述符,失败返回-1

close
头文件 #include <unistd.h>

int close(int fd);
成功返回0;失败返回-1 并设置err number

选项就是一个位符,对应的位置如果是,就设置为1,不然就是0,

  • 1 esc下 gg=G调整代码规范
  • 2 对应数open 选中 按下2 再按下大K,跳到函数原型,把头文件粘贴回来

example 用open和close实现touch (权限是664),所以open给的权限应该是0666,

#include<unistd.h>  //close的头文件
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[] )
{
        if(argc!=2)  // argc代表参数个数,至少有两个,第一个是路径,第二个是名字,
        {
                printf("./out filename\n");
        }

        int fd=open(argv[1],O_RDONLY|O_CREAT,0666);  // 第一个参数取出来名字,用来创建
        close(fd);
        return 0;
}

3、read,write

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
  • fd 文件描述符

  • buf 缓冲区

  • count 缓冲区大小

  • 返回值

    • -1 失败
    • 0 读到文件末尾
    • 非零正数,读到的文件大小字节数
    • 非阻塞状态返回-1,此时需要判断errno的值

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

  • 返回值

    • -1 失败
    • 0 啥也没做
    • 非0正数 写了多少字节数

用读写实现cat

STDOUT是file *类型的,fd是int类型的,虽然指向同一个,但类型不同

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

int main(int argc,char * argv[])
{
        if(argc!=2){
                printf("./a.out filename\n");
        return -1;
        }
        int fd=open(argv[1],O_RDONLY); // 第一个参数要打开读的文件名

        //read ,put to screen
        char buf[1024];
        int ret=read(fd,buf,sizeof(buf)); // 第一个参数文件描述符,返回读出的字节数

        write(STDOUT_FILENO,buf,ret);  // 输出到屏幕,第一个参数可以写 1
		//write(1,buf,ret);  // 一样
		
        close(fd);
        return 0;
}

执行此代码:

gcc myCat.c // 生成可执行文件 a.out
./a.out myCat.c  // 把.c文件读到屏幕上

练习2、

需求,打开一个文件,写入“hello world " 在输出到屏幕
自己写了一个:但是没有输出到屏幕

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

int main(int argc,char * argv[])
{
        if(argc!=2){
                printf("./a.out filename");
        return -1;
        }
        close(1);  // 把标准输出(输出到屏幕这个给关了)
        int fd=open(argv[1],O_RDWR|O_CREAT,0666);  // 打开的这个文件占用标准输出的文件符

        printf("hello world\n");  // 输出hello world  其实是写入到fd 那个文件的过程中,现在还在缓冲区
        fflush(stdout);  // 把缓冲区的hello world 写入到 fd的那个文件
        //read ,put to screen
        char buf[1024];  
        int ret=read(fd,buf,sizeof(buf));  // 读那个文件

        //write(STDOUT_FILENO,buf,ret);
        write(1,buf,ret);  // 

        close(fd);
        return 0;
}

因为读写位置更改了,要用lseek()函数来调回去 读写位置
函数:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

  • fd 文件描述符
  • offset 偏移量 一般设置成0
  • whence
    • SEEK_SET 文件开始位置
    • SEEK_CUR 当前位置
    • SEEK_END 结尾位置
  • 返回值
    • 成功 从当前位置到文件开始位置的字节数
    • 失败 -1 并设置err no
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>

int main(int argc,char * argv[])
{
        if(argc!=2){
                printf("./a.out filename\n");
                return -1;
        }
        
        int fd=open(argv[1],O_RDWR|O_CREAT,0666);

        write(fd,"hello world\n",12);  // 直接写world hello到打开的那个文件
        // 此时文件读写位置已经在文件末尾了
        //需要把文件读写位置移动到文件开始
        lseek(fd,0,SEEK_SET);  // 把读写位置回到最初的位置,为输出到屏幕做准备,不然已经读到文件末尾了,输出到屏幕就没有内容了
        
        //read ,put to screen
        char buf[1024]={0};
        int ret=read(fd,buf,sizeof(buf));

        //write(STDOUT_FILENO,buf,ret);
        write(STDOUT_FILENO,buf,ret);

        close(fd);
        return 0;
}

lseek()函数

作用:
1、调整文件读写位置
2、获取文件大小,(返回值)
3、扩展文件

作用2

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
        if(argc!=2){
                printf("./a.out filename\n");
                return -1;
        }
        int fd=open(argv[1],O_RDONLY);
        int ret=lseek(fd,0,SEEK_END);
        printf("file size if %d\n",ret);
        close(fd);
        return 0;
}

作用3

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
        if(argc!=2){
                printf("./a.out filename\n");
                return -1;
        }
        int fd=open(argv[1],O_WRONLY|O_CREAT,0666);

        int ret=lseek(fd,1024,SEEK_END);
        //需要至少写一次才能生效
        write(fd,"h",1);
        printf("file size if %d\n",ret);
        close(fd);
        return 0;
}

read函数的阻塞等待

在读设备时候会期待读的东西,如果设备没有输入,就会阻塞等待
open函数的第一个参数:文件名,可以是双引号之间的路径,如下例子
之前的open函数的第一个参数是argv[1],由命令行输入文件名

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
		int fd=open("/dev/tty",O_RDWR);  //
        //int fd=open("/dev/tty",O_RDWR|O_NONBLOCK);  // 设置打开之后非阻塞状态
        char buf[256]={0};
        int res=0;
        while(1){
                res=read(fd,buf,sizeof(buf));  // zu se
                if(res<0){
                        perror("read err:");// 输出错误信息
                        printf("res is %d\n",res);
                }
                if(res){
                        printf("buf is %s\n",buf);
                }
                printf("hahahah");
                sleep(2);  // 当非阻塞状态时候,while循环,睡一下,不然一直滚动了
        }
        close(fd);
        return 0;
}

fcntl()函数

#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
        //int fd=open("/dev/tty",O_RDWR|O_NONBLOCK);
        int fd=open("/dev/tty",O_RDWR);

		//角色函数,设置非阻塞
        int flags=fcntl(fd,F_GETFL);
        flags |=O_NONBLOCK;
        fcntl(fd,F_SETFL,flags);


        char buf[256]={0};
        int res=0;
        while(1){
                res=read(fd,buf,sizeof(buf));  // zu se
                if(res<0){
                        perror("\nread err:");
                        printf("res is %d\n",res);
                }
                if(res){
                        printf("buf is %s\n",buf);
                }
                printf("hahahah");
                sleep(10);
        }
        close(fd);
        return 0;
}

二、文件目录API接口

1、掌握stat/lstat函数的使用
2、了解文件属性相关函数使用
3、了解目录操作相关函数使用
4、掌握目录遍历相关函数的使用
5、掌握dup,dup2函数的使用
6、掌握fcntl函数的使用
进程的虚拟地址空间:

2.2 查看打开的最大的文件个数

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{

    int num=3;
    char filename[128]= {0};
    while(1)
    {
        sprintf(filename,"tem_%4d",num++);
        if(open(filename,O_RDONLY|O_CREAT,0666)<0)
        {
            perror("open err");
            break;
        }
        close(num);
    }
	printf("num is %d\n",num);

    return 0;
}

2.3.stat函数

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

  int stat(const char *pathname, struct stat *statbuf);  // 获取文件信息

结构体信息:
 struct stat {
               dev_t     st_dev;         /* ID of device containing file */
               ino_t     st_ino;         /* Inode number */      //节点号
               mode_t    st_mode;        /* File type and mode */   // 文件类型和权限
               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;     /* Block size for filesystem I/O */
               blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

节点信息:

还可以 vim ./
//来显示当前目录下的文件,再点一下才进入相应目录

mode_t st_mode; //文件权限

时间结构体:

grep -rn "struct timespec {" /usr/      //查看这个结构体,带个{更快查找 
vim +10 /usr/include/linux/time.h  //在这个文件里边找到了,就把它打开

struct timespec {
        __kernel_time_t tv_sec;                 /* seconds */   // 目前时间到1970年一月一日,0:0:0的秒数
        long            tv_nsec;                /* nanoseconds */    // 纳秒,(微秒,毫秒)
};

stat函数使用
* pathname:文件名
* struct stat 类型的 *statbuf // 传出参数 先定义struct stat sb,&sb
* 返回值
* 成功返回0,失败-1,设置errno

写一个使用的简单例子

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

int main(int argc,char * argv[])
{
        if(argc!=2)
        {
                printf("err pathname\n");
                return -1;
        }
        struct stat sb;
        stat(argv[1],&sb);
        return 0;
}

写makefile文件

SrcFiles=$(wildcard *.c)
TargetFiles=$(patsubst %.c,%,$(SrcFiles))

all:$(TargetFiles)


%:%.c
        gcc -o $@ $^ -g

clean:
        rm -f $(TargetFiles)

在命令行使用gdb调试

gdb stat001    //gdb 那个生成的可执行文件
#在gdb环境中:
(gdb) b main  // 查看主函数
(gdb) run test.cpp  // 指定执行查看这个test.cpp文件
(gdb) n  // 一行一行的执行
(gdb) p sb  // 打印sb这个结构体
(gdb) q   //退出

stat命令使用:

stat xxx.c
#得出信息,其中
最近访问:2019-12-22 17:53:13.853779014 -0800  // 访问
最近更改:2019-09-01 21:15:45.973579598 -0700  //更改内容     追加时候不改动访问时间
最近改动:2019-09-01 21:15:45.973579598 -0700  // 改动权限

实现一个ls hello显示信息:
E:\baidupan\08_Linux基础\08d04)\007
注意:
stat()函数会通过软链接,追溯到源文件显示大小,穿透!!!
而lstat()函数只会显示当前文件大小,

 int lstat(const char *pathname, struct stat *statbuf);  // 获取文件信息

2.4 access函数

返回当前用户对文件的权限,和是否存在

  #inlude <unistd.h>
  int access(const char *pathname, int mode);
  • pathname 文件名
  • mode 具体权限
    • R_OK
    • W_OK
    • X_OK
    • F_OK
  • 返回值
    • 如果有权限或者文件存在返回0,否则返回-1,设置errno
      查看函数:
#include<stdio.h>
#include <unistd.h>

int main(int argc,char * argv[])
{
        if(argc!=2)
        {
                printf("./a.out pathname\n");
                return -1;
        }
        if(access(argv[1],R_OK)==0) printf("%s,read ok\n!",argv[1]);
        if(access(argv[1],W_OK)==0) printf("%s,write ok\n!",argv[1]);
        if(access(argv[1],X_OK)==0) printf("%s,exe ok!\n",argv[1]);
        if(access(argv[1],F_OK)==0) printf("%s,file is exists!\n",argv[1]);
        return 0;
}
/*# 执行结果
txdy827@ubuntu:~/test$ ./a.out test.cpp 
test.cpp,read ok
!test.cpp,write ok
!test.cpp,file is exists!
/*

2.5truncate截断文件

如果第二个参数大于原文件大小,就扩展变大,如果原文件小于第二个参数指定的大小就截断了

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

  int truncate(const char *path, off_t length);

如下截断:

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

int main(int argc,char * argv[])
{
        if(argc!=2)
        {
                printf("./a.out pathname\n");
                return -1;
        }
        truncate(argv[1],3);
        return 0;
}

2.5哈哈

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值