Linux---系统函数

发布于:2025-02-16 ⋅ 阅读:(27) ⋅ 点赞:(0)

一、打开文件open

#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_TRUNC   //文件存在  截短为0 
  @mode     一般不用
            当flags中使用了 O_CREAT 时,需要指定 mode   
            mode 0777
                 0666
                 0444                  
返回值:
  成功 文件描述符
  失败 -1 && errno会被设置 
 

#include<stdio.h>
#include<fcntl.h>

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

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

	if(fd < 0)
	{
		perror("open fail");
		return -1;
	}


#if 0
	printf("open succes fd = %d\n",fd);


	printf("stdin fileno = %d\n",stdin->_fileno);
	printf("stdout fileno = %d\n",stdout->_fileno);
	printf("stderr fileno = %d\n",stderr->_fileno);
#endif
	
	return 0;
}

  
对比fopen             open


r                O_RDONLY 
r+               O_RDWR

w                O_WRONLY|O_CREAT|O_TRUNC 
w+               O_RDWR|O_CREAT|O_TRUNC

a                O_WRONLY|O_APPEND|O_CREAT
a+               O_RDWR |O_APPEND|O_CREAT
 

文件创建好后的权限:


  a.指定的mode 
  b.umask  (掩码) //二进制位 --- 遮住 

  最终文件的权限 = ~umask & mode

二、关闭文件 close

int close(int fd);
功能:
   关闭文件描述符
   以便 再次使用 
参数:
  @fd  要关闭的文件描述符
返回值:
  成功 0
  失败 -1 
  
文件描述符:
1.非负整型数值 
2.分配原则
  最小未使用   
3.范围 
  0~1023 
 

三、读写文件 read   write

#include <unistd.h>


(一)ssize_t  read(int fd,      void *buf, size_t count);


功能: 
    从fd中读数据 ,存到 buf中 
参数:
   @fd 要读取的文件 
   @buf 存放读取到的数据的 内存空间 
   @count 一次要读取的数量(字节)
返回值:
   成功 表示成功读到的字节数 
   失败 -1 && errno 
   
   读取结束:
      0 表示到达文件结尾


(二)ssize_t write(int fd,const void *buf, size_t count);


功能: 
    把buf中 写到fd中 
参数:
   @fd    要写入的文件 
   @buf   存放数据的 内存空间 
   @count 一次要写入的数量(字节)
返回值:
   成功 表示成功写入的字节数 
   失败 -1 && errno 
 

#include<stdio.h>
#include<unistd.h>

int main(int argc, const char *argv[])
{
	char buf[1024] = {0};

	while(1)
	{
		int ret = read(0,buf,100);
	//	buf[ret-1] = '\0';
	//	printf("ret = %d buf = %s\n",ret,buf);
	
		write(1,buf,ret);
	}

	return 0;
}

练习:
   cat  //文件IO 实现 

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>


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

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

	if(fp < 0)
	{
		perror("open fail");
		return -1;
	}

	char buf[1024] = {0};

	int ret = 0;

	while(ret = read(fp,buf,sizeof(buf)-1) )
	{
		write(1,buf,ret);
	}

	close(fp);
	return 0;
}

练习:
   实现cp 

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>


int main(int argc, const char *argv[])
{
	if(argc != 3)
	{
		printf("Usage: %s <dest> <srt>\n",argv[0]);
		return -1;
	}

	int fp1 = open(argv[1],O_RDONLY);
	int fp2 = open(argv[2],O_WRONLY | O_CREAT|O_TRUNC ,0666);

	if(fp1 < 0 || fp2 < 0)
	{
		perror("open fail");
		return -1;
	}

	char buf[1024] = {0};

	int ret = 0;

	while(ret = read(fp1,buf,sizeof(buf)-1) )
	{

		write(fp2,buf,ret);
	}

	close(fp1);
	close(fp2);
	return 0;
}

四、偏移lseek 

off_t lseek(int fd, off_t offset, int whence);
功能:
     重新定位文件偏移量 
参数:
    @fd      要定位的文件 
    @offset  偏移量 
    @whence  参考点 
               SEEK_SET //相对于文件开头的 
                  offset >=0 
               SEEK_CUR //相对于当前位置
                  offset>=0
                  offset<0   //不能超过这个文件开头
               SEEK_END //相对于文件末尾 
                  offset < 0  //不能超过这个文件开头
                  offset >= 0 //可以  --- 创建 空洞 文件
   
返回值:
   成功 从头的偏移量
   失败  -1 && errno

lseek(fd,0,SEEK_SET); //定位到文件开头 
lseek(fd,0,SEEK_END);

获得文件长度:
off_t len = lseek(fd,0,SEEK_END); //off_t <=> long int

注意:
    1、不支持O_APPEND的追加模式,无法生成空洞文件。
    2、lseek函数执行失败,文件指针还在偏移前的位置。
    3、lseek函数在设备文件上偏移无效。 /dev/video0 
    4、fifo,socket 也不支持lseek的操作。
   

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>

int main(int argc, const char *argv[])
{
	if(argc != 2)
	{
		printf("Usage: %s <filename>\n",argv[0]);
		return -1;
	}
	
	int fd = open(argv[1],O_RDONLY);

	if(fd < 0)
	{
		perror("open fail");
		return -1;
	}

	printf("open success fd = %d\n",fd);

	printf("len = %ld\n",lseek(fd,0,SEEK_END));

	return 0;
}

练习:
   创建空洞文件 
   给定一个文件,创建一个同样大小的空洞文件 

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>

int main(int argc, const char *argv[])
{
	if(argc != 2)
	{
		printf("Usage: %s <filename>\n",argv[0]);
		return -1;
	}
	
	int fd1 = open(argv[1],O_RDONLY);

	if(fd1 < 0)
	{
		perror("open fail");
		return -1;
	}

	int len = lseek(fd1,0,SEEK_END);

	int fd2 = open("hole.txt",O_WRONLY|O_CREAT,0666);

	if(fd2 < 0)
	{
		perror("open fail");
		return -1;
	}


	lseek(fd2,len-1,SEEK_END);//留出写'\0'的空间

	write(fd2,"",1);//该字符串指向字符串常量区,空字符串里有‘\0’

	close(fd1);
	close(fd2);
	return 0;
}

五、库函数和系统调用对比

库函数: //标准IO
     优点:
         a.方便,功能多 
         b.可移植性好 
           标准 
     不足:
         c.可能存在 安全性 隐患


系统调用:
     优点:
         a.使用起来,简单 ,功能简单
         b.安全性高 
         c.设备文件 ---- 文件IO      ///dev/video0 ----> fopen();     
     缺点:
         c.很多复杂功能需要自己封装设计
         d.可移植性差 

六、系统调用中的函数

(一)fdopen()  //将fd 转换  成 FILE *       ——       fileno()  //将FILE *转换 为 fd

1、FILE *fdopen(int fd,const char *mode);


功能:
   将fd 转换  成 FILE * 
参数:
   @fd    要操作fd
   @mode  打开的模式
返回值: 
   成功 FILE *
   失败 NULL

2、int fileno(FILE *stream);


功能:
    将FILE *转换 为 fd
参数:
   @stream  要转换流指针 
返回值:
   成功 fd 
   失败 - && errno   

#include<stdio.h>
#include<fcntl.h>

int main(int argc, const char *argv[])
{
	int fd = open("1.txt",O_RDONLY);

	if(fd < 0)
	{
		perror("open fail");
		return -1;
	}

	printf("fd = %d\n",fd);
	FILE *fp = fdopen(fd,"r");

	if(fp == NULL)
	{
		perror("fdopen fail");
		return -1;
	}

	printf("success\n");

	int fd1 = fileno(fp);

	printf("fileno = %d\n",fd1);

	return 0;
}


3、使用的选择:


  标准IO   --- 可移植性 如果操作只是文本数据 
  文件IO   --- 安全性  操作的是硬件 ---文件IO

操作目录

目录也是一种文件 
类似 标准IO 

(二)opendir

DIR *opendir(const char *name); 
功能:
    打开目录,关联一个目录流
参数:
  @name  要打开的目录名 
返回值:
  成功 返回DIR *
  失败 NULL & errno

#include<stdio.h>
#include<dirent.h>

int main(int argc, const char *argv[])
{
	DIR *dir = opendir(argv[1]);

	if(dir == NULL)
	{
		perror("opendir fail");
		return -1;
	}

	printf("success\n");
	return 0;
}

(三)读取目录readdir

struct dirent *readdir(DIR *dirp);
功能:
    读取目录项 
参数:
   @dirp 目录流指针 
返回值:
   成功 struct dirent *
   失败 NULL && errno
struct dirent 
{
    ino_t d_ino; /* Inode number */ 
    off_t d_off; /* Not an offset; see below */
    unsigned short d_reclen;/* Length of this record */
    unsigned char d_type;/* Type of file; not supported by all filesystem types */
    char d_name[256]; /* Null-terminated filename */
}

注意:
   读到文件末尾 NULL
 

#include<stdio.h>
#include<dirent.h>

int main(int argc, const char *argv[])
{
	DIR *dir = opendir(argv[1]);

	if(dir == NULL)
	{
		perror("opendir fail");
		return -1;
	}

	printf("success\n");

	struct dirent *pdir = readdir(dir);

	printf("ino = %ld\n",pdir->d_ino);
	printf("type = %d\n",pdir->d_type);
	printf("name = %s\n",pdir->d_name);
	
	closedir(dir);
	return 0;
}

(四)close

int closedir(DIR *dirp);
   功能:
      关闭目录流
   参数:
      @dirp --- 目录流指针 
   返回值:
      成功 0
      失败 -1 &&errno 
 

练习:
    实现ls

#include<stdio.h>
#include<dirent.h>

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

	DIR *dir = opendir(argv[1]);

	if(dir == NULL)
	{
		perror("opendir fail");
		return -1;
	}

	struct dirent *pdir ;

	while((pdir = readdir(dir)) != NULL)
	{
		if(pdir->d_name[0] != '.')
		printf("%s  ",pdir->d_name);
	}

	putchar('\n');

	closedir(dir);
	return 0;
}

练习:
   shell 
   给定一个目录,统计目录下的 普通文件 和 目录文件的个数

#include<stdio.h>
#include<dirent.h>

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

	DIR *dir = opendir(argv[1]);

	if(dir == NULL)
	{
		perror("opendir fail");
		return -1;
	}

	struct dirent *pdir ;

	int n = 0;
	while((pdir = readdir(dir)) != NULL)
	{
		if(pdir->d_type == DT_REG)
		{
			n++;
		}
	}

	rewinddir(dir);

	int m = 0;
	while((pdir = readdir(dir)) != NULL)
	{
		if(pdir->d_type == DT_DIR)
		{
			m++;
		}
	}

	printf("directory = %d\n",m);
	printf("regular = %d\n",n);

	closedir(dir);
	return 0;
}

(五)chdir

chdir ("/home/linux"); "../../"
fopen("1.mp4")
int chdir(const char *path);// /home/linux
功能:
    改变当前程序的工作路径
参数:
    path:改变到的路径
返回值:
    成功 返回0
    失败 返回-1


(六)getcwd

char *getcwd(char *buf, size_t size);
功能:
    获得当前的工作路径
参数:
    buf:保存工作路径空间的首地址
    size:保存路径空间的长度
返回值:
    成功返回包含路径空间的字符串首地址
    失败返回NULL
 

#include<stdio.h>
#include<unistd.h>

int main(int argc, const char *argv[])
{
	char buf[1024];

	getcwd(buf,sizeof(buf));

	printf("cwd = %s\n",buf);

	chdir("/home");
	
	getcwd(buf,sizeof(buf));

	printf("cwd = %s\n",buf);


	return 0;
}

(七)mkdir

nt mkdir(const char *pathname, mode_t mode);//777  666 --x--x--x
功能:
    创建一个目录
    666-
参数:
    pathname:路径
    mode:
        mode & ~umask  0002
        
返回值:
    成功 返回0
    失败 返回-1
 

(八)rmdir

int rmdir(const char *pathname);
功能:
    删除一个空目录文件
参数:
    pathname:目录文件的名字
返回值:
    成功 返回0
    失败 返回-1

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

int main(int argc, const char *argv[])
{
	if(argc != 2)
	{
		printf("Usage: %s <dirname>",argv[0]);
		return -1;
	}

#if 0
	if(-1 == mkdir(argv[1],0777))
	{
		printf("mkdir fail\n");
	}else
	{
		printf("mkdir success\n");
	}
#endif

	if(-1 == rmdir(argv[1]))
	{
		printf("rmdir fail\n");
	}else
	{
		printf("rmdir success\n");
	}



	return 0;
}

(九)sprintf

将格式化的输出结果,放到一个 字符数组空间上 形成一个字符串

#include<stdio.h>

int main(int argc, const char *argv[])
{
#if 0
	int a = 10;
	float b = 2.1;
	char c = 'A';

	printf("a = %d b = %f c = %c\n",a,b,c);

	char buf[1024];
	sprintf(buf,"%d %f %c",a,b,c);

	printf("buf = %s\n",buf);
#endif

	char buf[1024];
	sprintf(buf,"%s/%s",argv[1],argv[2]);

	printf("buf = %s\n",buf);
	return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到