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
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
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)

浙公网安备 33010602011771号