一个保持服务器文件整洁的简单方法

一个保持服务器文件整洁的简单方法

前言

在项目开发实施的过程中,我们经常遇到服务器需要存储大量文件的情况,而且这些文件中存在大量内容相同的文件。这篇文章的目标是使用少量代码。提供一个简单的解决方法

解决思路

  1. 建立一个表,用来保存用户上传的的文件记录.
  2. 当有新文件上传的时候,添加一条记录.并设置引用计数=1
  3. 当有记录删除或者修改的时候更新其对应的引用计数.
  4. 尔后,你就只需要定期清理引用计数为0 的文件就好.

数据表设计

文件引用计数器表

CREATE TABLE `tp_files_ref` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `path` varchar(100) NOT NULL COMMENT '文件路径 使用MD5作为文件名.',
  `ref_count` mediumint(9) NOT NULL COMMENT '引用计数',
  PRIMARY KEY (`id`),
  UNIQUE KEY `path` (`path`) USING HASH,
  KEY `ref_count` (`ref_count`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

假定我们有一个相册表,其中cover 便是用户要上传的相册封面照片.

CREATE TABLE `tp_category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `pid` int(11) DEFAULT '0',
  `path` varchar(35) DEFAULT NULL COMMENT '分类路径 数字 以 | 结尾',
  `name` varchar(60) DEFAULT NULL COMMENT '相册标题',
  `desc` varchar(120) DEFAULT NULL COMMENT '相册描述',
  `cover` varchar(100) DEFAULT NULL COMMENT '相册封面',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我们针对相册封面表编写触发器,分别是针对 插入、更新、删除的操作.

# 在记录插入的时候, 自动设置标记文件引用
CREATE TRIGGER `category_after_insert` AFTER INSERT ON `tp_category` FOR EACH ROW BEGIN
	IF FALSE = ISNULL(OLD.cover) THEN
		INSERT INTO `tp_files_ref`(`path`,`ref_count`)VALUES(NEW.cover, 1) ON DUPLICATE KEY UPDATE `ref_count`=`ref_count`+1;
	END IF;
END;

# 在记录更新的时候,如果改变了封面字段, 自动调整引用计数表.
CREATE TRIGGER `category_after_update` AFTER UPDATE ON `tp_category` FOR EACH ROW BEGIN
	IF NEW.cover != OLD.cover THEN
	
		IF FALSE = ISNULL(OLD.cover) THEN
				UPDATE `tp_files_ref` SET `ref_count`=`ref_count`-1 WHERE `path`=OLD.cover;
		END IF;
		IF FALSE = ISNULL(NEW.cover) THEN
		INSERT INTO `tp_files_ref`(`path`,`ref_count`)VALUES(NEW.cover, 1) ON DUPLICATE KEY UPDATE `ref_count`=`ref_count`+1;
		END IF;
	END IF;
END;

# 在删除的时候 引用计数 - 1
CREATE TRIGGER `category_after_delete` AFTER DELETE ON `tp_category` FOR EACH ROW BEGIN
	IF FALSE = ISNULL(OLD.cover) THEN
		UPDATE `tp_files_ref` SET `ref_count`=`ref_count`-1 WHERE `path`=OLD.cover;	
	END IF;
END;

开发文件清理功能.

以下代码基于PHP ThinkPHP5.1 开发.

<?php

namespace app\common\model;

use think\Model;
/*
    文件引用计数表. 用户标记 清理不必要的文件.
    当 ref_count =0 的时候,则表示该文件可以被删除.
*/
class  FilesRef extends Model {

	private function is_empty_dir($path){
	    if(is_dir($path) && ($handle = opendir($path))!==false){
	        while(($file=readdir($handle))!==false){     // 遍历文件夹
	            if($file!='.' && $file!='..'){
	                closedir($handle);
	                return false;
	            }
	        }
	        return true;
	    }
	    return false;
	}
    private function ClearEmptyDir()
    {
        $dir = dirname($this->path);
        $times = 2; //目录层数.

        while(Self::is_empty_dir($dir) && $times > 0) {
            rmdir($dir);
            $dir = dirname($dir);
            $times--;
        }    
    }

    /*
        清理不需要的文件.
    */
    static public function Clear()
    {
        $rows = Self::where('ref_count','EQ', 0)->select();
        foreach($rows as $item){
            $file = WWW_SITE_ROOT.$item->path;
            @\unlink($file);
            $item->ClearEmptyDir();
        }

        Self::where('ref_count', 'EQ', 0)->delete();
    }
}

猜你喜欢

转载自blog.csdn.net/bywayboy/article/details/88996625