采用链表的方式保存图片文件的格式信息,文件名和大小。
重要结构体:
/* 图片文件类型 */
typedef enum image_type
{
IMAGE_TYPE_BMP,
IMAGE_TYPE_JPG,
IMAGE_TYPE_PNG,
IMAGE_TPPE_UNKNOWN, /* 不能识别 */
}image_type_e;
/* 图片文件信息 */
typedef struct iamge_file_info
{
unsigned char path_name[PATH_NAME_MAX]; /* 图片文件路径 */
image_type_e image_type; /* 图片文件类型 */
unsigned long int picture_size; /* 图片文件的大小 */
}iamge_file_info_s;
/* 文件的双向链表的节点 */
typedef struct iamge_file_node
{
iamge_file_info_s iamge_file_data;
struct iamge_file_node *prior;
struct iamge_file_node *next;
}iamge_file_node_s;
全局变量和宏定义:
#define PATH_NAME_MAX 256 /* 路径名的最大字节数 */
#define FILE_NODE_MAX 256 /* 链表节点数量最大值 */
iamge_file_node_s file_head; /* 文件头链表头 */
static unsigned int now_file_num = 0; /* 当前的图片文件数量 */
iamge_file_node_s *tail_file_node = NULL; /* 指向链表的尾节点*/
初始化:
功能:把所有的图片加入到链表中
/* 初始化 */
int im_manage_init(void)
{
const char path[PATH_NAME_MAX] = {"/usr/picture"};/* 所有图片保存这个文件夹下 */
file_head.next = NULL;
file_head.prior = NULL;
im_add_dir(path);
DEBUG("现在有 [%d] 张图片\n", now_file_num);
return 0;
}
把 path_name_dir 文件夹中的图片文件添加到链表中:
/* 把文件夹中的文件添加到链表中 */
static int im_add_dir(const char *path_name_dir)
{
DIR *dir = NULL;
struct dirent *ptr;
char base[PATH_NAME_MAX];
struct stat sta;
if((dir = opendir(path_name_dir)) == NULL)
{
DERROR("Open dir error...\n");
return -1;
}
while ((ptr = readdir(dir)) != NULL)
{
if(strcmp(ptr->d_name, ".")==0 || strcmp(ptr->d_name, "..")==0) ///current dir OR parrent dir
continue;
// 用lstat来读取文件属性并判断文件类型
memset(base,'\0',sizeof(base));
strcpy(base,path_name_dir);
strcat(base,"/");
strcat(base,ptr->d_name);
lstat(base, &sta);
if (S_ISREG(sta.st_mode)){
/* 添加普通文件 */
im_add_file(base);
}else if(S_ISDIR(sta.st_mode)){
im_add_dir(base);/* 读子文件夹 */
}
}
return 0;
}
创建并初始化一个链表的节点:
/* 初始化一个链表的节点 */
static iamge_file_node_s *im_create_node(iamge_file_info_s *im_info_cr)
{
iamge_file_node_s *p;
p = (iamge_file_node_s*)malloc(sizeof(iamge_file_node_s));
if(p == NULL){
DERROR("动态内存分配失败!\n");
exit(-1);
}
p->iamge_file_data.image_type = im_info_cr->image_type;
memset(p->iamge_file_data.path_name, 0, PATH_NAME_MAX);
memcpy(p->iamge_file_data.path_name, im_info_cr->path_name, strlen((const char *)im_info_cr->path_name));
p->iamge_file_data.picture_size = im_info_cr->picture_size;
p->prior = NULL;
p->next = NULL;
return (p);
}
添加文件:
/* 添加文件 */
int im_add_file(char *path_name_add)
{
struct stat buffer;
iamge_file_info_s f_in;
iamge_file_node_s *f_p = NULL;
if(0 != lstat((const char *)path_name_add, &buffer)){
DERROR("读取文件错误\n");
return -1;
}
memset(f_in.path_name, 0, PATH_NAME_MAX);
memcpy(f_in.path_name, path_name_add, strlen(path_name_add));
if('Y' == im_is_bmp((const char *)path_name_add)){//判断是否是bmp文件
f_in.image_type = IMAGE_TYPE_BMP;
}else if('Y' == im_is_jpg((const char *)path_name_add)){
f_in.image_type = IMAGE_TYPE_JPG;
}else if('Y' == im_is_png((const char *)path_name_add)){
f_in.image_type = IMAGE_TYPE_PNG;
}else{
f_in.image_type = IMAGE_TYPE_PNG;
}
f_in.picture_size = buffer.st_size;//赋值文件的大小
f_p = im_create_node(&f_in);//创建并初始化链表节点
im_insert_list(f_p);//插入链表节点中
return 0;
}
删除文件:
/* 删除文件 */
int im_remove_file(unsigned char *path_name_re)
{
iamge_file_node_s *f_p = NULL;
f_p = im_search_list(path_name_re);
if(f_p == NULL){
DERROR("没有此文件可以删除\n");
return -1;
}
if(im_delect_list(f_p) < 0){
DERROR("删除文件失败\n");
return -1;
}
return 0;
}
在链表的头部插入结点:
/* 在链表的头部插入结点 */
static void im_insert_list(iamge_file_node_s *file_node_in)
{
if(file_head.next != NULL){
file_head.next->prior = file_node_in;
file_node_in->next = file_head.next;
file_head.next = file_node_in;
file_node_in->prior = &file_head;
}else{
file_head.next = file_node_in;
file_node_in->next = NULL;
file_node_in->prior = &file_head;
tail_file_node = file_node_in;
}
++now_file_num;
}
删除文件结点:
/* 删除文件结点 */
static int im_delect_list(iamge_file_node_s *file_node_de)
{
if(file_head.next == NULL){
DERROR("现在播放器中没有文件\n");
return -1;
}else{
if(file_node_de->next == NULL){
file_node_de->prior->next = NULL;
if(file_node_de->prior == &file_head){
tail_file_node = NULL;
}else{
tail_file_node = file_node_de->prior;
}
file_node_de->prior = NULL;
}else{
file_node_de->prior->next = file_node_de->next;
file_node_de->next->prior = file_node_de->prior;
file_node_de->next = file_node_de->prior = NULL;
}
--now_file_num;
free(file_node_de);
return 0;
}
}
搜索遍历一个链表:
/* 搜索遍历一个链表 */
static iamge_file_node_s * im_search_list(unsigned char *path_name_se)
{
iamge_file_node_s *p_file;
if(file_head.next == NULL)
{
DERROR("现在播放器中没有文件\n");
return NULL;
}
else
{
p_file = file_head.next;
while(p_file != NULL)
{
if(0 == memcmp(p_file->iamge_file_data.path_name, (const char *)path_name_se, strlen(((const char *)path_name_se)))){
DEBUG("找到文件 [%s]\n", path_name_se);
return (p_file);
}else{
p_file = p_file->next;
}
}
return NULL;
}
}
由于不想引用图片显示部分的函数,于是此文件中定义了判断文件格式的函数:
/* 判断是否为 bmp 文件*/
static char im_is_bmp(const char *path)
{
int ret;
int fd = -1;
char picture[2];
if ((fd = open(path, O_RDONLY)) < 0 ){
DERROR("NO [%s] file\n", path);
return 'O';
}
if ((ret = read(fd, picture, 2)) < 2){
DERROR("read [%s] file error\n", path);
close(fd);
return 'R';
}
if((picture[0] != 'B') || (picture[1] != 'M')){ /*判断能前两给字节是否是 BM */
DERROR("It's not a BMP file\n");
close(fd);
return 'N';
}else{
close(fd);
return 'Y';
}
}
/* 判断是否为 jpg 文件 */
static char im_is_jpg (const char *path)
{
int ret;
int fd = -1;
char picture[2];
if ((fd = open(path, O_RDONLY)) < 0 ){
DERROR("NO [%s] file\n", path);
return 'O';
}
/* 读文件的头两个字节 */
if ((ret = read(fd, picture, 2)) < 2){
DERROR("read [%s] file error\n", path);
close(fd);
return 'R';
}
if((picture[0] != 0xff) || (picture[1] != 0xd8)){
DERROR("It's not a JPG file\n");
close(fd);
return 'N';
}
lseek(fd, -2, SEEK_END);
/* 读文件的最后两个字节 */
if ((ret = read(fd, picture, 2)) < 2){
DERROR("read [%s] file error\n", path);
close(fd);
return 'R';
}
if((picture[0] != 0xff) || (picture[1] != 0xd9)){
DERROR("It's not a BMP file\n");
close(fd);
return 'N';
}else{
close(fd);
return 'Y';
}
}
/* 判断是否为 png 文件*/
static char im_is_png(const char *path)
{
unsigned char *buf = malloc(sizeof(8));
unsigned char png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
int fd = -1;
if ((fd = open(path, O_RDONLY)) < 0){
DERROR("NO [%s] file\n", path);
return 'O';
}
if (read(fd, buf, 8) != 8){
DERROR("read [%s] file error\n", path);
close(fd);
return 'R';
}
/*判断前 PNG_BYTES_TO_CHECK 个字节是否是 (89 50 4E 47 0D 0A 1A 0A 16进制) */
if(memcmp(buf, png_signature, 8) != 0){
DERROR("It's not a PNG file\n");
close(fd);
return 'N';
}else{
close(fd);
return 'Y';
}
}
读取链表尾节点:
由于多文件程序中,用指针做全局变量会带来一些问题,因此这里用函数的形式来进行多文件之间的沟通。
/* 读取链表尾节点 */
iamge_file_node_s *im_read_fail(void)
{
return tail_file_node;
}
销毁链表:
/* 销毁链表 */
int im_manage_destroy(void)
{
iamge_file_node_s *p_node_1 = NULL;
iamge_file_node_s *p_node_2 = NULL;
if(file_head.next == NULL){
DEBUG("不用销毁\n");
return 0;
}
p_node_1 = file_head.next;
p_node_2 = file_head.next->next;
while(p_node_2 != NULL)
{
free(p_node_1);
p_node_1 = p_node_2;
p_node_2 = p_node_1->next;
}
free(p_node_1);
p_node_1 = p_node_2 = file_head.next = NULL;
return 0;
}