有时候在编程时会碰到文件路径的解析,如提取一个文件路径中的文件名、文件所在目录,文件的后缀名等。下面写了一个小函数以实现这些功能。
#include <stdio.h>
#include <string.h>
typedef struct file_pathname{
char mini_pathname[1024]; /*文件的路径和名字(不带扩展名)*/
char fdir[1024]; /*文件所在的目录*/
char mini_fname[256]; /*文件的名字(不带扩展名)*/
char suffix[30]; /*文件的扩展名*/
}fpn;
fpn *analysis_pathname(fpn *myfpn, char *pathname);
int main()
{
fpn fpn_log;
memset(&fpn_log, 0, sizeof(fpn));
analysis_pathname(&fpn_log, "/root/home/Rayin/abc.log");
printf("文件的路径和名字(不带扩展名):%s\n",fpn_log.mini_pathname);
printf("文件所在的目录:%s\n",fpn_log.fdir);
printf("文件的名字(不带扩展名):%s\n",fpn_log.mini_fname);
printf("文件的扩展名:%s\n",fpn_log.suffix);
}
/*
*解析文件路径,提取出文件所在的目录、文件名和扩展名
*成功返回存放以上信息的结构体指针,失败返回NULL
*/
fpn *analysis_pathname(fpn *myfpn, char *pathname)
{
int len;
int i, j, k, rear;
i = j = k = rear = 0;
len = strlen(pathname);
if (!pathname)
return NULL;
i = len - 1;
while (pathname[i] != '.' && i >= 0) {
i--;
}
if (i == len -1 || i < 0) {
printf("log file:no suffix name!\n");
i = rear = len -1; /*无扩展名,i和rear都指向文件名最后一个字符的下标 */
}
else {
for (rear = i; rear < len; rear++) { /*有扩展名*/
myfpn->suffix[j++] = pathname[rear];
}
i--;
rear = i; /*i和rear都指向文件名最后一个字符的下标 */
myfpn->suffix[j] = '\0';
j = 0;
}
while (pathname[i] != '/' && i >= 0) { /*最后一个"/"是路径与文件名格开的标记*/
i--;
}
if (i == rear) {
printf("pathname error:no file name!\n"); /*没有文件名*/
return NULL;
}
if (i == -1) {
printf("pathname error:no dir!\n"); /*没有目录*/
return NULL;
}
while (j <= rear) {
if (j <= i) {
myfpn->fdir[j] = pathname[j]; /*提取文件所在目录(最里层)*/
j++;
}
else {
if (j <= rear) { /*仅提取文件名,不含扩展名*/
myfpn->mini_fname[k++] = pathname[j++];
}
else
break;
}
}
myfpn->fdir[j] = '\0'; /*文件所在目录*/
myfpn->mini_fname[k] = '\0'; /*文件名,不含扩展名*/
strcpy(myfpn->mini_pathname, myfpn->fdir);
strcat(myfpn->mini_pathname, myfpn->mini_fname);/*提取文件的路径和名字(不带扩展名)*/
return myfpn;
}
结果:
文件的路径和名字(不带扩展名):/root/home/Rayin/abc
文件所在的目录:/root/home/Rayin/
文件的名字(不带扩展名):abc
文件的扩展名:.log
最近又看了看这个,感觉还是有些不足,如,结构体fpn的成员有些多余,这样放浪内存空间,analyse_pathname()函数看起结构和逻辑都很复杂,下面出一个改良版本。有不足的地方,请多指正。
#include <stdio.h>
#include <string.h>
typedef struct file_pathname{
char fdir[256]; /*文件所在的目录*/
char mini_fname[256]; /*文件的名字(不带扩展名)*/
char suffix[10]; /*文件的扩展名*/
}fpn_t;
int strpos(const char *src, char c, int flag);
fpn_t *analysis_pathname(fpn_t *myfpn, char *pathname);
int main()
{
fpn_t myfpn;
memset(&myfpn, 0, sizeof(fpn_t));
if (NULL != analysis_pathname(&myfpn, "./apple.log")) {
printf("%s\n",myfpn.fdir);
printf("%s\n",myfpn.mini_fname);
printf("%s\n",myfpn.suffix);
}
else
printf("error!\n");
}
/* 功能:解析文件路径,提取出文件所在的目录、文件名和扩展名
* 参数:myfpn,存放以上信息的结构体指针;pathname,文件路径
* 返回值:成功为fpn_t *,失败为NULL.
*/
fpn_t *analysis_pathname(fpn_t *myfpn, char *pathname)
{
int i, pos, j;
i = pos = j = 0;
if (!pathname)
return NULL;
/* 获取文件所在的目录fdir */
pos = strpos(pathname, '/', 1); //标志为1表示从尾部开始找
if (pos == -1)
return NULL;
while(i < pos) {
myfpn->fdir[i] = pathname[i];
i++;
}
myfpn->fdir[i] = '\0';
/* 获取文件的名字(不带扩展名)mini_fname */
i = strpos(pathname, '/', 1);
pos = strpos(pathname, '.', 1);
if (i == -1 || pos == -1)
return NULL;
pos--;
while(i < pos) {
myfpn->mini_fname[j] = pathname[i];
i++;
j++;
}
myfpn->mini_fname[j] = '\0';
/* 获取文件的扩展名suffix,即.xxx */
i = strpos(pathname, '.', 1);
pos = strlen(pathname);
if (i == pos) //没有后缀
return NULL;
i--;
j = 0;
while(i < pos) {
myfpn->suffix[j] = pathname[i];
i++;
j++;
}
myfpn->suffix[j] = '\0';
return myfpn;
}
/* 功能:获取某字符c,在字符串src中的位置
* 参数:src,源字符串;c,字符;flag,选择查找顺序的标志,0表示从头部开始找,1表示从尾部开始找
* 返回值:成功为字符c在字符串src中的实际位置,范围:[1,strlen];失败为-1。
*/
int strpos(const char *src, char c, int flag)
{
const char *p;
int pos, len;
p = src;
pos = 1;
len = strlen(src);
if (flag == 0) { //flag == 0表示从头部开始找
while (c != *p && *p) {
pos++;
p++;
}
if(*p == '\0') //没有此字符
pos = -1;
}
else if(flag == 1) { //flag == 1表示从尾部开始找
p += len -1; //指向字符串的最后一个字符
pos = len;
while (c != *p && pos > 0) {
pos--;
p--;
}
if(pos == 0) //没有此字符
pos = -1;
}
return pos; //返回字符c在字符串src中的实际位置,范围:[1,strlen];失败为-1.
}
这里多了一个函数int strpos(const char *src, char c, int flag),使得fpn_t *analysis_pathname(fpn_t *myfpn, char *pathname)的结构和逻辑更加简洁明了。
结果:
./
apple
.log
===========================
第三次优化:大内存结构体变量不宜分配在栈上,因为栈空间本身就比较小,而应该用堆分配,并且按需分配内存。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct file_pathname{
char *fdir; /*文件所在的目录*/
char *mini_fname; /*文件的名字(不带扩展名)*/
char *suffix; /*文件的扩展名*/
}fpn_t;
int strpos(const char *src, char c, int flag);
fpn_t *analysis_pathname(char *pathname);
void release_fpn(fpn_t *fpn);
int main()
{
fpn_t *myfpn = NULL; //定义后一定要赋初值为NULL;且要记得最后释放它所指向的空间
if (NULL != (myfpn = analysis_pathname("/home/lgh/apple.log"))) {
printf("%s\n", myfpn->fdir);
printf("%s\n", myfpn->mini_fname);
printf("%s\n", myfpn->suffix);
}
else
printf("error!\n");
release_fpn(myfpn);
return 0;
}
/* 功能:解析文件路径,提取出文件所在的目录、文件名和扩展名,
* 这些信息都是按需分配内存空间。使用完后记得释放该函数分配的内存空间。
* 参数:pathname,文件路径.
* 返回值:成功为fpn_t *,失败为NULL.
*/
fpn_t *analysis_pathname(char *pathname)
{
int i, pos, j;
fpn_t *fpn;
i = pos = j = 0;
fpn = NULL;
if (!pathname)
return NULL;
fpn = (fpn_t *)malloc(sizeof(fpn_t));
if (fpn)
memset(fpn, 0, sizeof(fpn_t));
else
return NULL;
/* 获取文件所在的目录fdir */
pos = strpos(pathname, '/', 1); //标志为1表示从尾部开始找
if (pos == -1)
return NULL;
else { //分配空间
fpn->fdir = (char *)malloc(sizeof(char)*(pos+1));
if (fpn->fdir)
memset(fpn->fdir, 0, sizeof(char)*(pos+1));
else
return NULL;
}
while(i < pos) {
fpn->fdir[i] = pathname[i];
i++;
}
fpn->fdir[i] = '\0';
/* 获取文件的名字(不带扩展名)mini_fname */
i = strpos(pathname, '/', 1);
pos = strpos(pathname, '.', 1);
if (i == -1 || pos == -1)
return NULL;
else {
fpn->mini_fname = (char *)malloc(sizeof(char)*(pos-i));
if (fpn->mini_fname)
memset(fpn->mini_fname, 0, sizeof(char)*(pos-i));
else
return NULL;
}
pos--;
while(i < pos) {
fpn->mini_fname[j] = pathname[i];
i++;
j++;
}
fpn->mini_fname[j] = '\0';
/* 获取文件的扩展名suffix,即.xxx */
i = strpos(pathname, '.', 1);
pos = strlen(pathname);
if (i == pos) //没有后缀
return NULL;
else {
fpn->suffix = (char *)malloc(sizeof(char)*(pos-i+1));
if (fpn->suffix)
memset(fpn->suffix, 0, sizeof(char)*(pos-i+1));
else
return NULL;
}
i--;
j = 0;
while(i < pos) {
fpn->suffix[j] = pathname[i];
i++;
j++;
}
fpn->suffix[j] = '\0';
return fpn;
}
/* 功能:获取某字符c,在字符串src中的位置(第一次出现,从开头或从尾部)
* 参数:src,源字符串;c,字符;flag,选择查找顺序的标志,0表示从头部开始找,1表示从尾部开始找
* 返回值:成功为字符c在字符串src中的实际位置,范围:[1,strlen];失败为-1。
*/
int strpos(const char *src, char c, int flag)
{
const char *p;
int pos, len;
p = src;
pos = 1;
len = strlen(src);
if (flag == 0) { //flag == 0表示从头部开始找
while (c != *p && *p) {
pos++;
p++;
}
if(*p == '\0') //没有此字符
pos = -1;
}
else if(flag == 1) { //flag == 1表示从尾部开始找
p += len -1; //指向字符串的最后一个字符
pos = len;
while (c != *p && pos > 0) {
pos--;
p--;
}
if(pos == 0) //没有此字符
pos = -1;
}
return pos; //返回字符c在字符串src中的实际位置,范围:[1,strlen];失败为-1.
}
void release_fpn(fpn_t *fpn)
{
if (fpn) {
if (fpn->fdir)
free(fpn->fdir);
if (fpn->mini_fname)
free(fpn->mini_fname);
if (fpn->suffix)
free(fpn->suffix);
free(fpn);
fpn = NULL;
}
}
结果:
/home/lgh/
apple
.log
-----------------------------------------------------------------------------------ending!