import os import re import time import uuid import rarfile import zipfile import shutil import difflib import subprocess from pathlib import Path m_dbgLevel = 0 listDbgStr = [] # def IsEmptyStr(string): temp = f"{string}" return 0 == len(temp.strip()) # def GetCurrentTime(): # 현재 시간을 구하고 구조체로 변환 current_time_struct = time.localtime() # 구조체에서 연, 월, 일, 시간, 분, 초를 추출 year = current_time_struct.tm_year month = current_time_struct.tm_mon day = current_time_struct.tm_mday hour = current_time_struct.tm_hour minute = current_time_struct.tm_min second = current_time_struct.tm_sec strRet = (f"{year}/{month}/{day}_{hour}:{minute}:{second}") return strRet #for debug def DbgOut(strInput, bPrint = False): strMsg = (f"{GetCurrentTime()} : {strInput}") listDbgStr.append(strMsg) if True == bPrint: print(strMsg) def printDbgMessages(): for line in listDbgStr: print(line) # 입력된 경로의 자식 폴더를 찾아 반환한다. # 반환하는 리스트는 리커시브 - 손자, 증손자 폴더까지 전부 포함한다 def ListSubDirectories(root_dir): subdirectories = [] # root_dir에서 하위 디렉토리 및 파일 목록을 얻음 for dirpath, dirnames, filenames in os.walk(root_dir): # 하위 디렉토리 목록을 반복하며 하위 디렉토리만 추출 for dirname in dirnames: path = os.path.join(dirpath, dirname) if True == IsFinalFolder(path): subdirectories.append(path) return subdirectories # 자식 폴더를 구해온다. 직계 자식만 def ListChildDirectories(pathDir): listRet = [] for name in os.listdir(pathDir): pathChild = os.path.join(pathDir, name) if os.path.isdir(pathChild): listRet.append(pathChild) return listRet # 파일목록만 구해온다. 자식 폴더에 있는건 무시. def ListContainFiles(pathDir): listRet = [] for name in os.listdir(pathDir): pathChild = os.path.join(pathDir, name) if not os.path.isdir(pathChild): listRet.append(pathChild) return listRet def ListFileExtRcr(pathTrg, listExt): listRet= [] if False == isinstance(listExt, list): print("ext must list") return # pathTrg의 하위 디렉토리 및 파일 목록을 얻음 for dirpath, dirnames, filenames in os.walk(pathTrg): for file in filenames: extTmp = GetExtStr(file) if extTmp.lower() in listExt and not file.startswith('.'): listRet.append(os.path.join(dirpath, file)) return listRet # 입력된 패스에서 부모 폴더를 찾는다. 0 은 자기자신 1은 부모, 숫자대로 위로. def GetParentDirName(FullPath, nUp): parts = FullPath.split(os.sep) nTrgIdx = 0 if nUp < len(parts): nTrgIdx = len(parts) -nUp -1 elif nUp < 0: nTrgIdx = len(parts) - 1 else: nTrgIdx = 0 return parts[nTrgIdx] # 입력된 경로가 자식 폴더를 가지고 있는지 판단한다.- 최종 폴더인지 여부 # 자식이 없으면 True, 자식이 있으면 False def IsFinalFolder(path): bRet = True contents = os.listdir(path) for item in contents: if True == os.path.isdir(item): bRt = False break return bRet; # 어떤 경로 안에서 특정 확장자의 파일을 뽑아내어 그 리스트를 반환한다. def FindFileFromExt(path, ext): bDot = False if 0 <= ext.find('.'): bDot = True listRet = [] if False == os.path.exists(path): return listRet contents = os.listdir(path) for item in contents: if True == os.path.isdir(item): continue extItem = GetExtStr(item, bDot) if extItem.lower() == ext.lower(): listRet.append(item) return listRet # 파일 이름에서 확장자를 뽑아낸다. True : '.' 을 포함한다. def GetExtStr(file_path, bDot = True): retStr = "" # 파일 경로에서 마지막 점을 찾아 확장자를 추출 last_dot_index = file_path.rfind('.') if last_dot_index == -1: retStr = "" # 점이 없는 경우 확장자가 없음 else: if True == bDot: retStr = file_path[last_dot_index:] else: retStr = file_path[last_dot_index+1:] return retStr # 문자열에 포함된 단어를 지운다. def RmvSubString(mainString, subString): # 문자열에서 부분 문자열의 인덱스를 찾습니다. strIdx = mainString.find(subString) if strIdx == -1: # 부분 문자열이 존재하지 않으면 그대로 반환합니다. return mainString endIdx = strIdx + len(subString) # 부분 문자열을 제거하고 새로운 문자열을 반환합니다. return mainString[:strIdx] + mainString[endIdx:] def ExtractZIP(zip_file, extract_to): with zipfile.ZipFile(zip_file, 'r') as zf: zf.extractall(extract_to) # def CreateZIP(output_zip, *files): with zipfile.ZipFile(output_zip, 'w') as zf: for file in files: pathTemp = os.path.join('root', os.path.basename(file)) zf.write(file, pathTemp) bRet = False if os.path.exists(output_zip): bRet = True return bRet # 파일 리스트에 들어있는 파일만 골라서 압축을 합니다. 상대경로를 제거하는게 기본값. def CreateZIPShell(zipName, *files, bRmvRPath = True): command = "zip " if True == bRmvRPath: command += "-j " command += f"\"{zipName}\" " # 이중 리스트인 이유를 모르겠다. for file in files: strTemp = "" if isinstance(file, list): strTemp = ' '.join(file) else: strTemp = f"\"{file}\" " command += strTemp # for item in file: # command += f"\"{item}\" " result = subprocess.run(command, shell=True, capture_output=True, text=True) bRet = False if 0 == result.returncode: bRet = True return bRet # 특정 확장자만 쉘을 이용해서 압축한다 def CreateZIPShExt(zipName, TrgExt): command = f"zip -j {zipName} *.{TrgExt}" result = subprocess.run(command, shell=True, capture_output=True, text=True) bRet = False if 0 == result.returncode: bRet = True return bRet # 압축 파일 내의 모든 파일 및 디렉토리 목록 가져오기 def GetZipContentList(path): if None == path or not os.path.isfile(path): return [] listRet = [] with zipfile.ZipFile( path , 'r') as zip_file: listRet = zip_file.namelist() return listRet def GetZippedFileByte(pathZip, FileName): if None == pathZip or not os.path.isfile(pathZip): return None retBytes = None with zipfile.ZipFile( pathZip , 'r') as zip_file: if not FileName in zip_file.namelist(): return None with zip_file.open(FileName) as file: retBytes = file.read() return retBytes # JSON 을 트리 구조로 출력한다. def PrintJSONTree(data, indent=0): if isinstance(data, dict): for key, value in data.items(): print(' ' * indent + str(key)) PrintJSONTree(value, indent + 1) elif isinstance(data, list): for item in data: PrintJSONTree(item, indent) else: print(' ' * indent + str(data)) def IsPathWithin(base_path: str, target_path: str) -> bool: base = Path(base_path).resolve() target = Path(target_path).resolve() return target.is_relative_to(base) # 랜덤 UUID 생성 def UUIDGenRandom(): random_uuid = uuid.uuid4() return random_uuid # 이름을 기반으로 UUID 생성 def UUIDGenName(SeedName): namespace_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, SeedName) return namespace_uuid def GetTextInBrakets(text): return re.findall(r'\[(.*?)\]', text)