FastDFS加Redis实现自定义文件名存储海量文件

2022-04-10 0 419

FastDFS非常适合存储大量的小文件,遗憾的是本身不支持自定义文件名,文件名是存储成功以后根据存储位置生成的一个file_id。很多应用场景不得不使用自定义文件名,在不修改其源码的情况下,可以在存储客户端fdfs_client增加一个用来存储自定义文件名和fastdfs的file_id之间的映射关系的数据库间接实现自定义文件名的存取和访问,在这里我们选用了reids。顺便说一下,淘宝也有一个类似于FastDFS的文件存储系统TFS,对于自定义文件名,它是用mysql来存储映射关系的,我认为在高并发访问下mysql本身就是瓶颈,因此在这个方案中采用了redis。

准备工作:

fastdfs环境安装...略...(官方:https://code.google.com/p/fastdfs/)

redis环境安装...略...(官方:http://redis.io/)

用python实现,因此需要安装fastdfs的python客户端(下载:https://fastdfs.googlecode.com/files/fdfs_client-py-1.2.6.tar.gz)

python的redis客户端,到https://pypi.python.org/pypi/redis下载

# -*- coding: utf-8 -*-
import setting
from fdfs_client.client import *
from fdfs_client.exceptions import *
 
from fdfs_client.connection import *
 
import redis
import time
import logging
import random
 
logging.basicConfig(format=\'[%(levelname)s]: %(message)s\', level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
 
 
class RedisError(Exception):
     def __init__(self, value):
         self.value = value
     def __str__(self):
         return repr(self.value)
 
class fastdfsClient(Fdfs_client):
    def __init__(self):
        self.tracker_pool = ConnectionPool(**setting.fdfs_tracker)
        self.timeout  = setting.fdfs_tracker[\'timeout\']
        return None
 
    def __del__(self):
        try:
            self.pool.destroy()
            self.pool = None
        except:
            pass
 
class fastdfs(object):
    def __init__(self):
        \'\'\'
        conf_file:配置文件
        \'\'\'
        self.fdfs_client = fastdfsClient()
        self.fdfs_redis = []
        for i in setting.fdfs_redis_dbs:
            self.fdfs_redis.append(redis.Redis(host=i[0], port=i[1], db=i[2]))
 
    def store_by_buffer(self,buf,filename=None,file_ext_name = None):
        \'\'\'
        buffer存储文件
        参数:
        filename:自定义文件名,如果不指定,将远程file_id作为文件名
        file_ext_name:文件扩展名(可选),如果不指定,将根据自定义文件名智能判断
        返回值:
        {
        \'group\':组名,
        \'file_id\':不含组名的文件ID,
        \'size\':文件尺寸,
        \'upload_time\':上传时间
        }
        \'\'\'
        if filename and  random.choice(self.fdfs_redis).exists(filename):
            logger.info(\'File(%s) exists.\'%filename)
            return   random.choice(self.fdfs_redis).hgetall(filename)
        t1 = time.time()
#        try:
        ret_dict = self.fdfs_client.upload_by_buffer(buf,file_ext_name)
#        except Exception,e:
#            logger.error(\'Error occurred while uploading: %s\'%e.message)
#            return None
        t2 = time.time()
        logger.info(\'Upload file(%s) by buffer, time consume: %fs\' % (filename,(t2 - t1)))
        for key in ret_dict:
            logger.debug(\'[+] %s : %s\' % (key, ret_dict[key]))
        stored_filename = ret_dict[\'Remote file_id\']
        stored_filename_without_group = stored_filename[stored_filename.index(\'/\')+1:]
        if not filename:
            filename =stored_filename_without_group
        vmp = {\'group\':ret_dict[\'Group name\'],\'file_id\':stored_filename_without_group,\'size\':ret_dict[\'Uploaded size\'],\'upload_time\':int(time.time()*1000)}
        try:
            for i in self.fdfs_redis:
                if not i.hmset(filename,vmp):
                    raise RedisError(\'Save Failure\')
                logger.info(\'Store file(%s) by buffer successful\' % filename)
        except Exception,e:
            logger.error(\'Save info to Redis failure. rollback...\')
            try:
                ret_dict = self.fdfs_client.delete_file(stored_filename)
            except Exception,e:
                logger.error(\'Error occurred while deleting: %s\'%e.message)
            return None
        return vmp
 
    def remove(self,filename):
        \'\'\'
        删除文件,
        filename是用户自定义文件名
        return True|False
        \'\'\'
        fileinfo = random.choice(self.fdfs_redis).hgetall(filename)
        stored_filename = \'%s/%s\'%(fileinfo[\'group\'],fileinfo[\'file_id\'])
        try:
            ret_dict = self.fdfs_client.delete_file(stored_filename)
            logger.info(\'Remove stored file successful\')
        except Exception,e:
            logger.error(\'Error occurred while deleting: %s\'%e.message)
            return False
        for i in self.fdfs_redis:
            if not i.delete(filename):
                logger.error(\'Remove fileinfo in redis failure\')
        logger.info(\'%s removed.\'%filename)
        return True
 
    def download(self,filename):
        \'\'\'
        下载文件
        返回二进制
        \'\'\'
        finfo = self.getInfo(filename)
        if finfo:
            ret = self.fdfs_client.download_to_buffer(\'%s/%s\'%(finfo[\'group\'],finfo[\'file_id\']))
            return ret[\'Content\']
        else:
            logger.debug(\'%s is not exists\'%filename)
            return None
 
    def list(self,pattern=\'*\'):
        \'\'\'
        列出文件列表
        \'\'\'
        return random.choice(self.fdfs_redis).keys(pattern)
 
    def getInfo(self,filename):
        \'\'\'
        获得文件信息
        return:{
        \'group\':组名,
        \'file_id\':不含组名的文件ID,
        \'size\':文件尺寸,
        \'upload_time\':上传时间
        }
        \'\'\'
        return random.choice(self.fdfs_redis).hgetall(filename)

配置:

# -*- coding: utf-8 -*-
#fastdfs tracker, multiple tracker supported
fdfs_tracker = {
\'host_tuple\':(\'192.168.2.233\',\'192.168.2.234\'),
\'port\':22122,
\'timeout\':30,
\'name\':\'Tracker Pool\'
}
#fastdfs meta db, multiple redisdb supported
fdfs_redis_dbs = (
    (\'192.168.2.233\',6379,0),
    (\'192.168.2.233\',6379,1)
)

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Python教程 FastDFS加Redis实现自定义文件名存储海量文件 http://www.20zxx.cn/375245/xuexijiaocheng/python.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务