mmcv.fileio.file_client

 1 import inspect  # 使用import inspect查看python 类的参数和模块、函数代码
 2 import warnings
 3 from abc import ABCMeta, abstractmethod  # Python本身不提供抽象类和接口机制,要想实现抽象类,可以借助abc模块。ABC是Abstract Base Class的缩写。
 4 
 5 
 6 class BaseStorageBackend(metaclass=ABCMeta):
 7     """Abstract class of storage backends.
 8 
 9     All backends need to implement two apis: ``get()`` and ``get_text()``.
10     ``get()`` reads the file as a byte stream and ``get_text()`` reads the file
11     as texts.
12     """
13 
14     @abstractmethod
15     def get(self, filepath):
16         pass
17 
18     @abstractmethod
19     def get_text(self, filepath):
20         pass

占坑:inspect,  abs

此类做为基础类作为以下类的父类,实现两个api,“get()” and "get_text()"。

第一个读取文件作为字节流,第二个读取文件作为文本形式。

class CephBackend(BaseStorageBackend)
 1 class PetrelBackend(BaseStorageBackend):
 2     """Petrel storage backend (for internal use).
 3 
 4     Args:
 5         path_mapping (dict|None): path mapping dict from local path to Petrel
 6             path. When `path_mapping={'src': 'dst'}`, `src` in `filepath` will
 7             be replaced by `dst`. Default: None.
 8         enable_mc (bool): whether to enable memcached support. Default: True.
 9     """
10 
11     def __init__(self, path_mapping=None, enable_mc=True):
12         try:
13             from petrel_client import client
14         except ImportError:
15             raise ImportError('Please install petrel_client to enable '
16                               'PetrelBackend.')
17 
18         self._client = client.Client(enable_mc=enable_mc)
19         assert isinstance(path_mapping, dict) or path_mapping is None
20         self.path_mapping = path_mapping
21 
22     def get(self, filepath):
23         filepath = str(filepath)
24         if self.path_mapping is not None:
25             for k, v in self.path_mapping.items():
26                 filepath = filepath.replace(k, v)
27         value = self._client.Get(filepath)
28         value_buf = memoryview(value)
29         return value_buf
30 
31     def get_text(self, filepath):
32         raise NotImplementedError
class PetrelBackend(BaseStorageBackend)
 1 class MemcachedBackend(BaseStorageBackend):
 2     """Memcached storage backend.
 3 
 4     Attributes:
 5         server_list_cfg (str): Config file for memcached server list.
 6         client_cfg (str): Config file for memcached client.
 7         sys_path (str | None): Additional path to be appended to `sys.path`.
 8             Default: None.
 9     """
10 
11     def __init__(self, server_list_cfg, client_cfg, sys_path=None):
12         if sys_path is not None:
13             import sys
14             sys.path.append(sys_path)
15         try:
16             import mc
17         except ImportError:
18             raise ImportError(
19                 'Please install memcached to enable MemcachedBackend.')
20 
21         self.server_list_cfg = server_list_cfg
22         self.client_cfg = client_cfg
23         self._client = mc.MemcachedClient.GetInstance(self.server_list_cfg,
24                                                       self.client_cfg)
25         # mc.pyvector servers as a point which points to a memory cache
26         self._mc_buffer = mc.pyvector()
27 
28     def get(self, filepath):
29         filepath = str(filepath)
30         import mc
31         self._client.Get(filepath, self._mc_buffer)
32         value_buf = mc.ConvertBuffer(self._mc_buffer)
33         return value_buf
34 
35     def get_text(self, filepath):
36         raise NotImplementedError
class MemcachedBackend(BaseStorageBackend)
 1 class LmdbBackend(BaseStorageBackend):
 2     """Lmdb storage backend.
 3 
 4     Args:
 5         db_path (str): Lmdb database path. # lmdb数据路径
 6         readonly (bool, optional): Lmdb environment parameter. If True,  #lmdb环境参数,设为true,则只能读,不能写操作.
 7             disallow any write operations. Default: True.
 8         lock (bool, optional): Lmdb environment parameter. If False, when  #lmdb环境参数,设为false,发生并发访问时,不要锁定数据库
 9             concurrent access occurs, do not lock the database. Default: False.
10         readahead (bool, optional): Lmdb environment parameter. If False,
11             disable the OS filesystem readahead mechanism, which may improve   # lmdb环境参数,设为false,禁用OS文件系统预读机制,当数据库大于RAM时,这可能会提高随机读取性能。
12             random read performance when a database is larger than RAM.
13             Default: False.
14 
15     Attributes:
16         db_path (str): Lmdb database path.
17     """
18 
19     def __init__(self,
20                  db_path,
21                  readonly=True,
22                  lock=False,
23                  readahead=False,
24                  **kwargs):
25         try:
26             import lmdb
27         except ImportError:
28             raise ImportError('Please install lmdb to enable LmdbBackend.')
29 
30         self.db_path = str(db_path)
31         self._client = lmdb.open(
32             self.db_path,
33             readonly=readonly,
34             lock=lock,
35             readahead=readahead,
36             **kwargs)
37 
38     def get(self, filepath):
39         """Get values according to the filepath.
40 
41         Args:
42             filepath (str | obj:`Path`): Here, filepath is the lmdb key.
43         """
44         filepath = str(filepath)
45         with self._client.begin(write=False) as txn:
46             value_buf = txn.get(filepath.encode('ascii'))
47         return value_buf
48 
49     def get_text(self, filepath):
50         raise NotImplementedError

lmdb文件读取,只需要字节流。

 1 class HardDiskBackend(BaseStorageBackend):
 2     """Raw hard disks storage backend."""
 3 
 4     def get(self, filepath):
 5         filepath = str(filepath)
 6         with open(filepath, 'rb') as f:
 7             value_buf = f.read()
 8         return value_buf
 9 
10     def get_text(self, filepath):
11         filepath = str(filepath)
12         with open(filepath, 'r') as f:   
13             value_buf = f.read()
14         return value_buf

disk文件读取,因为是从磁盘读,所以两个方法一样。。

class FileClient:
    """A general file client to access files in different backend.

    The client loads a file or text in a specified backend from its path
    and return it as a binary file. it can also register other backend
    accessor with a given name and backend class.

    Attributes:
        backend (str): The storage backend type. Options are "disk", "ceph",
            "memcached" and "lmdb".
        client (:obj:`BaseStorageBackend`): The backend object.
    """

    _backends = {
        'disk': HardDiskBackend,
        'ceph': CephBackend,
        'memcached': MemcachedBackend,
        'lmdb': LmdbBackend,
        'petrel': PetrelBackend,
    }

    def __init__(self, backend='disk', **kwargs):
        if backend not in self._backends:
            raise ValueError(
                f'Backend {backend} is not supported. Currently supported ones'
                f' are {list(self._backends.keys())}')
        self.backend = backend
        self.client = self._backends[backend](**kwargs)

    @classmethod
    def _register_backend(cls, name, backend, force=False):
        if not isinstance(name, str):
            raise TypeError('the backend name should be a string, '
                            f'but got {type(name)}')
        if not inspect.isclass(backend):
            raise TypeError(
                f'backend should be a class but got {type(backend)}')
        if not issubclass(backend, BaseStorageBackend):
            raise TypeError(
                f'backend {backend} is not a subclass of BaseStorageBackend')
        if not force and name in cls._backends:
            raise KeyError(
                f'{name} is already registered as a storage backend, '
                'add "force=True" if you want to override it')

        cls._backends[name] = backend

    @classmethod
    def register_backend(cls, name, backend=None, force=False):
        """Register a backend to FileClient.

        This method can be used as a normal class method or a decorator.

        .. code-block:: python

            class NewBackend(BaseStorageBackend):

                def get(self, filepath):
                    return filepath

                def get_text(self, filepath):
                    return filepath

            FileClient.register_backend('new', NewBackend)

        or

        .. code-block:: python

            @FileClient.register_backend('new')
            class NewBackend(BaseStorageBackend):

                def get(self, filepath):
                    return filepath

                def get_text(self, filepath):
                    return filepath

        Args:
            name (str): The name of the registered backend.
            backend (class, optional): The backend class to be registered,
                which must be a subclass of :class:`BaseStorageBackend`.
                When this method is used as a decorator, backend is None.
                Defaults to None.
            force (bool, optional): Whether to override the backend if the name
                has already been registered. Defaults to False.
        """
        if backend is not None:
            cls._register_backend(name, backend, force=force)
            return

        def _register(backend_cls):
            cls._register_backend(name, backend_cls, force=force)
            return backend_cls

        return _register

    def get(self, filepath):
        return self.client.get(filepath)

    def get_text(self, filepath):
        return self.client.get_text(filepath)

 

posted @ 2020-11-19 20:02  闪耀虫蝗  阅读(595)  评论(0)    收藏  举报