utils_fs.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import os
  2. import shutil
  3. def get_path_stem(path):
  4. """
  5. References:
  6. `std::filesystem::path::stem` since C++17
  7. """
  8. return os.path.splitext(os.path.basename(path))[0]
  9. def replace_path_stem(path, new_stem):
  10. dirname, basename = os.path.split(path)
  11. stem, extname = os.path.splitext(basename)
  12. if isinstance(new_stem, str):
  13. return os.path.join(dirname, new_stem + extname)
  14. elif hasattr(new_stem, '__call__'):
  15. return os.path.join(dirname, new_stem(stem) + extname)
  16. else:
  17. raise ValueError('Unsupported Type!')
  18. def get_path_extension(path):
  19. """
  20. References:
  21. `std::filesystem::path::extension` since C++17
  22. Notes:
  23. Not fully consistent with `std::filesystem::path::extension`
  24. """
  25. return os.path.splitext(os.path.basename(path))[1]
  26. def replace_path_extension(path, new_extname=None):
  27. """Replaces the extension with new_extname or removes it when the default value is used.
  28. Firstly, if this path has an extension, it is removed. Then, a dot character is appended
  29. to the pathname, if new_extname is not empty or does not begin with a dot character.
  30. References:
  31. `std::filesystem::path::replace_extension` since C++17
  32. """
  33. filename_wo_ext = os.path.splitext(path)[0]
  34. if new_extname == '' or new_extname is None:
  35. return filename_wo_ext
  36. elif new_extname.startswith('.'):
  37. return ''.join([filename_wo_ext, new_extname])
  38. else:
  39. return '.'.join([filename_wo_ext, new_extname])
  40. def makedirs(name, mode=0o755):
  41. """
  42. References:
  43. mmcv.mkdir_or_exist
  44. """
  45. if name == '':
  46. return
  47. name = os.path.expanduser(name)
  48. os.makedirs(name, mode=mode, exist_ok=True)
  49. def listdirs(paths, path_sep=None, full_path=True):
  50. """Enhancement on `os.listdir`
  51. """
  52. assert isinstance(paths, (str, tuple, list))
  53. if isinstance(paths, str):
  54. path_sep = path_sep or os.path.pathsep
  55. paths = paths.split(path_sep)
  56. all_filenames = []
  57. for path in paths:
  58. path_ex = os.path.expanduser(path)
  59. filenames = os.listdir(path_ex)
  60. if full_path:
  61. filenames = [os.path.join(path_ex, filename) for filename in filenames]
  62. all_filenames.extend(filenames)
  63. return all_filenames
  64. def get_all_filenames(dirname, extensions=None, is_valid_file=None):
  65. if (extensions is not None) and (is_valid_file is not None):
  66. raise ValueError("Both extensions and is_valid_file cannot "
  67. "be not None at the same time")
  68. if is_valid_file is None:
  69. if extensions is not None:
  70. def is_valid_file(filename):
  71. return filename.lower().endswith(extensions)
  72. else:
  73. def is_valid_file(filename):
  74. return True
  75. all_filenames = []
  76. dirname = os.path.expanduser(dirname)
  77. for root, _, filenames in sorted(os.walk(dirname, followlinks=True)):
  78. for filename in sorted(filenames):
  79. path = os.path.join(root, filename)
  80. if is_valid_file(path):
  81. all_filenames.append(path)
  82. return all_filenames
  83. def copy_file(src, dst_dir, action_if_exist=None):
  84. """
  85. Args:
  86. src: source file path
  87. dst_dir: dest dir
  88. action_if_exist:
  89. None: when dest file exists, no operation
  90. overwritten: when dest file exists, overwritten
  91. rename: when dest file exists, rename it
  92. Returns:
  93. dest file basename
  94. """
  95. src_basename = os.path.basename(src)
  96. dst_fullname = os.path.join(dst_dir, src_basename)
  97. if action_if_exist is None:
  98. if not os.path.exists(dst_fullname):
  99. makedirs(dst_dir)
  100. shutil.copy(src, dst_dir)
  101. elif action_if_exist.lower() == 'overwritten':
  102. makedirs(dst_dir)
  103. # shutil.copy
  104. # If dst is a directory, a file with the same basename as src is
  105. # created (or overwritten) in the directory specified.
  106. shutil.copy(src, dst_dir)
  107. elif action_if_exist.lower() == 'rename':
  108. src_stem, src_extname = os.path.splitext(src_basename)
  109. suffix = 2
  110. while os.path.exists(dst_fullname):
  111. dst_basename = '{} ({}){}'.format(src_stem, suffix, src_extname)
  112. dst_fullname = os.path.join(dst_dir, dst_basename)
  113. suffix += 1
  114. else:
  115. makedirs(dst_dir)
  116. shutil.copy(src, dst_fullname)
  117. else:
  118. raise ValueError('Invalid action_if_exist, got {}.'.format(action_if_exist))
  119. return os.path.basename(dst_fullname)
  120. def move_file(src, dst_dir, action_if_exist=None):
  121. """
  122. Args:
  123. src: source file path
  124. dst_dir: dest dir
  125. action_if_exist:
  126. None: when dest file exists, no operation
  127. overwritten: when dest file exists, overwritten
  128. rename: when dest file exists, rename it
  129. Returns:
  130. dest file basename
  131. """
  132. src_basename = os.path.basename(src)
  133. dst_fullname = os.path.join(dst_dir, src_basename)
  134. if action_if_exist is None:
  135. if not os.path.exists(dst_fullname):
  136. makedirs(dst_dir)
  137. shutil.move(src, dst_dir)
  138. elif action_if_exist.lower() == 'overwritten':
  139. if os.path.exists(dst_fullname):
  140. os.remove(dst_fullname)
  141. makedirs(dst_dir)
  142. # shutil.move
  143. # If the destination already exists but is not a directory,
  144. # it may be overwritten depending on os.rename() semantics.
  145. shutil.move(src, dst_dir)
  146. elif action_if_exist.lower() == 'rename':
  147. src_stem, src_extname = os.path.splitext(src_basename)
  148. suffix = 2
  149. while os.path.exists(dst_fullname):
  150. dst_basename = '{} ({}){}'.format(src_stem, suffix, src_extname)
  151. dst_fullname = os.path.join(dst_dir, dst_basename)
  152. suffix += 1
  153. else:
  154. makedirs(dst_dir)
  155. shutil.move(src, dst_fullname)
  156. else:
  157. raise ValueError('Invalid action_if_exist, got {}.'.format(action_if_exist))
  158. return os.path.basename(dst_fullname)