当前位置:   article > 正文

Linux应用编程(2)lseek/dup/dup2函数介绍_linux dup seek

linux dup seek

lseek函数

1.lseek函数介绍

/*
 *@pram: fd     :文件描述符
 *       offset :偏移量
 *       whence :偏移开始的位置 (SEEK_SET / SEEK_CUR / SEEK_END)
 *@return value :offset到文件末尾的字节数
 */
off_t lseek(int fd, off_t offset, int whence);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 文件指针:当我们要对一个文件进行读写时,一定需要先打开这个文件,所以我们读写的所有文件都是动态文件。动态文件在内存中的形态就是文件流的形式。
  2. 文件流很长,里面有很多个字节。那我们当前正在操作的是哪个位置?GUI模式下的软件用光标来标识这个当前正在操作的位置,这是给人看的。
  3. 在动态文件中,我们会通过文件指针来表征这个正在操作的位置。所谓文件指针,就是我们文件管理表这个结构体里面的一个指针。所以文件指针其实是vnode中的一个元素。这个指针表示当前我们正在操作文件流的哪个位置。这个指针不能被直接访问,linux系统用lseek函数来访问这个文件指针。
  4. 当我们打开一个空文件时,默认情况下文件指针指向文件流的开始。所以这时候去write时写入就是从文件开头开始的。write和read函数本身自带移动文件指针的功能,所以当我write了n个字节后,文件指针会自动向后移动n位。如果需要人为的随意更改文件指针,那就只能通过lseek函数了。
  5. read和write函数都是从当前文件指针处开始操作的,所以当我们用lseek显式的将文件指针移动后,那么再去read/write时就是从移动过后的位置开始的。
  6. 回顾前面一节中我们从空文件,先write写了12字节,然后read时是空的(但是此时我们打开文件后发现12字节确实写进来了),原因就在这里,当我们写入12字节后文件指针也随着往后移动了,当我们来读取的时候,文件指针不是在文件的开头,所以读取到的数据是空的。

2 .应用

1.lseek计算文件长度

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

int cal_len(const char *pathname)
{
	int fd = -1;		// fd 就是file descriptor,文件描述符
	int ret = -1;
	
	// 第一步:打开文件
	fd = open(pathname, O_RDONLY);
	if (-1 == fd)		// 有时候也写成: (fd < 0)
	{
		//printf("\n");
		perror("文件打开错误");
		// return -1;
		return -1;
	}
	//else
	//{
		//printf("文件打开成功,fd = %d.\n", fd);
	//}
	
	// 此时文件指针指向文件开头
	// 我们用lseek将文件指针移动到末尾,然后返回值就是文件指针距离文件开头的偏移量,也就是文件的长度了
	ret = lseek(fd, 0, SEEK_END);
	
	return ret;
}

int main(int argc, char *argv[])
{
	int fd = -1;		// fd 就是file descriptor,文件描述符
	int ret = -1;
	
	if (argc != 2)
	{
		printf("usage: %s filename\n", argv[0]);
		_exit(-1);
	}
	
	printf("文件长度是:%d字节\n", cal_len(argv[1]));
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

2.用lseek构建空洞文件

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

int main(int argc, char *argv[])
{
	int fd = -1;		// fd 就是file descriptor,文件描述符
	char buf[100] = {0};
	char writebuf[20] = "abcdefg";
	int ret = -1;
	
	// 第一步:打开文件
	fd = open("222.txt", O_RDWR | O_CREAT, 0666);
	//fd = open("a.txt", O_RDONLY);
	if (-1 == fd)		// 有时候也写成: (fd < 0)
	{
		//printf("\n");
		perror("文件打开错误");
		// return -1;
		_exit(-1);
	}
	else
	{
		printf("文件打开成功,fd = %d.\n", fd);
	}
	
	ret = lseek(fd, 10, SEEK_SET);
	printf("lseek, ret = %d.\n", ret);
	
#if 1
	// 第二步:读写文件
	// 写文件
	ret = write(fd, writebuf, strlen(writebuf));
	if (ret < 0)
	{
		//printf("write失败.\n");
		perror("write失败");
		_exit(-1);
	}
	else
	{
		printf("write成功,写入了%d个字符\n", ret);
	}
#endif


#if 1
	// 读文件
	ret = read(fd, buf, 20);
	if (ret < 0)
	{
		printf("read失败\n");
		_exit(-1);
	}
	else
	{
		printf("实际读取了%d字节.\n", ret);
		printf("文件内容是:[%s].\n", buf);
	}
#endif	

	// 第三步:关闭文件
	close(fd);
	
	_exit(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

文件描述符的复制(dup/dup2)

1.dup解释

1.使用dup进行文件描述符复制

int dup(int oldfd);
/*DESCRIPTION
       The dup() system call creates a copy of the file descriptor oldfd, using the lowest-numbered unused file descriptor for the new descriptor.

       After  a  successful  return,  the old and new file descriptors may be used interchangeably.  They refer to the same open file description (see open(2)) and thus share file offset and
       file status flags; for example, if the file offset is modified by using lseek(2) on one of the file descriptors, the offset is also changed for the other.

       The two file descriptors do not share file descriptor flags (the close-on-exec flag).  The close-on-exec flag (FD_CLOEXEC; see fcntl(2)) for the duplicate descriptor is off.
*/

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. dup系统调用对fd进行复制,会返回一个新的文件描述符(譬如原来的fd是3,返回的就是4)
  2. dup系统调用有一个特点,就是自己不能指定复制后得到的fd的数字是多少,而是由操作系统内部自动分配的,分配的原则遵守fd分配的原则。
  3. dup返回的fd和原来的oldfd都指向oldfd打开的那个动态文件,操作这两个fd实际操作的都是oldfd打开的那个文件。实际上构成了文件共享。
  4. dup返回的fd和原来的oldfd同时向一个文件写入时,结果是分别写还是接续写?
  5. 缺陷:使用dup的缺陷分析
    • dup并不能指定分配的新的文件描述符的数字,dup2系统调用修复了这个缺陷,所以平时项目中实际使用时根据具体情况来决定用dup还是dup2.

2.应用(例:标准输出的重定位)

1.思路
  1. 之前课程讲过0、1、2这三个fd被标准输入、输出、错误通道占用。而且我们可以关闭这三个。
  2. 我们可以close(1)关闭标准输出,关闭后我们printf输出到标准输出的内容就看不到了。
  3. 然后我们可以使用dup重新分配得到1这个fd,这时候就把oldfd打开的这个文件和我们1这个标准输出通道给绑定起来了。这就叫标准输出的重定位。
  4. 可以看出,我们可以使用close和dup配合进行文件的重定位。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FILENAME	"1.txt"
int main(void)
{
	int fd1 = -1, fd2 = -1;
	
	fd1 = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
	if (fd1 < 0)
	{
		perror("open");
		return -1;
	}
	printf("fd1 = %d.\n", fd1);
	
	close(1);		// 1就是标准输出stdout
	
	
	// 复制文件描述符
	fd2 = dup(fd1);		// fd2一定等于1,因为前面刚刚关闭了1,这句话就把
	// 1.txt文件和标准输出就绑定起来了,所以以后输出到标准输出的信息就
	// 可以到1.txt中查看了。
	printf("fd2 = %d.\n", fd2);
	printf("this is for test.\n");
	
	close(fd1);
	return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

2.dup2

int dup2(int oldfd, int newfd);
/*
 The dup2() system call performs the same task as dup(), but instead of using the lowest-numbered unused file descriptor, it uses the file descriptor number specified in newfd.   If  the  file
       descriptor newfd was previously open, it is silently closed before being reused.

       The steps of closing and reusing the file descriptor newfd are performed atomically.  This is important, because trying to implement equivalent functionality using close(2) and dup() would be subject to race conditions, whereby newfd might be reused between the two steps.  Such reuse could happen because the main program is interrupted by a signal handler  that  allocates  a  file descriptor, or because a parallel thread allocates a file descriptor.
       Note the following points:

       *  If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.

       *  If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.

*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

1.dup2和dup的作用是一样的,都是复制一个新的文件描述符。但是dup2允许用户指定新的文件描述符的数字。

2.dup2共享文件交叉写入测试

  1. dup2复制的文件描述符,和原来的文件描述符虽然数字不一样,但是这连个指向同一个打开的文件。
  2. 交叉写入的时候,结果是接续写(实验证明的)。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


#define FILENAME	"1.txt"


int main(void)
{
	int fd1 = -1, fd2 = -1;
	
	fd1 = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
	if (fd1 < 0)
	{
		perror("open");
		return -1;
	}
	printf("fd1 = %d.\n", fd1);
	
	//close(1);		// 1就是标准输出stdout
	
	
	// 复制文件描述符
	//fd2 = dup(fd1);		// fd2一定等于1,因为前面刚刚关闭了1,这句话就把
	// 1.txt文件和标准输出就绑定起来了,所以以后输出到标准输出的信息就
	// 可以到1.txt中查看了。
	
	fd2 = dup2(fd1, 16);
	printf("fd2 = %d.\n", fd2);
//	printf("this is for test");

	while (1)
	{
		write(fd1, "aa", 2);
		sleep(1);
		write(fd2, "bb", 2);
	}
	close(fd1);
	return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/177029?site
推荐阅读
相关标签
  

闽ICP备14008679号