【Linux】文件操作函数-cat命令-cp命令简单仿写
文章目录(一)库函数、系统调用(1)C语言文件操作库函数(2)Linux系统调用(二)用户态和内核态相关知识(三)系统调用的使用测试(一)库函数、系统调用库函数:在函数库实现中、在用户空间调用执行(1)C语言文件操作库函数FILE* fopen(const char* pathname, const char* mode); // mode "r"int fread(void* buff, siz
·
文章目录
(一)库函数、系统调用
库函数:在函数库实现中、在用户空间调用执行
(1)C语言文件操作库函数
FILE* fopen(const char* pathname, const char* mode); // mode "r"
int fread(void* buff, size_t size, size_t count, FILE* fp);
fwrite(void* buff, size_t size, size_t count, FILE* fp);
fseek(FILE* fp, int offset, int whence); //移动读写游标
// whence : SEEK_SET SEEK_CUR SEEK_END
fclose(FILE* fp);
(2)Linux系统调用
在系统内核中实现,用户空间调用,内核空间执行
1.int open(const char* pathname, int flag);
int open(const char *pathname, int flags, mode_t mode);
参数详解:
- pathname:路径文件名
- flags:打开方式 O_RDONLY(只读)O_WRONLY(只写)O_RDWR(读写)O_APPEND(文本尾部追加打开) O_TRUNC(pathname文件存在,清空该文件,没有则创建)
- O_CREAT: 若此文件不存在则创建它。使用此选项时需要提供第三个参数mode ,表示该文件
的访问权限。- 返回值
失败-1,并设置全局erron
成功返回文件描述符
2.int read(int fd, void* buff, size_t size);
参数详解:
- fd:打开的文件描述符
- buff:保存数据的buff缓冲区的首地址
- size:一次读取的最大字节数(sizeof(buff) - 1)
- 返回值:
失败 -1
读取到的字节个数
3.int write(int fd, void* buff, size_t size);
- fd:文件描述符
- buff:写入文件的缓冲区的首地址
- size:buff中的真实数据大小
- 返回值:
失败 -1
成功:写入的字节个数
4.lseek(int fd, int offset, int whence);
- fd:文件描述符
- offset:标志偏移量
- whence: SEEK_SET SEEK_CUR SEEK_END
- 返回值:
成功:将结果偏移位置返回为从文件开头开始以字节为单位测量
失败 -1 errno被设置为指示错误
5.int close(int fd);
关闭文件描述符
(二)用户态和内核态相关知识
(三)系统调用的使用测试
从键盘获取,保存在mydata.txt文件中
#include <stdio.h> //标准输入输出文件
#include <fcntl.h> //系统调用头文件
#include <unistd.h>
#include <string.h>
void KeyIntoFile()
{
int fd = open("mydata.txt", O_WRONLY |O_CREAT | O_TRUNC, 0664);
if(fd == -1)
return;
printf("input data:\n");
while(1)
{
char buff[128] = {0};
fgets(buff, 127, stdin);
if(strncmp(buff, "end", 3) == 0)
{
break;
}
write(fd, buff, strlen(buff));
}
close(fd);
printf("saved\n");
}
int main()
{
KeyIntoFile();
return 0;
}
测试结果:
(四)实现cat的显示文件内容的功能
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
void Mycat(int argc, char* argv[])
{
if(argc != 2)
{
perror("argc error");
return;
}
char filename[128] = {0};
sprintf(filename, "%s", argv[1]);
int fd = open(filename, O_RDONLY);
if(fd == -1)
{
perror("file not exist");
return;
}
while(1)
{
memset(filename, 0, sizeof(filename));
int count = read(fd, filename, 127);
if(count == -1)
{
perror("read error");
break;
}
if(count == 0)
{
break;
}
printf("%s", filename);
}
close(fd);
}
int main(int argc, char* argv[])
{
Mycat(argc, argv);
return 0;
}
测试结果:
(五)系统调用实现cp命令
cp pathname1 pathname2
将pathname1文件拷贝到pathname2下
我们简单使用了下cp命令,结果如下
需要额外知识:
文件夹相关操作
开始仿写:
(1)mycp.h文件
#ifndef MYCP_H
#define MYCP_H
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
//cp命令
void Mycp(int argc, char* argv[]);
//-1文件名空, 0不是文件夹,1是文件夹
//检查是否为目录
int CheckIsDir(const char* path);
//-1路径为空 1绝对路径 2相对路径
//判断是否为合法路径、绝对或者相对路径;
int CheckPath(const char* path);
//拷贝数据
void CopyData(const char* path_src, const char* path_des);
//获取源文件名+拼接在目标路径后
char* getNewPath_des(const char* path_src, const char* path_des);
#endif
(2)mycp.c文件
#include "mycp.h"
//cp命令
void Mycp(int argc, char* argv[])
{
if(argc != 3)
{
printf("argc is err\n");
return;
}
//检查是绝对路径还是相对路径
int ret_pathsrc = CheckPath(argv[1]);
int ret_pathdes = CheckPath(argv[2]);
//判断是文件夹还是普通文件
int type_src = CheckIsDir(argv[1]);
int type_des = CheckIsDir(argv[2]);
if(type_src == 0 || type_src == -1)
{
printf("%s不是合法的文件或文件夹\n", argv[1]);
return;
}
/*给定目标文件名
src:绝对路径或相对路径/src普通文件名
des:绝对路径或相对路径/des普通文件名(新文件名)
*/
if(type_src == 2 && (type_des == 2 || type_des == -1)) //
{
CopyData(argv[1], argv[2]);
return;
}
/*未给定目标文件名(需要拼接目标文件名)
src:绝对路径或相对路径/src普通文件名
des:绝对路径或相对路径/文件夹
*/
if(type_src == 2 && type_des == 1)
{
//获取源文件名+拼接在目标路径后
char* newpath_des = getNewPath_des(argv[1], argv[2]);
if(newpath_des == NULL)
return;
CopyData(argv[1], newpath_des);
free(newpath_des);
return;
}
}
//-1文件名空/文件名不存在, 0不是文件夹、普通文件,1是文件夹, 2是普通文件
//检查是否为目录
int CheckIsDir(const char* path)
{
if(path == NULL)
return -1;
struct stat file_info;
int ret = stat(path, &file_info);
if(ret != 0)
return -1;
if(S_ISDIR(file_info.st_mode))
{
return 1;
}
else if(S_ISREG(file_info.st_mode))
{
return 2;
}
else
{
return 0;
}
}
//-1路径为空 1绝对路径 2相对路径
//判断是否为合法路径、绝对或者相对路径;
int CheckPath(const char* path)
{
if(path == NULL)
return -1;
//绝对路径
if(strncmp(path, "/", 1) == 0)
{
return 1;
}
//相对路径
else
{
return 2;
}
}
//拷贝数据
void CopyData(const char* path_src, const char* path_des)
{
if(path_src == NULL || path_des == NULL)
return;
int fd_src = open(path_src, O_RDONLY);
int fd_des = open(path_des, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if(fd_src == -1 || fd_des == -1)
{
printf("open src_file/ create des_file err\n");
return;
}
while(1)
{
char buff[1024] = {0};
int ret = read(fd_src, buff, 1023);
if(ret <= 0)
{
break;
}
write(fd_des, buff, ret);
}
close(fd_src);
close(fd_des);
}
//获取源文件名+拼接在目标路径后
char* getNewPath_des(const char* path_src, const char* path_des)
{
if(path_src == NULL || path_des == NULL)
return NULL;
char src_name[128] = {0};
char des_name[128] = {0};
strcpy(src_name, path_src);
strcpy(des_name, path_des);
//存放分割的每一个元素
char* src_buff[16] = {0};
char* s = strtok(src_name, "/");
int i = 0;
while(s != NULL)
{
src_buff[i++] = s;
s = strtok(NULL, "/");
}
//拼接目标文件名
//目的路径 + '/' + 文件名
char* heap_space = (char*)malloc(sizeof(char) * 128);
if(heap_space == NULL) return NULL;
memset(heap_space, 0, sizeof(char) * 128);
strcpy(heap_space, path_des);
strcat(heap_space, "/");
strcat(heap_space, src_buff[i - 1]);
return heap_space;
}
(3)main.c文件
#include "mycp.h"
int main(int argc, char* argv[])
{
Mycp(argc, argv);
return 0;
}
(4)makefile文件
objects = main.o mycp.o
mycp:$(objects)
cc -o mycp $(objects) -g
main.o:mycp.h
cc -c main.c -g
mycp.o:mycp.h
cc -c mycp.c -g
.PHONY:clean
clean:
rm mycp $(objects)
(5)测试结果
测试用例:./mycp
更多推荐
已为社区贡献1条内容
所有评论(0)