utils_fs.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import os
  2. import re
  3. import shutil
  4. def get_path_stem(path):
  5. """
  6. References:
  7. `std::filesystem::path::stem` since C++17
  8. """
  9. return os.path.splitext(os.path.basename(path))[0]
  10. def replace_path_stem(path, new_stem):
  11. dirname, basename = os.path.split(path)
  12. stem, extname = os.path.splitext(basename)
  13. if isinstance(new_stem, str):
  14. return os.path.join(dirname, new_stem + extname)
  15. elif hasattr(new_stem, '__call__'):
  16. return os.path.join(dirname, new_stem(stem) + extname)
  17. else:
  18. raise ValueError('Unsupported Type!')
  19. def get_path_extension(path):
  20. """
  21. References:
  22. `std::filesystem::path::extension` since C++17
  23. Notes:
  24. Not fully consistent with `std::filesystem::path::extension`
  25. """
  26. return os.path.splitext(os.path.basename(path))[1]
  27. def replace_path_extension(path, new_extname=None):
  28. """Replaces the extension with new_extname or removes it when the default value is used.
  29. Firstly, if this path has an extension, it is removed. Then, a dot character is appended
  30. to the pathname, if new_extname is not empty or does not begin with a dot character.
  31. References:
  32. `std::filesystem::path::replace_extension` since C++17
  33. """
  34. filename_wo_ext = os.path.splitext(path)[0]
  35. if new_extname == '' or new_extname is None:
  36. return filename_wo_ext
  37. elif new_extname.startswith('.'):
  38. return ''.join([filename_wo_ext, new_extname])
  39. else:
  40. return '.'.join([filename_wo_ext, new_extname])
  41. def makedirs(name, mode=0o755):
  42. """
  43. References:
  44. mmcv.mkdir_or_exist
  45. """
  46. if name == '':
  47. return
  48. name = os.path.expanduser(name)
  49. os.makedirs(name, mode=mode, exist_ok=True)
  50. def listdirs(paths, path_sep=None, full_path=True):
  51. """Enhancement on `os.listdir`
  52. """
  53. assert isinstance(paths, (str, tuple, list))
  54. if isinstance(paths, str):
  55. path_sep = path_sep or os.path.pathsep
  56. paths = paths.split(path_sep)
  57. all_filenames = []
  58. for path in paths:
  59. path_ex = os.path.expanduser(path)
  60. filenames = os.listdir(path_ex)
  61. if full_path:
  62. filenames = [os.path.join(path_ex, filename) for filename in filenames]
  63. all_filenames.extend(filenames)
  64. return all_filenames
  65. def _normalize_extensions(extensions):
  66. if extensions is None:
  67. return None
  68. new_extensions = []
  69. for extension in extensions:
  70. if extension.startswith('.'):
  71. new_extensions.append(extension.lower())
  72. else:
  73. new_extensions.append('.' + extension.lower())
  74. return new_extensions
  75. def get_all_filenames(path, extensions=None, is_valid_file=None):
  76. if (extensions is not None) and (is_valid_file is not None):
  77. raise ValueError("Both extensions and is_valid_file cannot "
  78. "be not None at the same time")
  79. if is_valid_file is None:
  80. if extensions is not None:
  81. if isinstance(extensions, str):
  82. extensions = [extensions]
  83. extensions = tuple(_normalize_extensions(extensions))
  84. def is_valid_file(filename):
  85. return filename.lower().endswith(extensions)
  86. else:
  87. def is_valid_file(filename):
  88. return True
  89. all_filenames = []
  90. path_ex = os.path.expanduser(path)
  91. for root, _, filenames in sorted(os.walk(path_ex, followlinks=True)):
  92. for filename in sorted(filenames):
  93. fullname = os.path.join(root, filename)
  94. if is_valid_file(fullname):
  95. all_filenames.append(fullname)
  96. return all_filenames
  97. def get_top_level_dirs(path, full_path=True):
  98. if path is None:
  99. path = os.getcwd()
  100. path_ex = os.path.expanduser(path)
  101. filenames = os.listdir(path_ex)
  102. if full_path:
  103. return [os.path.join(path_ex, item) for item in filenames
  104. if os.path.isdir(os.path.join(path_ex, item))]
  105. else:
  106. return [item for item in filenames
  107. if os.path.isdir(os.path.join(path_ex, item))]
  108. def get_top_level_files(path, full_path=True):
  109. if path is None:
  110. path = os.getcwd()
  111. path_ex = os.path.expanduser(path)
  112. filenames = os.listdir(path_ex)
  113. if full_path:
  114. return [os.path.join(path_ex, item) for item in filenames
  115. if os.path.isfile(os.path.join(path_ex, item))]
  116. else:
  117. return [item for item in filenames
  118. if os.path.isfile(os.path.join(path_ex, item))]
  119. def replace_invalid_filename_char(filename, new_char='_'):
  120. assert isinstance(new_char, str)
  121. control_chars = ''.join((map(chr, range(0x00, 0x20))))
  122. pattern = r'[\\/*?:"<>|{}]'.format(control_chars)
  123. return re.sub(pattern, new_char, filename)
  124. def copy_file(src, dst_dir, action_if_exist='rename'):
  125. """
  126. Args:
  127. src: source file path
  128. dst_dir: dest dir
  129. action_if_exist:
  130. None: same as shutil.copy
  131. rename: when dest file exists, rename it
  132. Returns:
  133. dest filename
  134. """
  135. src_basename = os.path.basename(src)
  136. src_stem, src_extname = os.path.splitext(src_basename)
  137. dst = os.path.join(dst_dir, src_basename)
  138. if action_if_exist is None:
  139. os.makedirs(dst_dir, exist_ok=True)
  140. shutil.copy(src, dst_dir)
  141. elif action_if_exist.lower() == 'rename':
  142. suffix = 2
  143. while os.path.exists(dst):
  144. dst_basename = '{} ({}){}'.format(src_stem, suffix, src_extname)
  145. dst = os.path.join(dst_dir, dst_basename)
  146. suffix += 1
  147. else:
  148. os.makedirs(dst_dir, exist_ok=True)
  149. shutil.copy(src, dst)
  150. else:
  151. raise ValueError('Invalid action_if_exist, got {}.'.format(action_if_exist))
  152. return dst
  153. def move_file(src, dst_dir, action_if_exist='rename'):
  154. """
  155. Args:
  156. src: source file path
  157. dst_dir: dest dir
  158. action_if_exist:
  159. None: same as shutil.move
  160. rename: when dest file exists, rename it
  161. Returns:
  162. dest filename
  163. """
  164. src_basename = os.path.basename(src)
  165. src_stem, src_extname = os.path.splitext(src_basename)
  166. dst = os.path.join(dst_dir, src_basename)
  167. if action_if_exist is None:
  168. os.makedirs(dst_dir, exist_ok=True)
  169. shutil.move(src, dst_dir)
  170. elif action_if_exist.lower() == 'rename':
  171. suffix = 2
  172. while os.path.exists(dst):
  173. dst_basename = '{} ({}){}'.format(src_stem, suffix, src_extname)
  174. dst = os.path.join(dst_dir, dst_basename)
  175. suffix += 1
  176. else:
  177. os.makedirs(dst_dir, exist_ok=True)
  178. shutil.move(src, dst)
  179. else:
  180. raise ValueError('Invalid action_if_exist, got {}.'.format(action_if_exist))
  181. return dst
  182. def rename_file(src, dst, action_if_exist='rename'):
  183. """
  184. Args:
  185. src: source file path
  186. dst: dest file path
  187. action_if_exist:
  188. None: same as os.rename
  189. rename: when dest file exists, rename it
  190. Returns:
  191. dest filename
  192. """
  193. if dst == src:
  194. return dst
  195. if action_if_exist is None:
  196. os.rename(src, dst)
  197. elif action_if_exist.lower() == 'rename':
  198. dirname, basename = os.path.split(dst)
  199. stem, extname = os.path.splitext(basename)
  200. suffix = 2
  201. while os.path.exists(dst):
  202. new_basename = '{} ({}){}'.format(stem, suffix, extname)
  203. dst = os.path.join(dirname, new_basename)
  204. suffix += 1
  205. os.makedirs(dirname, exist_ok=True)
  206. os.rename(src, dst)
  207. else:
  208. raise ValueError('Invalid action_if_exist, got {}.'.format(action_if_exist))
  209. return dst