云计算百科
云计算领域专业知识百科平台

Linux软件编程3.(文件IO和目录IO)

1.文件IO的概念

        标准IO有缓存,文件IO无缓存,多用于硬件操作和通信。

        标准IO是库函数,文件IO是系统效用。

2.系统调用与库函数

        系统调用:是Linux内核中的代码,只能在Linux系统中使用

        库函数:是对系统调用的封装,可以在不同的操作系统中安装并使用,库函数最终还是要调用系统调用完成对应功能

3.文件IO函数接口

3.1open打开文件

原型:
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_CREAT 文件不存在创建(注意要给定创建文件的权限)
O_TRUNC 文件存在截断为0(清0)
O_APPEND 追加
O_EXCL 文件存在报错
返回值:
成功返回新文件描述符
失败返回-1

        三个特殊的文件描述符:标准输入(0)、标准输出(1)、标准错误(2)。

3.2close关闭文件

注意:
有三个特殊的文件描述符:标准输入(0)、标准输出(1)、标准错误(2)
文件描述符特点:
非负整数

打开并关闭文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
int fd = 0;

//0664
//110110100
//rw-rw-r–
fd = open("a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}

printf("fd = %d\\n", fd);

close(fd);

return 0;
}

3.3标准IO对应的文件IO的打开方式

标准IO 文件IO
r O_RDONLY
r+ O_RDWR
w O_WRONLY | O_CREAT | O_TRUNC , 0664
w+ O_RDWR | O_CREAT | O_TRUNC, 0664
a O_WRONLY | O_APPEND | O_CREAT, 0664
a+ O_RDWR | O_APPEND | O_CREAT, 0664

3.4write写入

原型:ssize_t write(int fd, const void *buf, size_t count);
功能:
向文件描述符中写入buf指向的count个字节的数据
参数:
fd:文件描述符
buf:要写入的数据空间首地址
count:要写入的字节数
返回值:
成功返回实际写入的字节数
失败返回-1

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
int fd = 0;
char tmpbuff[4096] = {"hello world"};
ssize_t nret = 0;

fd = open("a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}

nret = write(fd, tmpbuff, strlen(tmpbuff));
printf("实际写入:%ld\\n", nret);

close(fd);

return 0;
}

3.5read读取

原型:ssize_t read(int fd, void *buf, size_t count);
功能:
从文件描述符中读取count个字节放入buf指向的空间中
参数:
fd:文件描述符
buf:存放数据空间的首地址
count:想要读取的字节数
返回值:
成功返回实际读到的字节数
读到文件末尾返回0
读取出错返回-1

读取/usr/include/stdio.h路径下4096个字节:

#include "head.h"

int main(void)
{
int fd = 0;
char tmpbuff[4096] = {0};
ssize_t nret = 0;

fd = open("/usr/include/stdio.h", O_RDONLY);
if (-1 == fd)
{
perror("fail to open");
return -1;
}

nret = read(fd, tmpbuff, sizeof(tmpbuff));
printf("实际接收 %ld 字节, 内容:%s\\n", nret, tmpbuff);

close(fd);

return 0;
}

用read和write进行文件的拷贝:

#include "head.h"

int main(void)
{
FILE *fp1 = NULL;
FILE *fp2 = NULL;
char src[256] = {0};
char dst[256] = {0};
char tmpbuff[4060] ={0};
printf("请输入要拷贝的文件名:");
m_fgets(src);
printf("请输入目的文件名:");
m_fgets(dst);
char a[4096]={0};
ssize_t nret;
fp1 = open(src, O_RDONLY);
if (NULL == fp1)
{
perror("fail to open1");
return -1;
}
fp2 = open (dst,O_WRONLY | O_CREAT | O_TRUNC ,0664);
if (NULL == fp2)
{
perror("fail to open2");
return -1;
}
while (nret = read(fp1,tmpbuff,sizeof(tmpbuff)))
{
write(fp2,tmpbuff,nret);
}

close(fp1);
close(fp2);
return 0;
}

3.6lseek文件描述符偏移量的定位

原型:off_t lseek(int fd, off_t offset, int whence);
功能:
重新定位流的偏移量
参数:
fd:文件描述符
offset:偏移量
whence:
SEEK_SET
SEEK_CUR
SEEK_END
返回值:
成功返回偏移量
失败返回-1

偏移打印并获取当前偏移量

#include "head.h"

int main(void)
{
int fd = 0;
char ch = 0;
off_t len = 0;

fd = open("a.txt", O_WRONLY | O_CREAT, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}

len = lseek(fd, 10, SEEK_SET);
printf("偏移量:%ld\\n", len);
ch = 'a';
write(fd, &ch, 1);
len = lseek(fd, 0, SEEK_CUR);
printf("偏移量:%ld\\n", len);

len = lseek(fd, -5, SEEK_CUR);
printf("偏移量:%ld\\n", len);
ch = 'b';
write(fd, &ch, 1);

len = lseek(fd, 0, SEEK_SET);
printf("偏移量:%ld\\n", len);
ch = 'c';
write(fd, &ch, 1);

close(fd);

return 0;
}

                                                

3.7文件IO与标准IO互相转换的函数

函数接口 功能
fileno 根据文件流指针获得文件描述符
fdopen 根据已经打开的文件描述符获得文件流指针
feof 判断文件流指针是否到达末尾
ferror 判断文件流指针是否出错

小项目:单词查找

需要从dict.txt文本文件中查找从终端输入的单词,并输出其意思。

#include"head.h"
int main(void)
{
char in_put_word[256] = {0};
char tmpbuff[1024] = {0};
char word[256] = {0};
char explanation[256] = {0};
int a = 0;
printf("请输入你要查询的单词:\\n");
gets(in_put_word);
in_put_word[strlen(in_put_word)]= '\\0';
FILE *fp = NULL;
fp = fopen("dict.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while(1)
{
if(fgets(tmpbuff, sizeof(tmpbuff), fp) == NULL)
{
printf("no found\\n");
break;
}
//将fgets读到的内容分割,前半部分为255个字节的内容,遇到空格截止存在word中
//后半部分读取255个字节内容,遇到\\n截止,存在explanation中
sscanf(tmpbuff, "%255s %255[^\\n]", word, explanation);
if(strcmp(in_put_word, word) == 0)
{
printf("单词含义:%s\\n",explanation);
a = 1;
break;
}
}
fclose(fp);
return 0;
}

4.目录IO

4.1操作方式

        1)打开目录文件 2)读取目录文件中的目录项 3)关闭目录文件

4.2函数接口

4.2.1opendir打开目录流获得目录流指针

原型:DIR *opendir(const char *name);
功能:
打开目录流获得目录流指针
参数:
name:目录文件的路径
返回值:
成功返回目录流指针
失败返回NULL

4.2.2closedir关闭目录流指针

原型:int closedir(DIR *dirp);
功能:
关闭目录流指针

4.2.3readdir读取并返回下一个目录项的信息

原型:struct dirent *readdir(DIR *dirp);
功能:
读取并返回下一个目录项的信息
参数:
dirp:目录流指针
返回值:
成功返回包含目录项信息结构体指针
失败返回NULL
读到文件末尾返回NULL

struct dirent {
ino_t d_ino; /* Inode number:通过inode找到文件对应的磁盘空
间位置 */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types:文件类型 */
char d_name[256]; /* Null-terminated filename: 文件名*/
};

返回输入路径文件的属性:

#include "head.h"

int main(void)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
char filepath[256] = {0};

printf("请输入路径:\\n");
m_fgets(filepath);

dp = opendir(filepath);
if (NULL == dp)
{
perror("fail to opendir");
return -1;
}

while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}

if ('.' == pp->d_name[0])
{
continue;
}

switch (pp->d_type)
{
case DT_BLK:printf("块设备文件");break;
case DT_CHR:printf("字符设备文件");break;
case DT_DIR:printf("目录文件");break;
case DT_FIFO:printf("管道文件");break;
case DT_LNK:printf("链接文件");break;
case DT_REG:printf("普通文件");break;
case DT_SOCK:printf("套接字文件");break;
}

printf("\\t\\t%s\\t\\t%s/%s\\n", pp->d_name, filepath, pp->d_name);
}

closedir(dp);

return 0;
}

4.2.4getcwd获得当前工作目录的绝对路径

原型:char *getcwd(char *buf, size_t size);
功能:
获得当前工作目录的绝对路径
参数:
buf:存放路径字符串空间首地址
size:最多存放字符串的大小
返回值:
成功返回包含字符串空间的首地址
失败返回NULL

示例:

#include "head.h"

int main(void)
{
char tmpbuff[4096] = {0};
FILE *fp = NULL;

getcwd(tmpbuff, sizeof(tmpbuff));
printf("当前路径:%s\\n", tmpbuff);

mkdir("tmp", 0777);
rmdir("tmp");

chdir("..");

getcwd(tmpbuff, sizeof(tmpbuff));
printf("当前路径:%s\\n", tmpbuff);

fclose(fopen("file.txt", "w"));

return 0;
}

                

深度有限遍历所有文件并打印路径:

#include "head.h"

void listdir(char *dirpath)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
char tmpbuff[4096] = {0};

dp = opendir(dirpath);
if (NULL == dp)
{
perror("fail to opendir");
printf("failed:%s\\n", dirpath);
return;
}

while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}

if ('.' == pp->d_name[0])
{
continue;
}

sprintf(tmpbuff, "%s/%s", dirpath, pp->d_name);
printf("%s\\n", tmpbuff);

if (pp->d_type == DT_DIR)
{
listdir(tmpbuff);
}
}

closedir(dp);

return;
}

int main(void)
{
listdir("/home/linux");

return 0;
}

广度优先遍历所有文件并打印路径:

#include "head.h" // 包含自定义头文件 head.h(可能包含通用定义或函数声明)
#include "linkqueue.h" // 包含链式队列的实现头文件

void listdir(char *dirpath) // 定义遍历目录的函数,参数为目录路径
{
linknode *plinkqueue = NULL; // 初始化队列指针
char tmppath[256] = {0}; // 临时存储出队的目录路径(缓冲区大小256字节)
char filepath[1024] = {0}; // 存储完整文件路径(缓冲区大小1024字节)
DIR *dp = NULL; // 目录流指针
struct dirent *pp = NULL; // 目录条目指针

plinkqueue = create_empty_linkqueue(); // 创建空队列
enter_linkqueue(plinkqueue, dirpath); // 将初始目录路径入队

while (!is_empty_linkqueue(plinkqueue)) // 循环直到队列为空
{
quit_linkqueue(plinkqueue, tmppath); // 从队头取出一个目录路径到 tmppath

dp = opendir(tmppath); // 尝试打开目录
if (NULL == dp) // 打开失败处理
{
perror("fail to opendir"); // 打印错误信息
printf("%s\\n", tmppath); // 输出失败路径
return; // 直接返回(可能需改为 continue 以继续处理其他目录)
}

while (1) // 循环读取目录条目
{
pp = readdir(dp); // 读取下一个目录条目
if (NULL == pp) // 如果条目为空(遍历完毕)
{
break; // 退出循环
}

if ('.' == pp->d_name[0]) // 跳过隐藏文件(以 . 开头)
{
continue;
}

sprintf(filepath, "%s/%s", tmppath, pp->d_name); // 拼接完整路径
printf("%s\\n", filepath); // 打印路径

if (pp->d_type == DT_DIR) // 如果是子目录
{
enter_linkqueue(plinkqueue, filepath); // 将子目录路径入队
}
}
closedir(dp); // 关闭当前目录流(原代码遗漏,需补充)
}

destroy_linkqueue(&plinkqueue); // 销毁队列释放内存
return; // 函数结束
}

int main(void)
{
listdir("/home/linux"); // 从 /home/linux 开始遍历目录
return 0; // 程序正常退出
}

均可实现以下效果:

4.2.5chdir切换当前的工作路径

原型:int chdir(const char *path);
功能:
切换当前的工作路径
参数:
path:要切换的路径
返回值:
成功返回0
失败返回-1

4.2.6mkdir创建目录文件

原型:int mkdir(const char *pathname, mode_t mode);
功能:
创建目录文件
r:读权限,决定用户是否能够查看目录下所有文件名
w:写权限,决定用户是否能够在目录下新建文件
x:执行权限,决定用户是否能够进入目录

4.2.7rmdir删除目录文件

原型:int rmdir(const char *pathname);
功能:
删除目录文件

5.时间相关的函数接口

5.1时间类型分类

5.2函数接口

5.2.1time

原型:time_t time(time_t *tloc);
功能:
返回1970-1-1日到现在的秒数
参数:
存放秒数空间的首地址
返回值:
成功返回秒数
失败返回-1

5.2.2localtime

原型:struct tm *localtime(const time_t *timep);
功能:
将秒数转换为结构体时间
参数:
timep:1970-1-1到现在的秒数
返回值:
成功返回包含时间的结构体指针
失败返回NULL

struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year – 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};

5.2.3mktime

原型:time_t mktime(struct tm *tm);
功能:
将结构体时间转换为time_t类型的时间
参数:
tm:结构体时间的首地址
返回值:
成功返回time_t时间
失败返回-1

5.2.4ctime

原型:char *ctime(const time_t *timep);
功能:
将time_t时间转换为字符串时间

应用:

#include "head.h"

int main(void)
{
time_t t;
time_t ret;
struct tm *ptm = NULL;
char *pstr = NULL;

// time(&t);
t = time(NULL);
printf("t = %ld\\n", t);

ptm = localtime(&t);
printf("%04d-%02d-%02d %02d:%02d:%02d\\n", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

ret = mktime(ptm);
printf("ret = %ld\\n", ret);

pstr = ctime(&ret);
printf("pstr = %s\\n", pstr);

return 0;
}

赞(0)
未经允许不得转载:网硕互联帮助中心 » Linux软件编程3.(文件IO和目录IO)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!