1、文件相关系统调用接口open/read/write/close的实现,fd与FILE结构体 的纵向对比
1.1、open函数介绍:用于打开一个指定文件
1.1.2、函数原型:int open(const char *pathname, int flags);
1.1.3、参数及返回值说明:
pathname 文件名
* flags 选项标志 O_RDWR | O_CREAT | O_TRUNC | O_APPEND
* 只能选其一/也必选其一
* O_RDONLY 只读
* O_WRONLY 只写
* O_RDWR 读写
* 可选:
* O_CREAT 文件不存在则创建,存在则打开
* O_TRUNC 打开文件的时候清空原有内容
* O_APPEND 写数据的时候总是追加在文件末尾
* mode 文件权限
* S_IWUSR | S_IXUSR|S_IRWXG.........
* 0664
* 返回值:文件描述符(正整数) 失败:-1
1.2、read函数介绍:读取指定文件
1.2.1、函数原型:ssize_t read(int fd, void *buf, size_t count);
1.2.2‘参数及返回值说明:
* ssize_t read(int fd, void *buf, size_t count);
* fd 文件描述符
* buf 定义的缓冲区
* count 要读取的数据字节数
*返回值:成功返回读取到字节数 失败:-1
1.3、write函数介绍 :往指定文件中写入数据
1.3.1、函数原型: ssize_t write(int fd, const void *buf, size_t count);
1.3.2、参数及返回值说明:
* fd 文件描述符
* buf 写入的内容
* count 写入的字节数
*返回值:成功时返回写入的字节数 失败:-1
1.4、close函数介绍:关闭指定文件
1.4.1、函数原型:int close(int fd);
1.4.2、参数及返回值说明:
* fd 指定文件描述符
* 返回值:成功:0 失败:-1
1.5、实现代码:
/**********************************************************
* Author : WangWei
* Email : 872408568@qq.com
* Last modified : 2019-04-28 16:50:59
* Filename : open.c
* Description :文件相关系统调用接口open/read/write/close的实现
* int open(const char *pathname, int flags); 打开指定文件
* pathname 文件名
* flags 选项标志 O_RDWR | O_CREAT | O_TRUNC | O_APPEND
* 只能选其一/也必选其一
* O_RDONLY 只读
* O_WRONLY 只写
* O_RDWR 读写
* 可选:
* O_CREAT 文件不存在则创建,存在则打开
* O_TRUNC 打开文件的时候清空原有内容
* O_APPEND 写数据的时候总是追加在文件末尾
* mode 文件权限
* S_IWUSR | S_IXUSR|S_IRWXG.........
* 0664
* 返回值:文件描述符(正整数) 失败:-1
*
* ssize_t read(int fd, void *buf, size_t count); 读取指定文件
* fd 文件描述符
* buf 定义的缓冲区
* count 要读取的数据字节数
*返回值:成功返回读取到字节数 失败:-1
* ssize_t write(int fd, const void *buf, size_t count); 往指定文件中写入数据
* fd 文件描述符
* buf 写入的内容
* count 写入的字节数
*返回值:成功时返回写入的字节数 失败:-1
* int close(int fd); 关闭指定文件
* fd 指定文件描述符
* 返回值:成功:0 失败:-1
* *******************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
char* file = "1.txt";
// int open(const char *pathname, int flags, mode_t mode)
umask(0); // 设置默认权限掩码
int fd = open(file , O_RDWR | O_CREAT , 0664);
if(fd < 0) {
perror("open error");
return -1;
}
// ssize_t write(int fd, const void *buf, size_t count);
char buf[1024] = "hello bit !";
int ret = write(fd, buf , 1024);
if(ret < 0) {
perror("write error");
return -1;
}
// off_t lseek(int fd, off_t offset, int whence); 重新定位读/写文件偏移量
// fd: 打开文件返回的操作句柄--文件描述符
// offset: 偏移量
// whence:偏移起始位置
// SEEK_SET
// SEEK_CUR
// SEEK_END
// 返回值:偏移的位置到文件起始位置的偏移量
lseek(fd, 0, SEEK_SET);
memset(buf,0x00,1024);
// ssize_t read(int fd, void *buf, size_t count);
ret = read(fd, buf, 1023);
if(ret < 0) {
perror("read error");
return -1;
}
else if(ret == 0) {
printf("have no date \n");
return -1;
}
printf("buf:%d %s \n",ret,buf);
close(fd);
return 0;
}
1.6、fd与FILE结构体 的纵向对比
(1)fd属于系统库 , FILE属于c标准库;
(2)fd是一个整数,FILE是一个结构体.
2、使minishell支持输入/输出/追加重定向
/**********************************************************
* Author : WangWei
* Email : 872408568@qq.com
* Last modified : 2019-04-28 21:00:40
* Filename : shell.c
* Description : 使minishell支持输入/输出/追加重定向
* minishell实现步骤:
* 1、获取标准输入
* 2、解析得到的字符串
* 3、创建子进程,进行程序替换
* 4、父进程进行进程等待
* *******************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
int main()
{
char buf[1024] = {0};
while(1) {
printf("[user@locahost]$");
fflush(stdout);
memset(buf,0x00,1024);
if(scanf("%[^\n]%*c",buf) != 1) {
// ^表示"非",[^\n]表示读入换行字符就结束读入。这个是scanf的正则用法,我们都知道scanf不能接收空格符,但是使用%[^\n]就可以了。
// *表示该输入项读入后不赋予任何变量,即scanf("%*[^\n]%*c")表示跳过一行字符串。
getchar();
continue;
}
// 创建子进程
int pid = fork();
if(pid < 0) {
perror("fork error");
return -1;
}
else if(pid == 0){
char *str = buf;
int count = 0; // 重定向符号个数
char *file = NULL;
int fd = 0;
// 找重定向个数
while(*str != '\0') {
if(*str == '>') {
count++;
*str = '\0';
if(*(str + 1) == '>') {
count++;
}
str += count;
while(*str != '\0' && !isspace(*str)) {
*str++ = '\0';
}
file = str;
// 走完文件
while(*str != '\0' && !isspace(*str)) {
str++;
}
*str = '\0';
continue;
}
str++;
}
if(count == 1) {
fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0664);
// int dup2(int fd1, int fd2)
// 用dup2则可以用fd2参数指定新的描述符数值。
// 如果fd2已经打开,则先关闭。若fd1=fd2,则dup2返回fd2,而不关闭它。
dup2(fd,1);
}
else if(count == 2) {
fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0664);
dup2(fd,1);
}
// 解析外部命令
char *ptr = buf;
char *argv[64];
int argc = 0;
while(*ptr != '\0') {
if(!isspace(*ptr)) {
argv[argc++] = ptr;
while(*ptr != '\0' && !isspace(*ptr)) {
ptr++;
}
}
*ptr = '\0';
ptr++;
}
argv[argc] = NULL;
//子进程进行程序替换
// int execvp(const char *file ,char * const argv []);
// execvp()会从PATH 环境变量所指的目录中查找符合参数file 的文件名,
// 找到后便执行该文件,然后将第二个参数argv传给该欲执行的文件。
execvp(argv[0], argv);
exit(0);
}
waitpid(pid, NULL, 0);
}
printf("Hello world\n");
return 0;
}
3、编写简单的add/sub/mul/div函数,并打包成动/静态库,并分别使用。
静态库:
生成静态库:
① gcc -c a.c -o a.o
② ar -rc libmytest.a a.o b.o
③ gcc main.c libmytest.a 将所有目标代码链接起来生成静态库 -c 创建 -r 模块替换
//gcc main.c -lmytest
(标准版测试运行:gcc main.c -L . -lmytest)
动态库 (共享库):
生成动态库:
gcc -FPIC -shared -o libmytestso a.c
(其中 -FPIC 产生未知无关代码)
add.c
/**********************************************************
* Author : WangWei
* Email : 872408568@qq.com
* Last modified : 2019-04-29 20:56:49
* Filename : add.c
* Description :
* *******************************************************/
#include "add.h"
int add(int a, int b) {
return a + b;
}
add.h
/**********************************************************
* Author : WangWei
* Email : 872408568@qq.com
* Last modified : 2019-04-29 20:56:49
* Filename : add.h
* Description :
* *******************************************************/
#ifndef _ADD_H
#define _ADD_H
int add(int a, int b);
#endif
sub.h
/**********************************************************
* Author : WangWei
* Email : 872408568@qq.com
* Last modified : 2019-04-29 21:04:10
* Filename : sub.c
* Description :
* *******************************************************/
#include "sub.h"
int sub(int a, int b) {
return a - b ;
}
sub.h
#ifndef _SUB_H
#define _SUB_H
int sub(int a, int b);
#endif
mul.c
#include "mul.h"
int mul(int a, int b) {
return a * b;
}
mul.h
#ifndef _MUL_H
#define _MUL_H
int mul(int a, int b);
#endif
div.c
/**********************************************************
* Author : WangWei
* Email : 872408568@qq.com
* Last modified : 2019-04-29 21:08:23
* Filename : div.c
* Description :
* *******************************************************/
#include "div.h"
int div(int a, int b) {
return a / b;
}
div.h
#ifndef _DIV_H
#define _DIV_H
int div(int a, int b);
#endif
main.c
/**********************************************************
* Author : WangWei
* Email : 872408568@qq.com
* Last modified : 2019-04-29 21:10:19
* Filename : main.c
* Description :
* *******************************************************/
#include <stdio.h>
#include "add.h"
#include "sub.h"
#include "mul.h"
#include "div.h"
int main()
{
int a;
int b;
printf("请输入两个整数:");
scanf("%d %d", &a, &b);
printf("[add]:%d \n",add(a, b));
printf("[sub]:%d \n",sub(a, b));
printf("[mul]:%d \n",mul(a, b));
printf("[div]:%d \n",div(a, b));
return 0;
}