首页 > 系统相关 >linux之系统调用与文件IO编程

linux之系统调用与文件IO编程

时间:2024-10-26 22:31:39浏览次数:1  
标签:fdw int 编程 char fdr IO linux include buf

linux 之系统调用与文件IO编程

系统调用主要包含以下内容:

  • 文件操作:打开、读取、写入、关闭文件。
  • 目录和文件系统:创建目录、遍历目录、文件属性管理。
  • 进程管理:进程创建、进程终止、信号处理、进程间通信(IPC)。
  • 内存管理:内存映射、共享内存、动态内存分配。
  • 时间管理:时间获取、时间格式化、定时器。

文件I/O和设备编程主要包含以下内容:

  • 标准输入输出、文件描述符和缓冲区。
  • 高级文件I/O:非阻塞I/O、多路复用(select、poll、epoll)。
  • 特殊文件操作:管道、命名管道、socket编程。
  • 设备文件:字符设备、块设备的读取和写入。

常用宏函数:

#define ARGS_CHECK(argc,num) {if(argc != num){fprintf(stderr,"args error!\n");return -1;}}
#define ERROR_CHECK(ret,num,msg) {if(ret == num){perror(msg);return -1;}}

基于文件流的文件操作

文件流的创建与关闭 fopen 函数与 fclose 函数

#include <stdio.h> // 头文件包含
FILE* fopen(const char* path, const char* mode);// 文件名 模式
int fclose(FILE* stream);

读写文件 fread 和 fwrite

外部设备与用户缓存区之间的读写

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);// 写到ptr指向的地址中,每个元素大小, 元素个数, 读取的文件流
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream// 写到ptr指向的地址中,每个元素大小, 元素个数, 读取的文件流

格式化读写:

#include <stdio.h>
int printf(const char *format, ...);
// 相当于fprintf(stdout,format, ...);
int scanf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format,...);
int sprintf(char *str, const char *format, ...);
//eg:sprintf(buf,"the string is;%s",str);
int sscanf(char *str, const char *format, ...);

单个字符读写

#include <stdio.h>
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
int getc(FILE *stream);// 等同于 fgetc(FILE* stream)
int putc(int c, FILE *stream);// 等同于 fputc(int c, FILE* stream)
int getchar(void);// 等同于 fgetc(stdin);从标准输入流中
int putchar(int c);// 等同于 fputc(int c, stdout);从标准输出流中

字符串读写

char *fgets(char *s, int size, FILE *stream);
int fputs(const char *s, FILE *stream);
int puts(const char *s);// 等同于 fputs(const char *s,stdout); 从标准输出流中
char *gets(char *s);// 等同于 fgets(const char *s, int size, stdin);从标准输出流中

文件定位函数:

#include <stdio.h>
int feof(FILE * stream);
// 通常的用法为while(!feof(fp))
int fseek(FILE *stream, long offset, int whence);
// 设置当前读写点到偏移whence 长度为offset处
long ftell(FILE *stream);
// 用来获得文件流当前的读写位置
void rewind(FILE *stream);
//把文件流的读写位置移至文件开头 fseek(fp, 0, SEEK_SET);

二进制文件与文本文件

如果文件当中的内容是一串 ASCII 字符的序列,那么这类文件就是 文本文件。文件类型存储的是字符串,建议使用 fscanf 读取。否则就都是二进制文件,二进制文件写入是什么类型,读取就使用什么类型

目录和文件系统

修改文件权限 chmod

#include <sys/stat.h>
int chmod(const char* path, mode_t mode);
//mode形如:0777 是一个八进制整型
//path参数指定的文件被修改为具有mode参数给出的访问权限。

获取和修改当前工作目录 getcwd,chdir

#include <unistd.h> // 头文件
char *getcwd(char *buf, size_t size); // 获取当前目录,相当于pwd命令
int chdir(const char *path); // 修改当前目录,即切换目录,相当于cd命令

创建和删除空目录 mkdir, rmdir

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int mkdir(const char *pathname, mode_t mode); // 创建目录,mode是目录权限
int rmdir(const char *pathname); // 删除目录

文件目录的存储(目录项)

$ ls -ial
# 查看所有文件的inode信息
$ ln 当前文件 目标
# 建立名为“目标”的硬链接

目录项的结构体

struct dirent{
ino_t d_ino; //该文件的inode
off_t d_off; //到下一个dirent的偏移
unsigned short d_reclen;//文件名长度
unsigned char d_type; //所指的文件类型
char d_name[256]; //文件名
};

目录流的相关操作

#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name); //打开一个目录流
struct dirent *readdir(DIR *dir); //读取目录流当中的一个目录项,
void rewinddir(DIR *dir); //重新定位到目录文件的头部
void seekdir(DIR *dir,off_t offset);//用来设置目录流目前的读取位置
off_t telldir(DIR *dir); //返回目录流当前的读取位置
int closedir(DIR *dir); //关闭目录文件

stat 命令

// man 2 stat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
//结构体stat的定义
struct stat {
dev_t st_dev; /*如果是设备,返回设备表述符,否则为0*/
ino_t st_ino; /* i节点号 */
mode_t st_mode; /* 文件类型 */
nlink_t st_nlink; /* 链接数 */
uid_t st_uid; /* 属主ID */
gid_t st_gid; /* 组ID */
dev_t st_rdev; /* 设备类型*/
off_t st_size; /* 文件大小,字节表示 */
blksize_t st_blksize; /* 块大小*/
blkcnt_t st_blocks; /* 块数 */
time_t st_atime; /* 最后访问时间*/
time_t st_mtime; /* 最后修改时间*/
time_t st_ctime; /* 最后权限修改时间 */
};

实现 ls -al 效果(简化)

Show Code
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
// 
void listFiles(const char* path){
    struct dirent *dirent_p = {0};
    struct stat fileInfo;
    DIR* dirp;
    if((dirp = opendir(path))==NULL){
        perror("opendir");
        exit(EXIT_FAILURE);
    }
    while((dirent_p = readdir(dirp))!=NULL){
        char fullpath[PATH_MAX];
        snprintf(fullpath,sizeof(fullpath),"%s%s%s",path,"/",dirent_p->d_name);
        if(stat(fullpath,&fileInfo)==-1){
            perror("stat");
            exit(EXIT_FAILURE);
        }
        char perm[11];
        switch (fileInfo.st_mode & S_IFMT) {
        case S_IFBLK: perm[0]='b';   break;
        case S_IFCHR: perm[0]='c';   break;
        case S_IFDIR: perm[0]='d';   break;
        case S_IFIFO: perm[0]='p';   break;
        case S_IFLNK: perm[0]='l';   break;
        case S_IFREG: perm[0]='-';   break;
        case S_IFSOCK:perm[0]='s';   break;
        default:      perm[0]='u';   break;
        }
        perm[1] = (fileInfo.st_mode & S_IRUSR)?'r':'-';
        perm[2] = (fileInfo.st_mode & S_IWUSR)?'w':'-';
        perm[3] = (fileInfo.st_mode & S_IXUSR)?'x':'-';
        perm[4] = (fileInfo.st_mode & S_IRGRP)?'r':'-';
        perm[5] = (fileInfo.st_mode & S_IWGRP)?'w':'-';
        perm[6] = (fileInfo.st_mode & S_IXGRP)?'x':'-';
        perm[7] = (fileInfo.st_mode & S_IROTH)?'r':'-';
        perm[8] = (fileInfo.st_mode & S_IWOTH)?'w':'-';
        perm[9] = (fileInfo.st_mode & S_IXOTH)?'x':'-';
        perm[10] = '\0';
        struct passwd* user = getpwuid(fileInfo.st_uid);
        struct group* group = getgrgid(fileInfo.st_gid);
        char timeString[128];
        strftime(timeString,sizeof(timeString),"%b %d %H:%M",localtime(&fileInfo.st_mtime));
        printf("%s %ld %s %s %16ld %s %s\n",
               perm,fileInfo.st_nlink,user->pw_name,group->gr_name,
               fileInfo.st_size,timeString, dirent_p->d_name);
    }
    closedir(dirp);
}
// argc = 1时,显示当前路径目录所有文件状态信息
int main(int argc, char *argv[])
{
    // ./myls dir 
    const char *path = (argc > 1) ? argv[1] : ".";
    listFiles(path);
    return 0;
}
### 实现 tree 命令(简化)
Show Code
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
void listFilesRecursively(const char *basePath, int depth) {
    DIR *dir;
    struct dirent *entry;
    struct stat fileInfo;
    if (!(dir = opendir(basePath))) {
        return;
    }   
    while ((entry = readdir(dir)) != NULL) {
        char path[1024];
        snprintf(path, sizeof(path), "%s/%s", basePath, entry->d_name); //拼接
        if (stat(path, &fileInfo) == -1) {
            continue;
        }      
        if (S_ISDIR(fileInfo.st_mode)) {
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                continue;
            }   
            for (int i = 0; i < depth; i++) {
                printf("  ");
            }   
            printf("|-- %s/\n", entry->d_name);
            listFilesRecursively(path, depth + 1); 
        } else {
            for (int i = 0; i < depth; i++) {
                printf("  ");
            }   
            printf("|-- %s\n", entry->d_name);                 
        }   
    }   
    closedir(dir);
}
int main(int argc, char *argv[]) {
    const char *path = (argc > 1) ? argv[1] : ".";
    printf("%s\n", path);
    listFilesRecursively(path, 0);
    return 0;
}

基于文件描述符的文件操作

文件描述符: 即内核区指针数组下标

open 和 close 函数打开和关闭文件

#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);// 文件名 打开方式 权限
int close(int fd);// fd表示文件描述词,是先前由open或creat创建文件时的返回值。
// 用法:
int fd = open("file",O_RDWR | O_CREAT,0755); // 表示给755的权限

read 和 write 读写文件

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);//文件描述符 缓冲区 缓冲区长度上限
ssize_t write(int fd, const void *buf, size_t count);//文件描述符 缓冲区 内容长度
//ssize_t为有符号大小的整形变量,大小与平台有关

//读写往往提前申请一个缓冲区数组
char buf[1024] = {0};

读写磁盘时不会阻塞,读写外设文件时会发生阻塞

二进制的读写 按什么类型写入,就用什么类型写出

通过读写实现拷贝

int main(int argc, char *argv[])
{
// ./cp src dest
ARGS_CHECK(argc,3);
int fdr = open(argv[1],O_RDONLY);
ERROR_CHECK(fdr,-1,"open fdr");
int fdw = open(argv[2],O_WRONLY|O_TRUNC|O_CREAT,0666);
ERROR_CHECK(fdw,-1,"open fdw");
//char buf[4096] = {0};
char buf[4096000] = {0};
// buf选择char数组,不是字符串的含义,而是因为char的字节是1
while(1){
memset(buf,0,sizeof(buf));
ssize_t sret = read(fdr,buf,sizeof(buf));
ERROR_CHECK(sret,-1,"read");
// 读取磁盘文件,返回值为0,则读完
if(sret == 0){
break;
}
// 写入dest
write(fdw,buf,sret);
}
close(fdr);
close(fdw);
return 0;
}

文件偏移 lseek

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);//fd文件描述词
//whence 可以是下面三个常量的一个
//SEEK_SET 从文件头开始计算
//SEEK_CUR 从当前指针开始计算
//SEEK_END 从文件尾开始计算

文件截断 ftruncate

#include <unistd.h>
int ftruncate(int fd, off_t length);
//可以形成文件空洞

文件映射 mmap

#include <sys/mman.h>
void *mmap(void *adr, size_t len, int prot, int flag, int fd, off_t off);
//常见使用步骤
//1open
int fd = open(argv[1], O_RDWR);
//2ftruncate
int ftr = ftruncate(fd, 5);
//3mmap
char *p = (char *)mmap(NULL,5,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
ERROR_CHECK(p,MAP_FAILED,"mmap");//mmap失败返回不是NULL
for(int i = 0; i < 5; ++i){
printf("%c", *(p+i));
}
printf("\n");
*(p+4) = 'O';
//4munmap
munmap(p,5);
close(fd)

文件流与文件描述符关系 fileno

int fileno(FILE* stream)//相当于接口
//输入一个文件流指针,返回一个文件描述符常常嵌套在函数中使用
write(fileno(fp),"hello",5);

标准输入输出流与重定向

可以通过改变文件描述符所对应的文件对象实现重定向

//常用重定向函数
#include <unistd.h>
int dup(int oldfd); //返回值为新的文件标识符
int dup2(int oldfd, int newfd);//使新的文件标识符指向旧标识符指向的对象
//多个描述符指向同一个文件对象,即共享机制

管道

$ mkfifo [管道名字]
使用cat打开管道可以打开管道的读端
$ cat [管道名字]
打开另一个终端,向管道当中输入内容可以实现写入内容
$ echo “string” > [管道名字]
此时读端也会显示内容
 //管道的打开与关闭与文件的打开关闭一致使用open/close,linux下管道也是文件
    
//若管道的写端先关闭,则之后管道的读端执行 read 操作时会立刻返回,且返回值为0;
//若管道的读端先关闭,则之后管道的写端执行 write 操作时会触发SIGPIPE信号,导致进程异常终止。

I/O 多路复用模型

简陋的即时聊天代码

//1号
int main(int argc, char *argv[])
{
ARGS_CHECK(argc,3);
int fdr = open(argv[1],O_RDONLY);//管道打开的时候,必须要先将读写端都打开之后才能继续
int fdw = open(argv[2],O_WRONLY);
printf("I am chat1\n");
char buf[128] = {0};
while(1)
{
memset(buf,0,sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
write(fdw, buf, strlen(buf)-1);
memset(buf,0,sizeof(buf));
read(fdr, buf, sizeof(buf));
printf("buf = %s\n", buf);
}
return 0;
}
//2号
int main(int argc, char *argv[])
{
ARGS_CHECK(argc,3);
int fdw = open(argv[1],O_WRONLY);//管道打开的时候,必须要先将读写端都打开之后才能继续
int fdr = open(argv[2],O_RDONLY);
printf("I am chat2\n");
char buf[128] = {0};
while(1)
{
memset(buf,0,sizeof(buf));
read(fdr, buf, sizeof(buf));
printf("buf = %s\n", buf);
memset(buf,0,sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
write(fdw, buf, strlen(buf)-1);
}
return 0;
}

缺点:stdin 和 read 会相互阻塞

I/0 多路复用模型与 select

#include <sys/select.h>
#include <sys/time.h>
//readset、writeset、exceptionset都是fd_set集合
//集合的相关操作如下:
void FD_ZERO(fd_set *fdset); /* 将所有fd清零 */
void FD_SET(int fd, fd_set *fdset); /* 增加一个fd */
void FD_CLR(int fd, fd_set *fdset); /* 删除一个fd */
int FD_ISSET(int fd, fd_set *fdset); /* 判断一个fd是否有设置 */
int select(int maxfd, fd_set *readset,fd_set *writeset, fd_set *exceptionset,
struct timeval * timeout);

实现简单的即时聊天,说话时打印时间:

//思路:每次说话时调用ctime打印当前时间,再用字符串拼接
#include <54func.h>
int main(int argc, char *argv[])
{
    // ./0_aqiang  1.pipe 2.pipe
    ARGS_CHECK(argc,3);
    int fdr = open(argv[1],O_RDONLY);
    ERROR_CHECK(fdr,-1,"open read");
    int fdw = open(argv[2],O_WRONLY);
    ERROR_CHECK(fdw,-1,"open write");
    printf("aqiang is connected!\n");
    char buf[4096];
    fd_set rdset; // 为fd_set申请内存
    while(1){
        // select之前需要重置监听集合
        FD_ZERO(&rdset); // fd_set 开始是监听集合
        FD_SET(STDIN_FILENO,&rdset);
        FD_SET(fdr,&rdset); //把fdr 和 stdin 加入监听
        select(fdr+1,&rdset,NULL,NULL,NULL);
        // select返回,说明fdr or stdin就绪了 rdset现在是就绪集合
        if(FD_ISSET(fdr,&rdset)){
            // 管道就绪 读取阿珍的消息
            memset(buf,0,sizeof(buf));
            ssize_t sret =read(fdr,buf,sizeof(buf));
            if(sret == 0){
                printf("Hehe\n");
                break;
            }
            printf("buf = %s\n", buf);
        }
        if(FD_ISSET(STDIN_FILENO,&rdset)){
            // 读取stdin的数据
            memset(buf,0,sizeof(buf));
            ssize_t sret = read(STDIN_FILENO,buf,sizeof(buf));
            if(sret == 0){
                write(fdw,"nishigehaoren",13);
                break;
            }
            time_t now = time(NULL);
            char *p = ctime(&now);
            char newbuf[8192] = {0};
            sprintf(newbuf,"%s %s",p,buf);
            write(fdw,newbuf,strlen(newbuf));
        }
    }
    return 0;
}

select 的超时处理 timeout

struct timeval
{
long tv_sec;//秒
long tv_usec;//微秒
};
//用法
...
struct timeval timeout;
while(1)
{
bzero(&timeout, sizeof(timeout));
timeout.tv_sec = 3;
ret = select(fdr+1, &rdset, NULL, NULL, &timeout);
if(ret > 0)
{
...
}
else
{
printf("time out!\n");
}
}

聊天做一个 10s 的超时处理:

server.c
//思路:创建两个变量一个记录当前时间一个记录对方的最后活跃时间(每当select返回时更新当前时间,当管道就绪时更新对方活跃时间),在循环的最后判断两者相减是否>= 10,满足则退出循环。
#include <myfunc.h>
int main(int argc, char *argv[])
{
    // ./server 1.pipe 2.pipe
    ARGS_CHECK(argc,3);
    int fdw = open(argv[1],O_WRONLY);
    ERROR_CHECK(fdw,-1,"open write");
    int fdr = open(argv[2],O_RDONLY);
    ERROR_CHECK(fdr,-1,"open read");
    printf("server is connected!\n");
    char buf[4096];
    fd_set rdset; // 为fd_set申请内存
    time_t curTime;
    time_t lastActive = time(NULL);
    while(1){
        // select之前需要重置监听集合
        FD_ZERO(&rdset); // fd_set 开始是监听集合
        FD_SET(STDIN_FILENO,&rdset);
        FD_SET(fdr,&rdset); //把fdr 和 stdin 加入监听
        struct timeval timeout;
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        int ret = select(fdr+1,&rdset,NULL,NULL,&timeout);
        ERROR_CHECK(ret,-1,"select");
        curTime = time(NULL); // 更新当前时间
        printf("curTime = %s\n", ctime(&curTime));
        // select返回,说明fdr or stdin就绪了 rdset现在是就绪集合
        if(FD_ISSET(fdr,&rdset)){
            // 管道就绪 读取客户端的消息
            // 更新客户端的lastActive
            lastActive = time(NULL);
            memset(buf,0,sizeof(buf));
            ssize_t sret =read(fdr,buf,sizeof(buf));
            if(sret == 0){
                printf("client leave\n");
                break;
            }
            printf("buf = %s\n", buf);
        }
        if(FD_ISSET(STDIN_FILENO,&rdset)){
            // 读取stdin的数据
            memset(buf,0,sizeof(buf));
            ssize_t sret = read(STDIN_FILENO,buf,sizeof(buf));
            if(sret == 0){
                write(fdw,"server stopped\n",15);
                break;
            }
            time_t now = time(NULL);
            char *p = ctime(&now);
            char newbuf[8192] = {0};
            sprintf(newbuf,"%s %s",p,buf);
            write(fdw,newbuf,strlen(newbuf));
        }
        if(curTime - lastActive >= 10){
            printf("client offline!\n");
            break;
        }
    }
    close(fdr);
    close(fdw);
    return 0;
}
client.c
#include <myfunc.h>
int main(int argc, char *argv[])
{
    // ./client 1.pipe 2.pipe
    ARGS_CHECK(argc,3);
    int fdr = open(argv[1],O_RDONLY);
    ERROR_CHECK(fdr,-1,"open read");
    int fdw = open(argv[2],O_WRONLY);
    ERROR_CHECK(fdw,-1,"open write");
    printf("client is connected!\n");
    char buf[4096]={0};
    fd_set rfds;
    while(1){
        FD_ZERO(&rfds);
        FD_SET(STDIN_FILENO,&rfds);
        FD_SET(fdr,&rfds);
        int cnt = select(fdr+1,&rfds,NULL,NULL,NULL);
        ERROR_CHECK(cnt,-1,"select");
        if(FD_ISSET(STDIN_FILENO,&rfds)){
            memset(buf,0,sizeof(buf));
            ssize_t sret = read(STDIN_FILENO,buf,sizeof(buf));
            if(sret == 0){
                write(fdw,"client leave!\n",14);
                break;
            }
            time_t now = time(NULL);
            char *p = ctime(&now);
            char newbuf[8192]={0};
            sprintf(newbuf,"%s %s",p,buf);
            write(fdw,newbuf,strlen(newbuf));
        }
        if(FD_ISSET(fdr,&rfds)){
            memset(buf,0,sizeof(buf));
            ssize_t sret = read(fdr,buf,sizeof(buf));
            if(sret == 0){
                printf("server stopped!\n");
                break;
            }
            printf("buf = %s\n",buf);
        }
    }
    close(fdr);
    close(fdw);
    return 0;
}

写集合的原理(写阻塞: 当数据在读缓存区与暂存区都满时,写缓冲区有数据时写便会阻塞)

实现一个进程在管道一直读写观察写阻塞:

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fdr = open(argv[1],O_RDWR);
    //非阻塞方式open管道的一端
    int fdw = open(argv[1],O_RDWR);//可以一次性打开管道的读写端
    fd_set rdset,wrset;
    int cnt = 0;
    char buf[4096] = {0};
    while(1)
    {
        FD_ZERO(&rdset);
        FD_ZERO(&wrset);
        FD_SET(fdr, &rdset);
        FD_SET(fdw, &wrset);
        int  ret  = select(fdw+1, &rdset, &wrset, NULL, NULL);
        if(FD_ISSET(fdr, &rdset))
        {
            printf("read ready, cnt = %d, ret = %d\n",cnt++,ret);
            read(fdr, buf, 2048);
        }
        if(FD_ISSET(fdw, &wrset))
        {
            printf("write ready, cnt = %d, ret = %d\n",cnt++,ret);
            write(fdw,buf,4096);
        }
        sleep(1);
    }
}

小火车协议

编写程序 A 和 B。A 负责将文件的名字、长度和内容通过管道发送 B,B 需要新建一个目录,并将该文件存储起来。

//程序A
#include <54func.h>
typedef struct train_s {
    int length;
    char data[1000];
} train_t;
int main(int argc, char *argv[])
{
    // ./2_A 1.pipe file
    ARGS_CHECK(argc,3);
    int fdw_pipe = open(argv[1],O_WRONLY);
    ERROR_CHECK(fdw_pipe,-1,"open");
    
    train_t train;
    train.length = strlen(argv[2]);
    memcpy(train.data,argv[2],train.length);
    // 发送文件名
    write(fdw_pipe,&train.length,sizeof(train.length));
    write(fdw_pipe,train.data,train.length);

    // 发送文件内容
    int fdr_file = open(argv[2],O_RDONLY);
    ERROR_CHECK(fdr_file,-1,"open");
    ssize_t sret = read(fdr_file,train.data,sizeof(train.data));
    train.length = sret;
    write(fdw_pipe,&train.length,sizeof(train.length));
    write(fdw_pipe,train.data,train.length);

    close(fdr_file);
    close(fdw_pipe);
    return 0;
}

//程序B
#include <54func.h>
typedef struct train_s {
    int length;
    char data[1000];
} train_t;
int main(int argc, char *argv[])
{
    // ./2_B 1.pipe
    ARGS_CHECK(argc,2);
    int fdr_pipe = open(argv[1],O_RDONLY);
    ERROR_CHECK(fdr_pipe,-1,"open");

    train_t train;
    read(fdr_pipe,&train.length,sizeof(train.length));
    read(fdr_pipe,train.data,train.length);
    char filename[4096] = {0};
    memcpy(filename,train.data,train.length);
    char path[8192] = {0};
    char dir[] = "dir1/";
    mkdir(dir,0777);
    sprintf(path,"%s%s%s",dir,"/",filename);
    int fdw_file = open(path,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(fdw_file,-1,"open");
    read(fdr_pipe,&train.length,sizeof(train.length));
    read(fdr_pipe,train.data,train.length);
    write(fdw_file,train.data,train.length);
    
    close(fdw_file);
    close(fdr_pipe);
    return 0;
}

标签:fdw,int,编程,char,fdr,IO,linux,include,buf
From: https://www.cnblogs.com/Invinc-Z/p/18504812

相关文章

  • redis高级篇之IO多路复用select方法简介 第174节答疑
    1、bitmap最大1024位,一个进程最多只能处理1024个客户端2、&rset不可重用,每次socket有数据就相应的位会被置位3、文件描述符数组拷贝到了内核态(只不过无系统调用切换上下文的开销。(内核层可优化为异步事件通知)),仍然有开销。select调用需要传入fd数组,需要拷贝一份到内核,高......
  • redis高级篇之IO多路复用IOMultiplexing从学术到人话版 172节答疑
    ref:selectRecieve.png这图什么意思,select是阻塞的,然后呢?这张图展示了I/O复用模式下的工作流程,特别是使用`select`系统调用进行I/O复用的情况。在这种模式下,`select`用于监听多个文件描述符(如套接字),等待其中任何一个变为可读、可写或有异常发生。以下是图中各部分的详......
  • linux学习day1
    1.常见命令介绍(1)ctrlc:取消命令,并且换行(2)ctrlu:清空本行命令(3)tab键:可以补全命令和文件名,如果补全不了快速按两下tab键,可以显示备选选项(4)ls:列出当前目录下所有文件,蓝色的是文件夹,白色的是普通文件,绿色的是可执行文件(5)pwd:显示当前路径(6)cdXXX:进入......
  • 第六届国际科技创新学术交流大会 暨通信、信息系统和软件工程学术会议(CISSE 2024)
    @目录一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题一、会议详情二、重要信息大会官网:https://ais.cn/u/vEbMBz提交检索:EICompendex、IEEEXplore、Scopus大会时间:2024年12月6-8日大会地点:中国-广州三、大会介绍通信、信息系统与软件工程学术会议(CI......
  • 第六届智能控制、测量与信号处理国际学术会议 (ICMSP 2024) 2024 6th International
    @目录一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题一、会议详情二、重要信息大会官网:https://ais.cn/u/vEbMBz提交检索:EICompendex、IEEEXplore、Scopus三、大会介绍第六届智能控制、测量与信号处理国际学术会议(ICMSP2024)由西安石油大学、中海油田......
  • Python 潮流周刊#74:创下吉尼斯世界记录的 Python 编程课(摘要)
    本周刊由Python猫出品,精心筛选国内外的250+信息源,为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景:帮助所有读者精进Python技术,并增长职业和副业的收入。本期分享了12篇文章,12个开源项目,2则音视频,全文2300字。好消息:即日起至......
  • CLion中使用add_subdirectory()模块化管理Stm32项目
    背景文章目录背景配置参考源码在Clion中使用STM32的时候,通常把自己开发的内容写在User目录中,然而需要将User目录下的源文件和头文件都添加到生成的CMakeLits.txt中。对于不同风格的库,直接在生成的CMakeLists.txt中添加资源会显得有些乱,可以使用cmake的**子目录(s......
  • uni-app 扫码插件推荐:基于支付宝 mPaaS 扫码组件开发,支持 Android 和 iOS
    一.前言之前说到,我的一个uni-app项目遭到用户吐槽:“你们这个App扫码的正确率太低了,尤其是安卓的设备。经常性的扫码扫不出来,就算是扫出来了,也是错误的结果!”面对以上这个问题,我在当时的项目是使用了一个基于安卓原生zxing扫码插件实现的,虽然扫码效率可观,但是它也有一......
  • 0-petalinux2018.3 摸索记录 - 快速亮机
    一、环境搭建1、环境要求①需要注意petalinux、vivado、vitis、linux之间的版本对应关系,在ug1144上可以找到②需要注意linux的硬件要求,运存8G以上不然会报错等等2、环境依赖配置2018.3_PetaLinux_Package_List.xlsx①安装包sudoapt-getinstalltofrodos......
  • axios delete请求如何发给springboot
    1、发送请求体时前端axios的delete和post/put在传值上有点区别post和put有三个参数,url,data和config,所以在使用这两个时,可以写成axios.post(api,{ id:1});axios.put(api,{ id:1});第二个参数{id:1}会传给data。但是delete只有两个参数:url和config,data在config中,所以需......