기술 · 실용 가이드
FileZilla MLSD 목록을 CSV로 바꾸면서 파일명 보존하기
이름의 쉼표·세미콜론·유효한 공백을 남기고 크기 누락과0을 구별하며 디렉터리 항목도 오프라인 복사본에 보존합니다.

FileZilla 원시 디렉터리 목록을 복사했더라도 모든 세미콜론을 쉼표로 바꾸는 것은 올바른 CSV 변환이 아닙니다. 세미콜론은 파일명에 들어갈 수 있고 이름의 쉼표나 따옴표는 올바른 CSV 인용 처리가 필요합니다.
이 방법은 한 번 수집한 MLSD 데이터 블록을 오프라인으로 변환합니다. 표시된 이름·항목 종류·원래 속성을 보존하지만 파일 다운로드, 서버 변경, 재귀 목록 생성이나 수집 목록의 완전성 증명은 하지 않습니다.
복사본이 MLSD 데이터인지 먼저 확인하기
기존에 허가받은 FTP 또는 FTPS 연결을 사용합니다. FileZilla 원래 지원 논의는 디버그 설정의 원시 목록 표시 방법을 설명합니다. 사용 중인 버전에 해당 항목이 있을 때만 켜고 대상 폴더만 새로 고칩니다. 로그에서 MLSD 명령과 정상 완료를 확인하고 원격 폴더와 수집 시각을 별도로 기록하세요. 현재 FileZilla 화면은 시험하지 않았습니다.
그 정상 목록 한 번의 데이터 항목만 UTF-8 일반 텍스트 mlsd.txt로 복사합니다. 예시는 type=file;size=926; image.jpg입니다. 앞뒤 공백을 포함해 이름의 모든 문자를 보존하세요. 변환기는 원시 항목이나 정확한 영어 접두사 Listing:와 뒤의 공백 하나를 받습니다. 타임스탬프, 번역된 접두사, 상태 메시지나 빈 구분 줄은 넣지 않습니다.
Unix/DOS LIST 텍스트, SFTP 목록, CLI JSON 객체, 디코딩하지 않은 바이트나 명백한 깨진 글자이면 중단하세요. 인코딩을 추측하거나 원래 로그를 덮어쓰지 마세요. 현재 FileZilla CLI는 구조화된 JSON도 제공하므로 이미 CLI가 있는 사용자에게 유효한 별도 방법이지만 이 변환기의 입력은 아닙니다.
Linux Bash 터미널에서 복사본 변환하기
Linux Bash 터미널에서 Python 3.9 이상을 쓰고 mlsd.txt가 있는 폴더로 이동합니다. 다음 명령을 곧은 따옴표와 역슬래시를 보존한 한 줄로 복사하고 새 출력 이름을 선택하세요. 모든 입력을 검증한 뒤 mlsd.csv를 배타적으로 생성하며 입력은 바꾸지 않습니다.
python3 -c "exec('import csv\\nimport sys\\n\\nrows = []\\nwith open(sys.argv[1], encoding=\"utf-8-sig\", newline=\"\") as source:\\n for number, raw in enumerate(source, 1):\\n line = raw.removesuffix(\"\\\\n\").removesuffix(\"\\\\r\")\\n if line.startswith(\"Listing: \"):\\n line = line[len(\"Listing: \"):]\\n facts, separator, name = line.partition(\" \")\\n if not separator or not name or (facts and not facts.endswith(\";\")):\\n raise ValueError(f\"Line {number}: expected one MLSD data entry\")\\n values = {}\\n for fact in facts[:-1].split(\";\") if facts else []:\\n key, equals, value = fact.partition(\"=\")\\n key = key.lower()\\n if not key or not equals or key in values or any(c.isspace() for c in fact):\\n raise ValueError(f\"Line {number}: malformed or duplicate fact\")\\n values[key] = value\\n size = values.get(\"size\", \"\")\\n if \"size\" in values and not (size.isascii() and size.isdecimal()):\\n raise ValueError(f\"Line {number}: invalid size\")\\n rows.append([name, values.get(\"type\", \"\"), size, values.get(\"modify\", \"\"), facts])\\nif not rows:\\n raise ValueError(\"No MLSD records: do not assume an empty directory\")\\nwith open(sys.argv[2], \"x\", encoding=\"utf-8-sig\", newline=\"\") as destination:\\n writer = csv.writer(destination)\\n writer.writerow([\"name\", \"type\", \"size_bytes\", \"modify_raw\", \"facts_raw\"])\\n writer.writerows(rows)\\nprint(len(rows), \"MLSD records exported; includes any directory entries\")\\n')" "mlsd.txt" "mlsd.csv"
다섯 열은 name, type, size_bytes, modify_raw, facts_raw입니다. 첫 공백은 속성과 이름의 경계이고 이후 공백과 이름의 세미콜론은 그대로 남습니다. 속성 이름은 대소문자를 구별하지 않고 비교하지만 facts_raw에는 원래 철자·순서·값이 남습니다. 누락된 크기는 빈칸이고 반환된0은0으로 남습니다.
텍스트로 가져오고 수집 기록 검증하기
LibreOffice Calc에서 CSV를 열고 UTF-8, 쉼표 구분, 곧은 큰따옴표 문자열 구분을 선택합니다. 구분자 병합, 공백 제거, 수식 평가를 끄고 다섯 열을 모두 텍스트로 지정하세요. 가져오기 창이 생략되면 열 때 필터 설정 편집을 켭니다. =로 시작하는 이름이 수식 대신 문자 그대로인지 확인합니다.
출력 수와 머리글을 제외한 파싱된 CSV 데이터 행 수를 비교하고 여러 정확한 이름·속성을 저장한 텍스트와 대조하세요. cdir, pdir, dir 기록은 남깁니다. 디렉터리 항목이므로 기록 수는 파일 수가 아닙니다. type 누락은 알 수 없음으로 남습니다. 서버는 한 경로에 여러 종류를 반환할 수 있어 중복 이름도 보존하며 자동 중복 제거를 하지 않습니다.
오류와 메타데이터의 한계 이해하기
빈 입력, 잘못된 기록, 중복 속성 키나 유효하지 않은 제공 크기는 출력 생성 전에 중단됩니다. 대상이 이미 있다면 새 이름을 선택하세요. 디스크·쓰기 실패는 부분 CSV를 남길 수 있으니 해당 출력을 버리고 새 이름으로 다시 실행한 뒤 파싱된 행을 비교합니다. 서버에 실제로 항목이 없어도 이 변환기는 빈 목록을 인증하지 않습니다.
크기는 서버가 보고한 메타데이터이며 근사치일 수 있습니다. 누락은0이 아니고 디렉터리 크기도 재귀 합계가 아닙니다. modify_raw는 변환하지 않은 서버 텍스트로 내용이 같다는 증거가 아닙니다. 복사할 때 빠진 문법상 정상 행은 탐지할 수 없습니다. 정상 수집을 직접 확인하고 원래 로그를 보관하며 의도한 메타데이터만 공유하세요.
이 정확한 Bash 명령으로17개 합성 하위 프로세스 검사를 실행해 문장부호, 유니코드, 유효한 공백, 선택 속성, 디렉터리 종류, 잘못된 입력과 덮어쓰기 거부를 확인했습니다. 실제 FileZilla·FTP 서버·Calc 화면이나 Windows·macOS는 시험하지 않았습니다. 두 일러스트는 가상 예이며 화면 캡처가 아닙니다.
