//c语言中的一些文件操作以及文件操作函数
#include <stdio.h>//内有FILE结构体
#include <assert.h>
void FileCopy(const char*des,const char *src)//将src文件的内容拷贝到des文件,src文件可以是文本文件,也可以是二进制文件
{
FILE *fr = fopen(src,"rb");
FILE *fw = fopen(des,"wb");
assert(fr!=NULL && fw!=NULL);
char buf[1024];
int len;
while((len=fread(buf,1,1024,fr))>0)
{
fwrite(buf,1,len,fw);//读取多少写多少
}
fclose(fr);
fclose(fw);
}
int main()
{
FILE*p, *p1, *p2;
p = fopen("a.txt", "w+");
p1 = fopen("a.cpp", "wb+");
p2 = fopen("b.txt", "w+");
if (p == NULL || p1 == NULL || p2== NULL)
printf("Open error!");
char buf[128]={"dddkivgfhdhyjfhccfgdddddddddddfefwefew"};
fwrite(buf,1,20,p);
char res[128]={0};
int len1=fread(res,1,25,p);
printf("len1=%d,%s\n",len1,res);
fclose(p);
fclose(p1);
fclose(p2);
FileCopy("a.cpp","a.txt");
return 0;
}
//补充一个例题并介绍一个好用的函数:将1.txt中的前10个字符重复读取和输出5 次
/*
fseek函数调用的几个例子:
(1)移到文件开头的第十个字节后
fseek (fp,10, SEEK_SET);
(2)移到文件当前位置的后50个字节处
fseek (fp,50, SEEK_CUR);
(3)移到文件倒数第10个字节处
fseek (fp,-10, SEEK_END);
*/
按二进制只读方式打开文件;利用fseek将文件位置标记指向文件的结尾;利用ftell获取文件的位置根据返回值就能得到
FILE *fr = fopen(“1.cpp","rb");
fseek(fr,0,SEEK_END);
long sz = ftell(fr);
printf("该文件一个%ld个字节\n",sz);
fclose(fr);
强制使文件位置标记指向指定的位置;用ftell函数测定文件位置标记的当前位置,ftell函数的作用是得到流式文件中文件位置标记的当前位置。
char buf[100] = "";
FILE *fr = fopen("1.txt","r");
assert(fr != NULL);
for(int i=0;i<5;i++)
{
fread(buf,sizeof(char),10,fr);
printf("%s\n",buf);
memset(buf,0,100);//清空buf
fseek(fr,0,SEEK_SET);//文件标记跳到开头
}
fclose(fr);
*/
//linux下的一些文件操作以及文件操作函数
/*
*描述:利用文件操作函数实现普通文件的拷贝,拷贝的源文件和目标文件由主函数参数传递此处处理四种情况:
* 1 、正常使用
* 2 、传递的文件是不是同一个文件
* 3 、拷贝的是不是普通文件
* 4 、将文件是否只拷贝一份
*/
/*
stat结构体:用于获取文件信息
struct stat
{
dev_t st_dev; /* ID of device containing file */ 文件使用的设备号
ino_t st_ino; /* inode number */ 索引节点号-----可判断文件是否为同一个文件
mode_t st_mode; /* protection */ 文件对应的模式,文件,目录等-----文件类型
nlink_t st_nlink; /* number of hard links */ 文件的硬连接数
uid_t st_uid; /* user ID of owner */ 所有者用户识别号
gid_t st_gid; /* group ID of owner */ 组识别号
dev_t st_rdev; /* device ID (if special file) */ 设备文件的设备号
off_t st_size; /* total size, in bytes */ 以字节为单位的文件容量
blksize_t st_blksize; /* blocksize for file system I/O */ 包含该文件的磁盘块的大小
blkcnt_t st_blocks; /* number of 512B blocks allocated */ 该文件所占的磁盘块
time_t st_atime; /* time of last access */ 最后一次访问该文件的时间
time_t st_mtime; /* time of last modification */ /最后一次修改该文件的时间
time_t st_ctime; /* time of last status change */ 最后一次改变该文件状态的时间
};
st_mode 的结构:
st_mode 主要包含了 3 部分信息:
(1)15-12 位保存文件类型
(2)11-9 位保存执行文件时设置的信息
(3)8-0 位保存文件访问权限
S_IFMT 0170000 文件类型的位遮罩
S_IFSOCK 0140000 套接字
S_IFLNK 0120000 符号连接
S_IFREG 0100000 一般文件
S_IFBLK 0060000 区块装置
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符装置
S_IFIFO 0010000 先进先出
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
上述的文件类型在POSIX中定义了检查这些类型的宏定义:
S_ISLNK (st_mode) 判断是否为符号连接
S_ISREG (st_mode) 是否为一般文件
S_ISDIR (st_mode) 是否为目录
S_ISCHR (st_mode) 是否为字符装置文件
S_ISBLK (s3e) 是否为先进先出
S_ISSOCK (st_mode) 是否为socket
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/stat.h>//包含文件操作函数的头文件
#include <fcntl.h>//
#include <sys/types.h>//
#include <unistd.h>//
// 1、正常传参的文件拷贝
int main(int argc, char *argv)
{
if(argc < 2)
{
printf("参数不够,请重新输入\n");
exit(0);
}
int fd1 = open(argv[1], O_RDONLY);
assert(fd1 != -1);
int fd2 = open(argv[2], O_WRONLY | O_CREAT |O_TRUNC, 0664);
assert(fd2 != -1);
while(1) // 由于文件大小无法预测,所以此处使用死循环来处理
{
char buff[128] = {0};
int n = read(fd1, buff, 127);
if(n <= 0) // 当读取到文件末尾时,直接退出死循环
{
break;
}
write(fd2, buff, n);
}
close(fd1);
close(fd2);
exit(0);
}
// 2 、传递的文件是同一个文件,依靠文件信息结构体stat中的st_ino索引节点号来判断,一个文件对应一个inode节点;软连接不生成副本;
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("参数不够,请重新输入\n");
exit(0);
}
//判断传递的文件是否是同一个文件
struct stat st1, st2;
int res = stat(argv[1], &st1);
assert(res != -1);
res = stat(argv[2], &st2);
assert(res != -1);
if(st1.st_ino == st2.st_ino)
{
printf("不能拷贝同一份文件\n");
exit(0);
}
//end
int fd1 = open(argv[1], O_RDONLY);
assert(fd1 != -1);
int fd2 = open(argv[2], O_WRONLY | O_CREAT |O_TRUNC, 0664);
assert(fd2 != -1);
while(1) // 由于文件大小无法预测,所以此处使用死循环来处理
{
char buff[128] = {0};
int n = read(fd1, buff, 127);
if(n <= 0) // 当读取到文件末尾时,直接退出死循环
{
break;
}
write(fd2, buff, n);
}
close(fd1);
close(fd2);
exit(0);
}
// 3 、拷贝的是不是普通文件
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("参数不够,请重新输入\n");
exit(0);
}
//判断传递的文件是否是同一个文件
struct stat st1, st2;
int res = stat(argv[1], &st1);
assert(res != -1);
res = stat(argv[2], &st2);
assert(res != -1);
if(st1.st_ino == st2.st_ino)
{
printf("不能拷贝同一份文件\n");
exit(0);
}
//end
// 判断是否是普通文件
if(!S_ISREG(st1.mode) || !S_ISREG(st2.mode))
{
printf("源文件或者目标文件不是普通文件\n");
exit(0);
}
// end
int fd1 = open(argv[1], O_RDONLY);
assert(fd1 != -1);
int fd2 = open(argv[2], O_WRONLY | O_CREAT |O_TRUNC, 0664);
assert(fd2 != -1);
while(1) // 由于文件大小无法预测,所以此处使用死循环来处理
{
char buff[128] = {0};
int n = read(fd1, buff, 127);
if(n <= 0) // 当读取到文件末尾时,直接退出死循环
{
break;
}
write(fd2, buff, n);
}
close(fd1);
close(fd2);
exit(0);
}
// 4 、将文件不只拷贝一份
void FileCopy(char *file1, char *file2)
{
//判断传递的文件是否是同一个文件
struct stat st1, st2;
int res = stat(file1, &st1);
assert(res != -1);
res = stat(file2, &st2);
assert(res != -1);
if(st1.st_ino == st2.st_ino)
{
printf("不能拷贝同一份文件\n");
exit(0);
}
//end
// 判断是否是普通文件
if(!S_ISREG(st1.mode) || !S_ISREG(st2.mode))
{
printf("源文件或者目标文件不是普通文件\n");
exit(0);
}
// end
int fd1 = open(file1, O_RDONLY);
assert(fd1 != -1);
int fd2 = open(file2, O_WRONLY | O_CREAT |O_TRUNC, 0664);
assert(fd2 != -1);
while(1) // 由于文件大小无法预测,所以此处使用死循环来处理
{
char buff[128] = {0};
int n = read(fd1, buff, 127);
if(n <= 0) // 当读取到文件末尾时,直接退出死循环
{
break;
}
write(fd2, buff, n);
}
close(fd1);
close(fd2);
}
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("参数不够,请重新输入\n");
exit(0);
}
int i = 0;
for(i = 2; i < argc; ++i)
{
CopyFile(argv[1], argv[i]);
}
exit(0);
}