Linux文件操作
Open
通过Open函数打开一个磁盘文件,如果不存在还可以打开新的文件
#include <sys/type.h>
#include <sys/stat.h>
#include <fcntl.h>
// open 函数只能在Linux系统中使用g
int open(const char *pathname,int flags);
int open(const char* pathname,int flags,mode_t mode);参数
pathname :被打开的文件名
flags,根据需求指定
O_RDONLY: 以只读方式打开文件O_WRONLY: 以只写方式打开文件O_RDWR: 以读写方式打开文件可选属性, 和上边的属性一起使用O_APPEND: 新数据追加到文件尾部,不会覆盖文件的原来内容O_CREAT: 如果文件不存在,创建该文件,如果文件存在什么也不做O_EXCL:检测文件是否存在,必须要和O_CREAT一起使用,不能单独使用: O_CREAT | O_EXCL- 检测到文件
不存在,创建新文件 - 检测到文件已经存在,创建失败,函数直接返回 - 1(如果不添加这个属性,不会返回 - 1)
- 检测到文件
mode:在创建新文件需要指定新文件的权限
* 参数最大值`0777`
* 返回值
* 成功:返回内核分配的文件描述符,大于0的整数
* 失败:-1Close函数原型
释放Open函数打开的文件描述符
#include <unistd.h>
int close(int fd);- 函数参数
:fd文件描述符,是open()函数的返回值 - 释放成功返回
0,调用失败返回-1
测试
打开文件
授予文件权限
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main(void)
{
//打开文件
int fd = open("a.txt", O_RDWR);//以读写的方式
//创建新文件
//int fd = open("./new.txt", O_CREAT|O_RDWR, 0664);
if (fd == -1)
{
printf("file open fail\n");
}
else
{
printf("create file successful fd:%d\n", fd);
}
close(fd); //关闭文件
return 0;
}判断文件状态
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main(void)
{
//检查文件状态,创建失败返回-1,文件不存在,返回分配的问价描述符
int fd = open("./new.txt", O_CREAT | O_EXCL | O_RDWR);
if (fd == -1)
{
printf("file open fail\n");
}
else
{
printf("create file successful fd:%d\n", fd);
}
close(fd); //关闭文件
return 0;
}read
用于读取文件
内部数据,在Open打开文件的时候指定读权限
#include <unistd.h>
ssize_t read(int fd,void *buf,size_t count);参数
- fd:文件描述符,open()函数的返回值,通过这个参数定位打开的
磁盘文件 - buf
传出参数,指向一块有效的内存,用于存储从文件中读出的数据- 传出参数,将变量地址传递给函数,函数调用完毕,地址中就有数据
- count :buf指针指向的
内存的大小,指定可以存储的最大字节数
返回值
大于0:从文件中读出的字节数,读文件成功等于0:代表文件读完,读文件成功-1: 读文件失败
write
将数据
写入到文件内部,通过Open打开文件的时候需要指定写权限
#include <unistd.h>
ssize_t write(int fd,const void *buf,size_t count);文件拷贝
首先在目录中创建
english.txt文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
// 1. 打开存在的文件english.txt, 读这个文件
int fd1 = open("./english.txt", O_RDONLY);
if (fd1 == -1)
{
perror("open-readfile");
return -1;
}
// 2. 打开不存在的文件, 将其创建出来, 将从english.txt读出的内容写入这个文件中
int fd2 = open("copy.txt", O_WRONLY | O_CREAT, 0664);
if (fd2 == -1)
{
perror("open-writefile");
return -1;
}
// 3. 循环读文件, 循环写文件
char buf[4096];
int len = -1;
while ((len = read(fd1, buf, sizeof(buf))) > 0)
{
// 将读到的数据写入到另一个文件中
write(fd2, buf,
);
}
// 4. 关闭文件
close(fd1);
close(fd2);
return 0;
}lseek移动文件指针
lseek可以通过此函数移动文件指针
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);参数
- fd:文件描述符,open函数的返回值
offset:偏移量whenceSEEK_SET:从文件头部开始偏移offset个字节SEEK_CUR指针的位置向后偏移offset个字节SEEK_END向后偏移offset个字节
- 返回值
- 成功
从头部开始计算总的偏移量 - 失败:-1
- 成功
lseek(fd,0,SEEK_SET); //文件指针移动到文件头部
lseek(fd,0,SEEK_CUR); //得到当前文件指针的位置
lseek(fd,0,SEEK_END); //得到文件总大小扩展实现
//拓展文件大小
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("hello.txt",O_RDWR);
if(fd == -1)
{
perror("open");
return -1;
}
//文件扩展字节
lseek(fd,1000,SEEK_END);
write(fd," ",1);
close(fd);
return 0;
}trucate/ftruncate
截断或扩展文件
#include <unistd.h>
#include <sys/types.h>
int truncate(const char*path,off_t length);
int ftruncate(int fd,off_t length);参数:
- path:要
扩展/截断的文件的文件名 - fd,open()得到
- length
最终大小size > length,文件被截断,尾部多余部分被删除size < length文件被拓展,文件最终长度为length
- 返回值: 成功返回0 ,失败返回值 -1
perror
返回值来描述系统
函数的状态(调用是否成功)成功返回0,失败返回-1.
#include <stdio.h>
void perror(const char *s);
//指定字符串值,会输出并且输出对应的错误描述信息查看文件属性信息
file文件名[参数]
参数
-b只显示文件类型和文件编码,不显示文件名-i显示文件的MIME类型MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型-F设置输出字符串的分隔符-L查看软链接文件自身文件属性
stat 命令
显示文件或目录的
详细属性信息和文件系统状态,输出的更加详细
stat [参数] 文件或者目录名参数
-f仅显示文件所在文件系统的信息-L查看软链接文件-c查看文件某个属性信息-t简洁模式,只显示摘要信息,不显示属性描述
输出的信息属性
*File :文件名
Size: 文件大小,单位字节Blocks: 文件使用的数据库总数IO Block:IO块大小regular file: 文件的实际类型,文件类型不同,该关键字也会变化Device: 设备编号Inode: Inode号,操作系统用inode编号来识别不同的文件,找到文件数据所在的block读出数据Links
*Access: 文件所有者+所属组用户+其他人对文件的访问权限UidGid: 文件所有数组名字已经组IDAccess Time,Modify TimeChange Time,被修改则更新,例如文件的硬链接链接数,大小,权限等Birth:文件生成日期
stat/lstat函数
lstat():得到的是软链接文件本身的属性信息stat(): 得到的是软链接文件关联的文件的属性信息
#include <sys/types.h>
#include <sys/stat.h>
#include <unisd.h>
int stat(const char *pathname ,struct stat *buf);
int lstat(const char *pathname,struct stat *buf);参数
pathname: 文件名,要获取这个文件的属性信息buf:传出参数,文件的信息被写入到这块内存中返回值0,失败返回-1.
struct stat {
dev_t st_dev; // 文件的设备编号
ino_t st_ino; // inode节点
mode_t st_mode; // 文件的类型和存取的权限, 16位整形数 -> 常用
nlink_t st_nlink; // 连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; // 用户ID
gid_t st_gid; // 组ID
dev_t st_rdev; // (设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; // 文件字节数(文件大小) --> 常用
blksize_t st_blksize; // 块大小(文件系统的I/O 缓冲区大小)
blkcnt_t st_blocks; // block的块数
time_t st_atime; // 最后一次访问时间
time_t st_mtime; // 最后一次修改时间(文件内容)
time_t st_ctime; // 最后一次改变时间(指属性)
};读取文件大小
#include <sys/stat.h>
#include <stdio.h>
int main(void)
{
//定义结构体存储文件休息
struct stat myst;
int ret = stat("./english.txt", &myst);
if (ret == -1)
{
perror("stat error"); //失败
}
printf("文件大小为:%d\n", (int)myst.st_size);
return 0;
}目录遍历
Opendir 函数打开目录
#include <sys/types.h>
#include <dirent.h>
//打开目录
DIR *opendir(const char *name);- 参数:
name要打开的目录名字 - 返回值
DIR*,结构体类型指针,打开失败返回NULL
readdir
目录打开后,通过readdir()函数
遍历目录中的文件信息。
每调用一次这个函数就可以得到目录中的一个文件信息,当目录中的文件信息被全部遍历完毕会得到一个空对象
#include <dirent.h>
struct dirent *readdir(DIR *dirp)参数
dirp->opendir()函数的返回值- 函数调用
成功,返回读到的文件的信息,目录文件被读完或者函数调用失败返回NULL
struct dirent结构体原型
struct dirent {
ino_t d_ino; /* 文件对应的inode编号, 定位文件存储在磁盘的那个数据块上 */
off_t d_off; /* 文件在当前目录中的偏移量 */
unsigned short d_reclen; /* 文件名字的实际长度 */
unsigned char d_type; /* 文件的类型, linux中有7中文件类型 */
char d_name[256]; /* 文件的名字 */
};- 结构体中文件类型
d_type的宏值
DT_BLK:块设备文件
DT_CHR:字符设备文件
DT_DIR:目录文件
DT_FIFO:管道文件
DT_LNK:软连接文件
DT_REG:普通文件
DT_SOCK:本地套接字文件
DT_UNKNOWN:无法识别的文件类型 - 通过readdir()函数
遍历某个目录中的文件
//打开目录
DIR* dir = opendir("/home/foryouos");
struct dirent* ptr = NULL;
//遍历目录
while((ptr = readdir(dir)) != NULL)
{
}closedir
目录操作完毕之后,需要通过
closedir()关闭通过opendir()得到的示例,释放资源
//参数是opendir()的返回值
int closedir(DIR *dirp);
//目录关闭成功返回0
//失败返回 -1遍历单层目录
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
//传入目录参数
int main(int argc, char* argv[]) //在./a.out 传入参数目录,绝对路径
{
DIR* dir = opendir(argv[1]); //打开文件
if (dir == NULL) //如果目录 为空
{
perror("opendir NULL");
return -1;
}
//遍历当前目录中的文件
int count = 0;
while (1) //循环遍历
{
struct dirent* ptr = readdir(dir); //读目录的结构体,每次读一层
if (ptr == NULL) //如果为空
{
printf("目录读完了...\n");
break;
}
//读到一个文件,判断文件类型
if (ptr->d_type == DT_REG)
{
char* p = strstr(ptr->d_name, ".txt"); //输出名字
if (p != NULL && *(p + 4) == '\0') //若明细不空
{
count++;
printf("file %d: %s\n", count, ptr->d_name);
}
}
}
printf("%s目录中txt文件的格式:%d\n", argv[1], count);
closedir(dir); //关闭目录
return 0;
}遍历多层目录
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
int GetFile(const char* path)
{
DIR* dir = opendir(path);
if (dir == NULL) //如果目录 为空
{
perror("opendir NULL");
return -1;
}
//遍历当前目录
struct dirent* ptr = readdir(dir); //读目录的结构体,每次读一层
int count = 0;
while ((ptr = readdir(dir)) != NULL) //只要目录不为空,就一直遍历先去
{
//当文件名为.或者为..时,表示当前目录或者父级目录,则通过continue语句跳过,不做处理
if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
{
continue;
}
else if (ptr->d_type == DT_DIR) //当读取的为目录类型
{
//目录
char newPath[4096];
sprintf(newPath, "%s/%s", path, ptr->d_name); //输出未见类型,并递归遍历
count += GetFile(newPath);
}
else
{
//若为普通文件
char* p = strstr(ptr->d_name, ".txt");
if (p != NULL && *(p + 4) == '\0')
{
count++;
printf("%s/%s\n", path, ptr->d_name);
}
}
}
closedir(dir);
return count;
}
//传入目录参数
int main(int argc, char* argv[]) //在./a.out 传入参数目录,绝对路径
{
if (argc < 2)
{
printf("./a.out path\n");
return 0;
}
int num = GetFile(argv[1]);
printf("%s .c :%d\n", argv[1], num);
return 0;
}