Linux系统编程1、open函数 2、read读设备文件、网络文件、管道文件会阻塞 3、lseek重新制定read write的偏移 4、dup2重定向 5、常见命令(ls cp mv)的源码实现

1、open函数

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

int main(int argc, char *argv[])
{
	int fd = open("./mydir", O_WRONLY);
	printf("fd = %d, errno = %d\n", fd, errno);
	if (fd == -1)
	{
		printf("%s\n", strerror(errno));
	}

	
	int fd1 = close(fd);
	printf("fd1 = %d\n", fd1);
	if (fd1 == -1)
	{
		printf("%s\n", strerror(errno));
	}

	return 0;

}

2、实现cp-系统函数

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


int main(int args, char *argv[])
{
	// 1、打开要复制的文件
	int fd1 = open(argv[1], O_RDONLY);
	if (fd1 == -1)
		printf("%s\n", strerror(errno));
	// 2、新建1个空文件
	int fd2 = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
	if (fd2 == -1)
		printf("%s\n", strerror(errno));
	// 循环3、4、读文件到末尾read返回0
	int counts1;
	char buf[BUFSIZ];
	while (1)
	{
		// 3、读取该文件
		counts1 = read(fd1, buf, BUFSIZ);
		// 4、读取到的内容写到空文件中
		write(fd2, buf, counts1);
		if (counts1 == 0)
			break;
	}
	// 5、关闭打开的文件
	close(fd1);
	close(fd2);

	return 0;
}

2、实现cp-库函数 

#include <stdio.h>

int main(int argc, char *argv[])
{
	// 1、只读方式打开文件
	FILE * f1 = fopen(argv[1], "r");
	// 2、创建新文件
	FILE * f2 = fopen(argv[2], "w");
	char buf[1];
	int n; //读到的字节数
	// 循环3、4、
	while (1)
	{

		// 3、读文件存到缓冲区
		 n = fgetc(f1);
		// 4、写到新文件中
		 fputc(n, f2);
		if (n == EOF)
			break;
	}
	fclose(f1);
	fclose(f2);

	return 0;
}

3、read读设备文件、网络文件、管道文件会阻塞

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
	char buf[10];
	int n;
	int flags = fcntl(STDIN_FILENO, F_GETFL);
	if (flags == -1)
	{
		perror("fcntl STDIN_FILENO");
		exit(1);
	}
	flags |= O_NONBLOCK;
	int ret = fcntl(STDIN_FILENO, F_SETFL, flags);
	if (ret == -1)
	{
		perror("fcntl STDIN_FILENO");
		exit(1);
	}

tryagain:
	n = read(STDIN_FILENO, buf, 10);
	if (n < 0)
	{
		if (errno != EAGAIN)
		{
			perror("read /dev/tty");
			exit(1);
		}
		else
		{
			write(STDOUT_FILENO, "try again\n", strlen("try again\n"));
			sleep(2);
			goto tryagain;
		}
	}
	write(STDOUT_FILENO, buf, n);

	return 0;
}

4、lseek重新制定read write的偏移位置

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


int main(void)
{
	int fd, n;
	char msg[] = "It's a test for lseek\n";
	char ch;

	fd = open("lseek.txt", O_RDWR | O_CREAT, 0644);
	if (fd < 0)
	{
		perror("open lseek.txt");
		exit(1);
	}

	write(fd, msg, strlen(msg));
	
	lseek(fd, 0, SEEK_SET);

	while ((n = read(fd, &ch, 1))) // 1个1个字符往外读
	{
		if (n < 0)
		{
			perror("read error");
			exit(1);
		}
		write(STDOUT_FILENO, &ch, n); // 1个1个字符往屏幕上写
	}
	close(fd);

	return 0;
}

4、lseek结合实际IO写入-获取文件及扩展文件大小 

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

int main(void)
{
	int fd;
	off_t n;
	fd = open("lseek.txt", O_RDWR);
	if (fd < 0)
	{
		perror("open lseek.txt");
		exit(1);
	}

	n = lseek(fd, 0, SEEK_END);
	printf("文件大小 = %ld\n", n);

	printf("扩展1000字节\n");
	n = lseek(fd, 1000 - 1, SEEK_END);
	printf("文件大小 = %ld\n", n);
	// 真正拓展文件大小-引起文件IO操作
	write(fd, "\n", 1);

	close(fd);

	return 0;
}

5、trunctate拓展文件 

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

int main(void)
{
	int n = truncate("./dict.txt", 1000);
	if (n == -1)
	{
		perror("truncate error");
		exit(1);
	}

	return 0;

}

6、stat获取文件属性(默认穿透)

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

int main(int argc, char *argv[])
{
	int ret;
	struct stat buf;
	ret = stat(argv[1], &buf);
	if (ret == -1)
	{
		perror("stat error");
		exit(1);
	}
	// 打印信息
	printf("size = %ld, inode = %ld\n", buf.st_size, buf.st_ino);
	// 判断文件类型
	switch (buf.st_mode & S_IFMT)
	{
		case S_IFLNK : 
			printf("软链接文件\n"); 
			break;
		case S_IFREG : 
			printf("普通文件\n"); 
			break;
		case S_IFBLK : 
			printf("块设备文件\n"); 
			break;
		case S_IFSOCK : 
			printf("套接字文件\n"); 
			break;
		case S_IFDIR : 
			printf("目录文件\n"); 
			break;
		case S_IFCHR : 
			printf("字符设备文件\n"); 
			break;
		case S_IFIFO : 
			printf("管道文件\n"); 
			break;
		default:
			printf("未知文件类型\n");
			break;
	};

	return 0;
}

6、lstat获取文件属性(不穿透) 

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

int main(int argc, char *argv[])
{
	int ret;
	struct stat buf;
	ret = lstat(argv[1], &buf);
	if (ret == -1)
	{
		perror("stat error");
		exit(1);
	}
	// 打印信息
	printf("size = %ld, inode = %ld\n", buf.st_size, buf.st_ino);
	// 判断文件类型
	switch (buf.st_mode & S_IFMT)
	{
		case S_IFLNK : 
			printf("软链接文件\n"); 
			break;
		case S_IFREG : 
			printf("普通文件\n"); 
			break;
		case S_IFBLK : 
			printf("块设备文件\n"); 
			break;
		case S_IFSOCK : 
			printf("套接字文件\n"); 
			break;
		case S_IFDIR : 
			printf("目录文件\n"); 
			break;
		case S_IFCHR : 
			printf("字符设备文件\n"); 
			break;
		case S_IFIFO : 
			printf("管道文件\n"); 
			break;
		default:
			printf("未知文件类型\n");
			break;
	};

	return 0;
}

7、利用link和ulink实现mv 

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

int main(int args, char *argv[])
{
    int ret1 = link(argv[1], argv[2]);
    if (ret1 == -1)
    {
        perror("link error");
        exit(1);
    }
    int ret2 = unlink(argv[1]);
    if (ret2 == -1)
    {
        perror("link error");
        exit(1);
    }

    return 0;
}

8、getcwd获取当前工作目录 和chdir改变工作目录 

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

int main(int argc, char *argv[])
{
    char buf[1024];
    char * str = getcwd(buf, 1024);
    if (str == NULL)
    {
        perror("getcwd error");
        exit(1);
    }
    printf("当前工作目录在%s\n", buf);
    int ret2 = chdir(argv[1]);
    if (ret2 == -1)
    {
        perror("chdir error");
        exit(1);
    }
    str = getcwd(buf, 1024);
    if (str == NULL)
    {
        perror("getcwd error");
        exit(1);
    }
    printf("当前工作目录在%s\n", buf);

    return 0;
}

9、readdir实现ls(无递归) 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
// 判断文件类型
int IsDir(const char *str)
{
    int ret;
    struct stat buf;
    ret = stat(str, &buf);
    if (ret == -1)
    {
        perror("stat error");
        return -1; // 判断失败
    }
    if (S_ISDIR(buf.st_mode))
        return 1; // 是目录
    else
        return 0; // 其他文件类型
}

void LS(const char *path)
{
    int ret1 = IsDir(path);
    if (ret1 != 1)
        printf("%s ", path); // 非目录直接打印
    else // 目录--
    {
        // 1、打开目录
        DIR * dp = opendir(path);
        if (dp == NULL)
        {
            perror("opendir error");
            exit(1);
        } 
        // 2、循环的读目录
        struct dirent * dbuf;
        while ((dbuf = readdir(dp)) != NULL)
        {
            // ls默认隐藏.开头的文件
            if (dbuf->d_name[0] != '.')
                printf("%s ", dbuf->d_name);
        }
        // 3、关闭目录
        int ret2 = closedir(dp);
        if (ret2 == -1)
        {
            perror("closedir error");
            exit(1);
        }
    }
    return ;
}

int main(int argc, char *argv[])
{
    if (argc == 1)
        LS("./");
    else
    {
        for (int i = 1; i < argc; ++i)
            LS(argv[i]);
    }
        
    return 0;
}

9、readdir实现ls(递归)  

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
// 判断文件类型
int IsDir(const char *str)
{
    int ret;
    struct stat buf;
    ret = stat(str, &buf);
    if (ret == -1)
    {
        perror("stat error");
        return -1; // 判断失败
    }
    if (S_ISDIR(buf.st_mode))
        return 1; // 是目录
    else
        return 0; // 其他文件类型
}

void LS(const char *path)
{
    int ret1 = IsDir(path);
    if (ret1 != 1)
        printf("%s\n", path); // 非目录直接打印
    else                     // 目录--
    {
        // 1、打开目录
        DIR *dp = opendir(path);
        if (dp == NULL)
        {
            perror("opendir error");
            exit(1);
        }
        // 2、循环的读目录
        struct dirent *dbuf;
        while ((dbuf = readdir(dp)) != NULL)
        {
            // ls默认隐藏.开头的文件
            if (dbuf->d_name[0] == '.')
                continue;
            // 1、判断读出来的文件是目录?
            if (dbuf->d_type == DT_DIR)
            {
                // 2、是目录-递归调用自己
                // 拼接绝对路径
                printf("%s\t", dbuf->d_name);
                char pj[BUFSIZ];
                sprintf(pj, "%s%s%s", path, "/", dbuf->d_name);
                // printf("pj = %s\n", pj);
                LS(pj);
                printf("\n");
            }
            // 2、不是目录-打印-读下一个目录项
            else
            {
                if (dbuf->d_name[0] != '.')
                    printf("%s\t", dbuf->d_name);
            }
        }
        // 3、关闭目录
        int ret2 = closedir(dp);
        if (ret2 == -1)
        {
            perror("closedir error");
            exit(1);
        }
    }
    return;
}

int main(int argc, char *argv[])
{
    if (argc == 1)
        LS("./");
    else
    {
        for (int i = 1; i < argc; ++i)
            LS(argv[i]);
    }

    return 0;
}

10、dup和dup2重定向文件描述符 

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

int main(int argc, char *argv[])
{
    int fd1 = open(argv[1], O_RDWR | O_APPEND);
    if (fd1 == -1)
    {
        perror("open error");
        exit(1);
    }
    printf("fd1 = %d\n", fd1);
    int fd2 = dup(fd1);
    printf("fd2 = %d\n", fd2);
    // read write共用同一个位置(追加O_APPEND/lseek SEEK_END设置写入位置为末尾)
    int ret2 = write(fd1, "old write\n", 10);
    if (ret2 == -1)
    {
        perror("old write");
        exit(1);
    }
    int ret3 = write(fd2, "----test----\n", 13);
    if (ret3 == -1)
    {
        perror("write error");
        exit(1);
    }
    
    int ret4 = close(fd1);
    if (ret4 == -1)
    {
        perror("close error");
        exit(1);
    }

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    int fd1 = open(argv[1], O_RDWR | O_APPEND);
    if (fd1 == -1)
    {
        perror("open error");
        exit(1);
    }
    printf("旧fd1 = %d\n", fd1);
    int fd2 = open(argv[2], O_RDWR | O_APPEND);
    if (fd2 == -1)
    {
        perror("open error");
        exit(1);
    }
    printf("新fd2 = %d\n", fd2);
    int ret1 = dup2(fd1, fd2);
    if (ret1 == -1)
    {
        perror("dup2 error");
        exit(1);
    }
    printf("dup2返回值 = %d\n", ret1);
    // read write共用同一个位置(追加O_APPEND/lseek SEEK_END设置写入位置为末尾)
    int ret2 = write(fd1, "old write\n", 10);
    if (ret2 == -1)
    {
        perror("old write");
        exit(1);
    }
    int ret3 = write(fd2, "----test----\n", 13);
    if (ret3 == -1)
    {
        perror("write error");
        exit(1);
    }
    
    int ret4 = close(fd1);
    if (ret4 == -1)
    {
        perror("close error");
        exit(1);
    }
    
    return 0;
}

9、dup2重定向标准输出 

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


int main(int argc, char *argv[])
{
    int fd = open(argv[1], O_RDWR | O_APPEND);
    if (fd == -1)
    {
        perror("open error");
        exit(1);
    }
    int ret1 = dup2(fd, STDOUT_FILENO); // 重定向标准输出-打开的文件上
    if (ret1 == -1)
    {
        perror("dup2 error");
        exit(1);
    }
    printf("dup2返回值%d\n", ret1);
    int i = 0;
    while (i < 20)
    {
        printf("hello %d\n", i);
        ++i;
        sleep(1);        
    }

    return 0;
}

9、fcntl实现dup2

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

int main(int argc, char *argv[])
{
    int fd1 = open(argv[1], O_RDWR | O_APPEND);
    printf("fd1 = %d\n", fd1);
    write(fd1, "the first write\n", 17);

    int ret = fcntl(fd1, F_DUPFD, 0); // 返回1个新的文件描述符--类似dup(fd); dup2(fd1, fd2);
    printf("newfd = %d\n", ret);
    write(ret, "the second write\n", 18);

    int ret1 = fcntl(fd1, F_DUPFD, 7); // 返回1个新的文件描述符--类似dup(fd); dup2(fd1, fd2);
    printf("newfd1 = %d\n", ret1);
    write(ret1, "the third write\n", 17);
    write(7, "the third 7 write\n", 19);

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪呈祥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值