在shell命令中有cp命令,能实现文件拷贝
cp srcfile destfile
若文件destfile不存在,则将srcfile复制一份取名为destfile;
若文件destfile存在,则将srcfile复制一份取名为destfile,覆盖原来的destfile;
文件存在则清空,文件不存在则创建。
FILE *fp = open("srcfilr","r"); //以只读的方式打开文件,光标定位在文件开头
//若打开文件成功则返回文件的文件指针,若打开失败则返回NULL,并置为错误码。
if(fp == NULL){
printf("errno = %d\n", errno);//errno就是错误码,系统定义的可直接使用
printf("%s\n", strerror(errno));//错误码就是个数字,如果不知道其含义可以使用strerror(errno)打印错误码对应的信息
perror("fopen file");//可以使用perror直接打印出错误信息,"fopen file"字符串是附加信息,若不加换行,则错误信息会在字符串后接 ':'加错误信息;加换行后 ':'和错误信息会在下一行显示。
return -1;//返回-1
}
FILE *fq = open("destfile", "w");//以只读的方式打开文件destfile,若文件存在则清空文件,若文件不存在则创建文件。
if(fp == NULL){
//可使用perror打印文件错误信息,然后返回-1
perror("fopen file");
return -1;
}
char ch;
while((ch = fgetc(fp))!=EOF){
fputc(ch, fq);
}
//可将头文件封装到一个.h文件中,然后再将一些宏也封装到此文件中,最后将此文件放入/usr/include/文件夹中,这样就可以使用<>了,也不用在编译的时候加头文件路径了
#include
#include
#include
int main(int argc, const char *argv[])
{
FILE *fp, *fq;
char ch;
//文件名通过命令行传参
if((fp = fopen(argv[1], "r"))==NULL){
printf("%s",argv[1]);
//下面两句经常使用,也可封装到头文件中
perror("");
return -1;
}
if((fq = fopen(argv[2],"w"))==NULL){
printf("%s",argv[2]);
perror("");
return -1;
}
while((ch = fgetc(fp))!=EOF){
fputc(ch, fq);
}
//关闭文件
fclose(fp);
fclose(fq);
return 0;
}
步骤和fgetc/fputc相同
#include
#include
#include
void cp_file(FILE* fp, FILE* fq)
{
char buf[10];
//fgets在读到换行符是会结束,并将换行符保存在buf中,fgets最多能读取size - 1,size是fgets的第二个参数。
//fgets在读到最后一行时,会先把EOF之前的读完,然后第二次再读取EOF,这时会返回NULL
while (fgets(buf, sizeof(buf), fp)) {
//这地点应该加一个判断,判断是否成功写入文件,一般都会写成功,所以在这里默认写入成功
fputs(buf, fq);
}
}
int main(int argc, const char* argv[])
{
FILE *fp, *fq;
if ((fp = fopen(argv[1], "r")) == NULL) {
perror("open file error");
return -1;
}
if ((fq = fopen(argv[2], "w")) == NULL) {
perror("open file error");
return -1;
}
cp_file(fp, fq);
fclose(fp);
fclose(fq);
return 0;
}
#include
#include
#include
void copy_file(FILE* sfp, FILE* dfp)
{
char buf[128] = { 0 };
int ret;
//当读取到文件结尾的时候feof(sfp)返回真
//如果读取的时候失败了ferror(sfp)也是真
//只有两者同时为假的时候才能循环读写数据
while (!(feof(sfp) || ferror(sfp))) {
ret = fread(buf, 1, sizeof(buf), sfp);
fwrite(buf, 1, ret, dfp);
}
}
int main(int argc, const char* argv[])
{
FILE *fp, *fq;
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("%s", argv[1]);
perror("");
return -1;
}
if ((fq = fopen(argv[2], "w")) == NULL) {
printf("%s", argv[2]);
perror("");
return -1;
}
copy_file(fp, fq);
fclose(fp);
fclose(fq);
return 0;
}
将所需要的头文件封装到一个.h文件中,将复用行较高的语句定义成宏,并将此文件移动到/usr/include/路径下。
若以后需要可以直接向此头文件中添加内容,在使用的时候我们只需引入这一个头文件即可。
#ifndef __HEAD_H__
#define __HEAD_H__
#include
#include
#include
#define PRINT_ERR(msg) \
do { \
perror(msg); \
return -1; \
} while (0)
#endif
#include
int main(int argc, const char* argv[])
{
int fd1, fd2, ret;
char buf[128] = { 0 };
//以只读的方式打开文件,若成功则返回文件描述符,失败返回-1
if ((fd1 = open(argv[1], O_RDONLY)) == -1)
//头文件中定义的宏
PRINT_ERR("open file1 error");
//以只读的方式打开文件,若文件存在则清空文件,不存在则创建文件,文件权限为(0666 &(~umask))
if ((fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1)
PRINT_ERR("open file2 error");
//read成功返回读取到的字节的个数,0表示读取到了文件的结尾,失败返回-1置位错误码,所以只要read的返回值大于0都写文件
while ((ret = read(fd1, buf, sizeof(buf))) > 0) {
//将buf中的内容写入文件,写入长度为ret
write(fd2, buf, ret);
}
return 0;
}
父进程拷贝文件的前半部分,子进程拷贝文件的后半部分
//将光标定位到文件的结尾,lseek返回是光标距离文件开头的字节数,也就是文件的大小
int len = lseek(fd, 0, SEEK_END);
if((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1){
PRINT_ERR("open destfile error");
}
pid_t pid = fork();
//创建子进程,成功父进程返回子进程的pid,子进程返回0;失败返回-1
#include
//检查目标文件是否创建
int InitFile(const char *filename){
int fd;
if((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1){
PRINT_ERR("open destfile error");
}
close(fd);
return 0;
}
//求文件的长度
int filelen(const char *filename){
int fd;
if((fd = open(filename, O_RDONLY)) == -1)
PRINT_ERR("open srcfile error");
int len = lseek(fd, 0, SEEK_END);
return len;
}
//拷贝文件
int copy_file(const char *srcfile, const char *destfile, int n, int len){
int sfd, dfd;
char buf[128];
int count = 0;
//只能在父进程和子进程中分别打开文件
//以只读方式打开源文件
if((sfd = open(srcfile,O_RDONLY)) == -1)
PRINT_ERR("open srcfile error");
//以读写的方式开打文件,以只写的方式也可以
if((dfd = open(destfile, O_RDWR)) == -1)
PRINT_ERR("open destfile error");
//分别定位文件的光标位置,若是子进程先执行,此时文件长度为0,lseek是可以将光标定位到距文件开头n个字节位置
lseek(sfd, n, SEEK_SET);
lseek(dfd, n, SEEK_SET);
//使用read/write读写文件
while(count = read(sfd, buf, sizeof(buf))){
//len的作用主要是防止父进程在拷贝文件的时候将子进程拷贝的前几个字符覆盖
//每次都将还需读取的长度减去一睹字节
len -= count;
//当最后一次读取长度大于所需长度,那么我们在写的时候只需要写入我们需要的长度
if(len < 0)
count += len;
write(dfd, buf, count);
}
return 0;
}
int main(int argc, const char* argv[])
{
int fd, wfd;
int len = filelen(argv[1]);
if(len == -1){
fprintf(stderr, "srcfilelen == -1");
return -1;
}
InitFile(argv[2]);
pid_t pid = fork();
if (pid == -1) {
PRINT_ERR("fork error");
} else if (pid == 0) {
copy_file(argv[1], argv[2], len / 2, len - len / 2);
} else {
copy_file(argv[1],argv[2], 0, len / 2);
}
return 0;
}
多线程拷贝文件的速度要比多进程拷贝文件的速度快
#include
pthread_t tid1, tid2;
int file_len;
void CopyFile(int n, int len){
int sfd, dfd;
char buf[128];
int count = 0;
if ((sfd = open("hello.txt", O_RDONLY)) == -1) {
printf("open srcfile error");
}
if ((dfd = open("world.txt", O_RDWR)) == -1) {
printf("open destfile error");
}
lseek(sfd, n, SEEK_SET);
lseek(dfd, n, SEEK_SET);
while (count = read(sfd, buf, sizeof(buf))) {
len -= count;
if (len < 0)
count += len;
write(dfd, buf, count);
}
}
//查看目标文件是否有
int InitFile(const char* filename)
{
int fd;
if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
PRINT_ERR("open destfile error");
}
close(fd);
return 0;
}
//求源文件长度
int filelen(const char* filename)
{
int fd;
if ((fd = open(filename, O_RDONLY)) == -1)
PRINT_ERR("open srcfile error");
int len = lseek(fd, 0, SEEK_END);
return len;
}
//根据不同的arg调用不同的处理函数
void* Func(void* arg)
{
int n = 0, len = 0;
int* flag = (int*)arg;
if (*flag == 0) {
n = 0;
len = file_len / 2;
} else {
n = file_len / 2;
len = file_len - n;
}
//printf("*flag = %d, n = %d, len = %d\n", *flag, n, len);
CopyFile(n, len);
}
int main(int argc, const char* argv[])
{
//为了方便,将文件写成固定的了,当让也可采用命令行传参
file_len = filelen("hello.txt");
if (file_len == -1) {
fprintf(stderr, "srcfilelen == -1");
return -1;
}
InitFile("world.txt");
//通过不同的标记拷贝文件不同的位置
int flag = 0;
if (errno = pthread_create(&tid1, NULL, Func, (void*)&flag))
PRINT_ERR("create thread1 error");
int flag1 = 1;
if (errno = pthread_create(&tid2, NULL, Func, (void*)&flag1))
PRINT_ERR("create thread2 error");
//一定要阻塞等待线程结束,或者使用死循环,一定不要让进程结束,当进程结束时,所有的线程都会被销毁
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}