web2py的upload使用详解/优化/修复

一、使用详解

web2py在表字段定义时,如果类型是“upload”,就能很方便的实现文件上传,upload字段有几个关键属性配置:

1、uploadfield

这个意思是,在数据库中另外单独再用一个blob字段来存储上传的文件,例如:

db.define_table('myfile',
                Field('image', 'upload', uploadfield='image_file'),
                Field('image_file', 'blob'))


上传上来的文件是存在数据库中的 BLOB(binary large object)----二进制大对象,实践证明用了BLOB对数据库性能影响还是蛮大,特别是有 大的 图像视频 文件,所以基本不这么用;

2、autodelete

这个很好理解,如果设置成True,那表中行数据删除时,相关的上传文件也自动删除;

3、uploadseparate

这个属性很有意义,因为实践已经证明,一个文件夹中有大量文件时,文件访问性能会变低,web2py手册原话是这样的:

    In most operating system, accessing the file system can become slow when there are many files in the same folder. If you plan to upload more than 1000 files you can ask web2py to organize the uploads in subfolders

1000个文件以上就建议你分文件夹存储了,那对于有10万级以上大量附件文件上传的管理系统,这里肯定设置成True

二、为何要优化

接着上面说,那是不是 uploadseparate 设置成Ture就万事大吉呢,非也。因为web2py的上传文件分文件夹存储逻辑是这样的。

1、我们知道web2py为了安全性,上传文件的名字都做了加密改名,最终存储在系统的文件名为:

“表名+字段名+UUID+BASE编码加密后的源文件名” 

2、uploadseparate 设置成Ture,他的文件夹拆分存储逻辑为:“表+字段”名称生成一个文件夹,然后UUID的前2位生成一个子文件夹,即UUID前2位相同的文件都会存在同一个文件夹下。我们知道UUID是个16进制编码的东西,每1位的取值范围为0-f共16位,只取前2位那就意味着现在的web2py默认的自动拆分逻辑,子文件夹最多256个

实践观察,我这边一个系统目前才1万行数据的附件上传文件,有的单个子文件夹已经超过了1K个文件了,再往后使用估计又会造成单文件夹下文件太多问题。

三、开始优化

我计划按照UUID的前5位来拆分(大家随意,开始打算直接按UUID,每个文件放一个文件,后来想想文件夹太多是不是也影响性能,这个未证实测试过),需要更改库里面objects.py,methods.py两个文件:

(1)objects.py

搜索uploadseparate,总共改2处

                if self.uploadseparate:
                    if self.uploadfs:
                        raise RuntimeError("not supported")
                    path = pjoin(
                        path, "%s.%s" % (tablename, self.name), uuid_key[:5]
                    )

       if self.uploadseparate:
            t = m.group("table")
            f = m.group("field")
            u = m.group("uuidkey")
            path = pjoin(path, "%s.%s" % (t, f), u[:5])

(2)methods.py

搜索uploadseparate,总共改1处

if field.uploadseparate:
    items = oldname.split(".")
    uploadfolder = pjoin(
        uploadfolder, "%s.%s" % (items[0], items[1]), items[2][:5]

就这么简单,手工。

四、之前的文件修复

如果你像我一样,之前没有拆分文件夹,中途半道才来修改,怎么办呢,之前的文件在前台肯定不能访问了。这里写了个小的修复程序参考:

def uploadfix():
    import shutil,os

    old_path = os.path.join(request.folder, 'xxx')#xxx你原来定义字段的上传目录
    REGEX_UPLOAD_PATTERN = (r"(?P<table>\w+)\.(?P<field>\w+)\.(?P<uuidkey>[\w-]+)(\.(?P<name>\S+))?\.\w+$")
    #一个表中有多个字段是上传附件用的
    for row in db().select(db.mydb.upload1,db.mydb.upload2,db.mydb.upload3,):
        for filed in row:
          if row[filed]:
             m = re.match(REGEX_UPLOAD_PATTERN, row[filed])
             t = m.group("table")
             f = m.group("field")
             u = m.group("uuidkey")
             new_path=os.path.join(old_path,"%s.%s" % (t, f), u[:5])#我用前5位
             try:os.mkdir(new_path)
             except:pass
             try:shutil.move(os.path.join(old_path, row[filed]), os.path.join(new_path, row[filed]))
             except:pass
    return

五、最后的收尾

最后,upload使用分文件夹存储后,如果autodelete打开,web2py自动删除文件后不会删除 空的文件夹,这里做个定时任务,定期清理删除一次遗留的空文件夹:
def del_emp_dir():
  path_list=[os.path.join(request.folder, 'xxx\\mydb.upload1'),
             os.path.join(request.folder, 'xxx\\mydb.upload2'),
             os.path.join(request.folder, 'xxx\\mydb.upload3')]
  for path in path_list:
     for root,dirs,files in os.walk(path):
        for dir in dirs:
          try:os.rmdir(os.path.join(root,dir)) #os.rmdir() 方法用于删除指定路径的目录。仅当这文件夹是空的才可以, 否则抛出异常,所以不用担心把文件错删了
          except:pass
  return

收工!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值