1. 학교 PC와 연구실의 고질병: "수천 개의 파일이 뒤섞여 마비된 Downloads 폴더"
현대 웹 브라우저(Chrome, Edge, Whale)는 사용자가 인터넷에서 파일을 내려받을 때 기본적으로 %USERPROFILE%\Downloads 단일 폴더에 모든 파일을 쏟아붓습니다. 이로 인해 교원과 공공기관 실무자들은 다음과 같은 치명적 생산성 저하에 시달립니다:
- 탐색기 응답 없음 (I/O 병목): 단일 디렉터리에 수천 개의 파일이 몰리면 Windows Explorer는 메타데이터 추출(아이콘 썸네일, 파일 속성 등)을 위해 디스크 I/O를 대량 소모하며 폴더 진입 시 '응답 없음'을 띄웁니다.
- 정보 분실 및 버전 혼선: 동일한 이름의 공문 서식이나 시험 문제가 중복 다운로드되면서 어떤 파일이 최신인지 분간하지 못해 이전 버전의 문서를 결재 올리는 행정 사고가 발생합니다.
- 정리 도구의 부작용: 시중의 무료 파일 정리 툴들은 사용자가 원치 않는 임의의 폴더 구조를 강제하거나, 백그라운드에서 주기적으로 폴더 전체를 폴링(Polling)하며 배터리와 CPU를 과도하게 갉아먹습니다.
2. 브라우저 다운로드의 맹점: ".crdownload 미완료 상태와 백신 I/O 락(Lock) 충돌"
단순히 "새 파일이 생기면 확장자에 따라 폴더로 이동(Move)시킨다"는 생각으로 스크립트를 작성하면 100% 실패합니다. 브라우저의 다운로드 파이프라인은 생각보다 매우 복잡하기 때문입니다:
주목할 기술적 맹점은 다음과 같습니다:
- 임시 확장자 잠김: Chrome/Edge는 다운로드 도중
.crdownload, Firefox는.part, 다운로드 매니저는.tmp확장자로 디스크에 임시 파일을 쓰고 있습니다. 이때 운영체제 레벨의 독점 쓰기 락(Exclusive Write Lock)이 걸려 있어 접근 시IOException이 터집니다. - 완료 시점의 본질은 '이름 변경(Rename)': 브라우저는 다운로드가 끝나면 새 파일을 만드는 것이 아니라, 임시 파일의 이름을 최종 파일명으로 바꿉니다(
MoveFileExAPI). 따라서Created이벤트만 수신하는 감시기는 다운로드 완료를 감지하지 못합니다. - 백신 프로그램(V3, Windows Defender)의 간섭: 파일 이름이 변경되는 순간 백신이 실시간 검사를 위해 파일을 수백 밀리초 동안 잠급니다. 이 타이밍에 파일 이동을 시도하면 "다른 프로세스가 사용 중이므로 파일에 액세스할 수 없습니다"라는 오류가 발생합니다.
3. FileSystemWatcher의 함정 격파: "Created와 Renamed 듀얼 훅 & 15초 적응형 재시도 루프"
ZeliDesk의 SweepService는 이 문제를 완벽하게 해결하기 위해 듀얼 이벤트 훅(Dual-Event Hook)과 15회 적응형 재시도 큐를 탑재했습니다:
public void Start()
{
if (IsRunning || string.IsNullOrEmpty(TargetDirectory)) return;
if (!Directory.Exists(TargetDirectory)) return;
_watcher = new FileSystemWatcher(TargetDirectory)
{
NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime,
EnableRaisingEvents = true,
IncludeSubdirectories = false // ★ 핵심: 무한 재귀 이동 방지
};
// 브라우저 다운로드 완료 사이클을 완벽히 포착하기 위해 Created와 Renamed 모두 수신
_watcher.Created += OnFileDetected;
_watcher.Renamed += OnFileDetected;
IsRunning = true;
}
private async void OnFileDetected(object sender, FileSystemEventArgs e)
{
await Task.Run(async () =>
{
try
{
string ext = Path.GetExtension(e.FullPath);
if (string.IsNullOrEmpty(ext)) return;
// 브라우저 진행 중 임시 파일은 즉시 필터링하여 불필요한 I/O 낭비 방지
if (ext.Equals(".crdownload", StringComparison.OrdinalIgnoreCase) ||
ext.Equals(".tmp", StringComparison.OrdinalIgnoreCase)) return;
var rule = Rules.FirstOrDefault(r => r.Extensions.Contains(ext));
if (rule == null) return; // 등록된 규칙이 아니면 이동하지 않고 원본 유지
// 백신 검사나 브라우저 락 해제를 대기하기 위한 15초(1초 간격 × 15회) 적응형 재시도 루프
for (int i = 0; i < 15; i++)
{
var result = TryMoveFile(e.FullPath, rule.TargetFolderName);
if (result == MoveResult.Success || result == MoveResult.FatalError_Skip)
{
return; // 성공했거나 복구 불가능한 에러 시 즉시 종료
}
await Task.Delay(1000); // 1초 후 재시도
}
}
catch (Exception ex)
{
LogEmitted?.Invoke($"[ZeliSweep] Error: {ex.Message}");
}
});
}
이 아키텍처 덕분에 사용자가 10GB짜리 대용량 설치 파일이나 1MB짜리 한글 문서를 다운로드하더라도, 브라우저가 완전히 쓰기를 끝마치고 백신 검사가 완료되는 찰나를 정확히 포착하여 안전하게 분류를 완료합니다.
4. 무한 재귀 이동 루프 원천 차단: IncludeSubdirectories = false와 대상 폴더 격리
파일 감시 프로그램을 만들 때 발생하기 쉬운 가장 치명적인 버그는 무한 이벤트 캐스케이드(Event Cascade Loop)입니다.
IncludeSubdirectories = true로 설정되어 있다면 어떤 일이 벌어질까요?Downloads\수업자료.pdf가 생성되어 Downloads\Documents\수업자료.pdf로 이동하는 순간, Documents 서브 폴더 안에서 또다시 Created 이벤트가 발행됩니다. 감시기는 이를 또 새 파일로 감지하여 Downloads\Documents\Documents\수업자료.pdf로 끝없이 하위 폴더를 파고들며 디스크를 잠식합니다."
ZeliSweep은 커널 레벨에서 IncludeSubdirectories = false를 강제함으로써, 오직 다운로드 루트 디렉터리에 처음 안착한 1차 파일들만 필터링합니다. 이미 분류 폴더 안으로 이동한 파일은 이벤트 트리거 대상에서 물리적으로 격리되므로 무한 루프 가능성이 0%입니다.
5. 동명 파일 덮어쓰기 방지 원자적 인덱싱(FileName (1).ext)과 7대 확장자 매트릭스
학교나 관공서에서는 '기안서_최종.hwp', '성적집계표.xlsx'처럼 매번 동일한 이름으로 배포되는 서식이 많습니다. 만약 새 파일을 분류 폴더로 옮길 때 단순 덮어쓰기(Overwrite)를 수행하면, 기존에 작업해 둔 소중한 문서가 증발해 버립니다.
ZeliSweep의 TryMoveFile 메서드는 Windows 탐색기 표준과 완벽히 호환되는 원자적 인덱싱 알고리즘을 내장하고 있습니다:
private MoveResult TryMoveFile(string sourceFile, string targetSubFolder)
{
try
{
if (!File.Exists(sourceFile)) return MoveResult.Success;
string destDir = Path.Combine(TargetDirectory, targetSubFolder);
if (!Directory.Exists(destDir)) Directory.CreateDirectory(destDir);
string fileName = Path.GetFileName(sourceFile);
string nameOnly = Path.GetFileNameWithoutExtension(fileName);
string ext = Path.GetExtension(fileName);
string destFile = Path.Combine(destDir, fileName);
// 안전장치: 이미 동일한 이름의 파일이 존재한다면 '(1)', '(2)' 형태로 고유 이름 자동 생성
int counter = 1;
while (File.Exists(destFile))
{
string newName = $"{nameOnly} ({counter}){ext}";
destFile = Path.Combine(destDir, newName);
counter++;
}
File.Move(sourceFile, destFile);
LogEmitted?.Invoke($"[분류됨] {fileName} ➔ {targetSubFolder} 이동 완료!");
return MoveResult.Success;
}
catch (IOException)
{
// 파일이 타 프로세스(브라우저/백신)에 의해 락 상태임 -> Retry 루프로 복귀
return MoveResult.Locked_Retry;
}
catch (Exception ex)
{
return MoveResult.FatalError_Skip;
}
}
교육·행정 현장 맞춤형 7대 분류 규칙 매트릭스
ZeliSweep은 학교 현장의 디지털 교과서 제작, 행정 업무, 개발 실습에 최적화된 7개 카테고리 매트릭스를 기본 탑재하고 있습니다:
| 카테고리 | 대상 하위 폴더 | 지원 확장자 매트릭스 | 현장 활용 목적 |
|---|---|---|---|
| 문서 (Documents) | Documents |
.hwp, .hwpx, .pdf, .docx, .doc, .xlsx, .xls, .pptx, .ppt, .txt, .csv |
NEIS 공문서, 시험지, 성적부, 강의 계획서 자동 보존 |
| 설치 및 압축 | Installers & Archives |
.exe, .msi, .msix, .zip, .7z, .rar, .iso, .tar, .gz |
각종 교육용 소프트웨어 셋업 및 대용량 압축 데이터 정리 |
| 이미지 미디어 | Images |
.png, .jpg, .jpeg, .gif, .webp, .svg, .bmp, .psd, .ai, .heic |
학급 앨범, 캡처 판서, 그래픽 소스 고화질 정리 |
| 동영상 미디어 | Videos |
.mp4, .mkv, .mov, .avi, .wmv, .webm |
원격 수업 녹화본, 유튜브 다운로드 교육 영상 정리 |
| 오디오 사운드 | Audio |
.mp3, .wav, .flac, .aac, .ogg, .m4a |
영어 듣기 평가 자료, 행사 배경 음악 파일 분류 |
| 코드 및 개발 | Codes & Dev |
.cs, .py, .js, .ts, .html, .css, .cpp, .json, .xml, .yaml, .sql |
SW/AI 정보 교육 실습 코드 및 학생 과제 제출물 정리 |
| 3D 및 디자인 | Design & 3D |
.blend, .fbx, .obj, .stl, .fig |
3D 프린터 실습 모델링(.stl) 및 메타버스 그래픽 에셋 |
6. 기존 서드파티 정리기 vs Windows 저장 공간 센스 vs ZeliDesk ZeliSweep 심층 비교
| 비교 항목 | CCleaner / 고클린 등 기존 정리기 | Windows 저장 공간 센스 (Storage Sense) | ZeliDesk ZeliSweep (엔지니어링 백서) |
|---|---|---|---|
| 분류 동작 방식 | 파일 삭제 위주 (오래된 다운로드 강제 제거) | 30일 이상 미사용 파일 무조건 영구 삭제 | 무삭제 100% 보존: 확장자별 지능형 자동 정돈 |
| 실시간 감지 여부 | 수동 실행 필요 (배치 파일 방식) | 일/주 단위 백그라운드 주기적 검사 | 다운로드 완료 즉시 0초 실시간 자동 이동 |
| 다운로드 락 충돌 방어 | 지원 안 함 (접근 에러 시 건너뛰거나 실패) | 해당 없음 | 15초 적응형 재시도 큐 & 브라우저 임시 파일 격리 |
| 동명 파일 보호 | 단순 덮어쓰기로 원본 훼손 위험 | 해당 없음 | FileName (1).ext 무손실 원자적 인덱싱 |
| CPU 및 메모리 부하 | 주기적 폴링 시 3~10% 점유 | 시스템 프로세스 상시 점유 | 커널 이벤트 기반: 유휴 시 CPU 0.01% 미만 |
| 보안 및 광고 | 외부 애드웨어 및 원격 텔레메트리 포함 | Microsoft 원격 진단 데이터 전송 | 100% 로컬 오프라인 무설치 (Zero Telemetry) |
7. 결론: "다운로드 클릭 즉시 제자리를 찾아가는 무소음·무간섭 데스크톱 거버넌스"
선생님이나 공공 연구원들이 컴퓨터를 다루면서 가장 많은 피로를 느끼는 순간은 정작 복잡한 작업을 할 때가 아니라, 방금 내려받은 파일 하나를 찾기 위해 스크롤을 끝없이 내리며 헤맬 때입니다.
ZeliDesk의 ZeliSweep은 화려하게 사용자의 시선을 빼앗지 않습니다. 백그라운드에서 조용히 숨 쉬며 Windows OS 커널의 파일 변경 통보를 수신하고, 브라우저와 백신의 락 상태를 섬세하게 어루만지며 모든 파일을 완벽한 제자리로 인도합니다. 극도의 안정성과 파일 무손실 원칙을 타협하지 않는 것—ZeliDesk가 추구하는 데스크톱 거버넌스 엔지니어링의 정수입니다.