[Django 0-1] Core.Files

Core.Files 模块

Django 的核心模块之一,封装文件操作,提供对文件的上传、下载、删除、查看大小等功能。

提供的功能

  1. 存储后端解耦,支持多种存储后端,使得在不同存储后端中的文件数据都能以相同的方式操作
  2. 文件上传、下载、删除、查看大小等功能

支持的文件存储后端

  • FileSystemStorage:基于本地文件系统的存储后端,适用于开发环境和小型项目。
  • MemoryStorage:基于内存的存储后端,适用于开发环境,小型项目,处理一些临时文件。
第三方存储后端库
  • django-storages:支持 S3, LibCloud, Azure, DigitalOcean, Google Cloud Storage, Backblaze B2, SFTP, FTP, Dropbox, Oracle Cloud 等云存储服务。
  • django-oss-storage: 支持阿里云 OSS 对象存储服务, 可能已经失效但仍可以 fork 修改。
  • django-qiniu-storage: 支持七牛云对象存储服务, 可能已经失效但仍可以 fork 修改。

支持的文件类型

  • File:普通文件,可以是任何类型的文件,如图片、视频、文档等。
  • ImageFile:图片文件,继承自 File,提供图片处理的功能,也没什么功能就多了,height,width 两个方法,需要安装 Pillow 库。
  • UploadedFile: 抽象类,提供文件上传的基本功能,主要是满足 form-data 上传的文件。
  • TemporaryUploadedFile(继承自 UploadedFile): 存放在临时文件中
  • InMemoryUploadedFile(继承自 UploadedFile): 存储在内存中

可以学习的地方

  1. 自定义文件存储后端
python 复制代码
class Storage:
    # 文件存储后端无关的接口,可以提供默认实现
    def open(self, name, mode="rb"): ...

    def save(self, name, content, max_length=None): ...

    def get_valid_name(self, name): ...

    def get_alternative_name(self, file_root, file_ext): ...

    def get_available_name(self, name, max_length=None): ...

    def generate_filename(self, filename): ...

    def path(self, name): ...

    # 与文件存储后端相关的接口,需要子类实现
    def _open(self, name, mode="rb"):
        raise NotImplementedError(
            "subclasses of Storage must provide an _open() method"
        )

    def delete(self, name):
        """
        Delete the specified file from the storage system.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a delete() method"
        )

    def exists(self, name):
        """
        Return True if a file referenced by the given name already exists in the
        storage system, or False if the name is available for a new file.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide an exists() method"
        )

    def listdir(self, path):
        """
        List the contents of the specified path. Return a 2-tuple of lists:
        the first item being directories, the second item being files.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a listdir() method"
        )

    def size(self, name):
        """
        Return the total size, in bytes, of the file specified by name.
        """
        raise NotImplementedError("subclasses of Storage must provide a size() method")

    def url(self, name):
        """
        Return an absolute URL where the file's contents can be accessed
        directly by a web browser.
        """
        raise NotImplementedError("subclasses of Storage must provide a url() method")

    def get_accessed_time(self, name):
        """
        Return the last accessed time (as a datetime) of the file specified by
        name. The datetime will be timezone-aware if USE_TZ=True.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a get_accessed_time() method"
        )

    def get_created_time(self, name):
        """
        Return the creation time (as a datetime) of the file specified by name.
        The datetime will be timezone-aware if USE_TZ=True.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a get_created_time() method"
        )

    def get_modified_time(self, name):
        """
        Return the last modified time (as a datetime) of the file specified by
        name. The datetime will be timezone-aware if USE_TZ=True.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a get_modified_time() method"
        )
  1. 文件读写锁
python 复制代码
def _fd(f):
    """Get a filedescriptor from something which could be a file or an fd."""
    return f.fileno() if hasattr(f, "fileno") else f


if os.name == "nt":
    import msvcrt
    from ctypes import (
        POINTER,
        Structure,
        Union,
        WinDLL,
        byref,
        c_int64,
        c_ulong,
        c_void_p,
        sizeof,
    )
    from ctypes.wintypes import BOOL, DWORD, HANDLE

    LOCK_SH = 0  # the default
    LOCK_NB = 0x1  # LOCKFILE_FAIL_IMMEDIATELY
    LOCK_EX = 0x2  # LOCKFILE_EXCLUSIVE_LOCK

    # --- Adapted from the pyserial project ---
    # detect size of ULONG_PTR
    if sizeof(c_ulong) != sizeof(c_void_p):
        ULONG_PTR = c_int64
    else:
        ULONG_PTR = c_ulong
    PVOID = c_void_p

    # --- Union inside Structure by stackoverflow:3480240 ---
    class _OFFSET(Structure):
        _fields_ = [("Offset", DWORD), ("OffsetHigh", DWORD)]

    class _OFFSET_UNION(Union):
        _anonymous_ = ["_offset"]
        _fields_ = [("_offset", _OFFSET), ("Pointer", PVOID)]

    class OVERLAPPED(Structure):
        _anonymous_ = ["_offset_union"]
        _fields_ = [
            ("Internal", ULONG_PTR),
            ("InternalHigh", ULONG_PTR),
            ("_offset_union", _OFFSET_UNION),
            ("hEvent", HANDLE),
        ]

    LPOVERLAPPED = POINTER(OVERLAPPED)

    # --- Define function prototypes for extra safety ---
    kernel32 = WinDLL("kernel32")
    LockFileEx = kernel32.LockFileEx
    LockFileEx.restype = BOOL
    LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
    UnlockFileEx = kernel32.UnlockFileEx
    UnlockFileEx.restype = BOOL
    UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]

    def lock(f, flags):
        hfile = msvcrt.get_osfhandle(_fd(f))
        overlapped = OVERLAPPED()
        ret = LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped))
        return bool(ret)

    def unlock(f):
        hfile = msvcrt.get_osfhandle(_fd(f))
        overlapped = OVERLAPPED()
        ret = UnlockFileEx(hfile, 0, 0, 0xFFFF0000, byref(overlapped))
        return bool(ret)

else:
    try:
        import fcntl

        LOCK_SH = fcntl.LOCK_SH  # shared lock
        LOCK_NB = fcntl.LOCK_NB  # non-blocking
        LOCK_EX = fcntl.LOCK_EX
    except (ImportError, AttributeError):
        # File locking is not supported.
        LOCK_EX = LOCK_SH = LOCK_NB = 0

        # Dummy functions that don't do anything.
        def lock(f, flags):
            # File is not locked
            return False

        def unlock(f):
            # File is unlocked
            return True

    else:

        def lock(f, flags):
            try:
                fcntl.flock(_fd(f), flags)
                return True
            except BlockingIOError:
                return False

        def unlock(f):
            fcntl.flock(_fd(f), fcntl.LOCK_UN)
            return True

总结

对于 web 服务端开发,文件操作是日常。但是文件的用途有很多,处置方式也很多。例如不同的文件类型放置在不同的存储后端,以及文件的访问控制、时效性也可以通过拓展存储后端来实现。

利用 django 这种分离文件操作和存储后端的框架,在开发中可以很好的解决大部分文件类需求。

相关推荐
苏三说技术1 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
aqi001 小时前
15天学会AI应用开发(七)有了大模型为什么还要引入RAG
人工智能·python·大模型·ai编程·ai应用
长栎2 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode2 小时前
Redis 在生产项目的使用
前端·后端
用户559822481222 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode2 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战2 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha2 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn2 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端