Linux默认文件描述符个数为 1024
可用命令查看
ulimit -n
前三个默认已占用
// stdin
#define STDIN_FILENO 0;
// stdout
#define STDOUT_FILENO 1;
// stderr
#define STDERR_FILENO 2;
/**
* @author IYATT-yx
* @brief 读取一个文件,并写入另外一个文件(不存在则创建)
*/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char **argv)
{
if (argc != 3)
{
printf("请指定两个参数,分别为 [源文件] [目标文件]\n");
return -1;
}
// 打开源文件,若执行失败,open内部会设置 errno 值,并返回 -1
// perrno根据 errno 的值,输出对应错误信息
int fdRead = open(argv[1], O_RDONLY);
if (fdRead == -1)
{
perror("read file");
return -1;
}
// 打开或不存在就创建将要写入的目标文件
// 指定生成的文件权限为 0664 ,实际文件的权限为 0664 & ~umask
int fdWrite = open(argv[2], O_WRONLY | O_CREAT, 0664);
if (fdWrite == -1)
{
perror("write file");
return -1;
}
char buf[4096];
ssize_t len;
// 从文件描述符 fdRead 读取 buf 容量大小的数据到 buf 中, 返回值为实际读取的数据长度, 返回 0 读完,返回 -1 失败
while ((len = read(fdRead, buf, sizeof(buf))) > 0)
{
// 将 buf 中 len 长度的数据写入 fdWrite 文件描述符对应打开的文件, 返回 -1 代表失败!
ssize_t ret = write(fdWrite, buf, (size_t)len);
if (ret == -1)
{
perror("write");
return -1;
}
}
// 关闭文件描述符
close(fdRead);
close(fdWrite);
}
移动 文件指针 到头部
lseek(fd, 0, SEEK_SET);
获取文件指针当前位置
off_t idx = lseek(fd, 0, SEEK_CUR);
获取文件长度
off_t len = lseek(fd, 0. SEEK_END);
文件拓展 (比如可以在开始下载时,创建一个空白文件,并根据要下载的文件大小来拓展本地下载文件为相同的大小来占位,下载时再依次从头开始替换拓展填充的数据)
// 拓展 1KB 大小
off_t size = 1024;
lseek(fd, size, SEEK_END);
// 拓展后进行write才有效,写入内容任意,比如这里以空格结尾
const char *str = " ";
write(fd, str, 1);
/**
* @author IYATT-yx
* @brief 阻塞读终端
*/
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char buf[5];
ssize_t len = read(STDIN_FILENO, buf, 5);
if (len == -1)
{
perror("open STDIN_FILENO");
return -1;
}
write(STDOUT_FILENO, buf, (size_t)len);
}
编译执行这个程序后,终端会等待用户输入,并一直停在read函数处,直到输入内容按下回车,将输入内容的前五个(不足5个字符则为实际输入个数)读入buf,下一步执行write将buf的内容打印输出到终端.
当输入的字符在read设定的5个之内时可能没有异样,但是如果输入的数据超过5个,可能会看到另一番现象.前面5个字符会被正常输出,后面的字符会在命令提示符后显示,并被当作命令执行.而这种现象的原因:当执行这里的程序时,程序作为前台,终端切换到后台,而这个程序只获取前5个字符,并将获取到的字符输出,完成以后程序结束,终端切为前台,并将执行程序时输入超出的字符接受,同时执行.
/**
* @author IYATT-yx
* @brief 非阻塞读终端
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdbool.h>
#include <errno.h>
int main(void)
{
int fdRead = open("/dev/tty", O_RDONLY | O_NONBLOCK);
if (fdRead == -1)
{
perror("open /dev/tty");
return -1;
}
char buf[4];
ssize_t len;
while (true)
{
len = read(fdRead, buf, sizeof(buf));
if (len == -1)
{
if (errno == EAGAIN)
{
printf("请重试!\n");
sleep(3);
continue;
}
perror("read /dev/tty");
return -1;
}
write(STDOUT_FILENO, buf, (size_t)len);
close(fdRead);
return 0;
}
}
在非阻塞读终端时,在没有输入的情况下, 不会一直停在read处等待输入而是继续执行下去.
ps:
普通文件的属性默认不阻塞
终端设备,管道,套接字文件默认阻塞
复制文件描述符:
dup
函数: 返回新的文件描述符(最小的未被占用的)也指向原文件描述符指向的文件
dup2
函数: 可以自己指定新的文件描述符指向原文件描述符指向的文件