File System Access API ์ข ํฉ ๊ฐ์ด๋๋ก ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฏธ๋๋ฅผ ํ์ํ์ธ์. ๋ธ๋ผ์ฐ์ ์์ ์ง์ ๋ก์ปฌ ํ์ผ ๋ฐ ๋๋ ํ ๋ฆฌ ๋ณ๊ฒฝ ์ฌํญ์ ๋ชจ๋ํฐ๋งํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ฐ๊ณ , ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ฅผ ์ํ ์ค์ ์์ , ๋ชจ๋ฒ ์ฌ๋ก, ์ฑ๋ฅ ํ์ ํ์ธํ์ธ์.
์ค์๊ฐ ํ๋ก ํธ์๋ ์ญ๋ ๊ฐํ: ํ์ผ ์์คํ ๋๋ ํ ๋ฆฌ ๊ฐ์ ์ฌ์ธต ๋ถ์
๋ก์ปฌ ๋์คํฌ์ ํ๋ก์ ํธ ํด๋์ ๋ณ๊ฒฝ ์ฌํญ์ ์ ์ฉํ๋ฉด ์ฆ์ ๋ฐ์๋๋ ์น ๊ธฐ๋ฐ ์ฝ๋ ์๋ํฐ๋ฅผ ์์ํด ๋ณด์ธ์. ์นด๋ฉ๋ผ์์ ์ ์ด๋ฏธ์ง๋ฅผ ์ถ๊ฐํ๋ฉด ์๋์ผ๋ก ์ ๋ฐ์ดํธ๋๋ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ์ฌ์ง ๊ฐค๋ฌ๋ฆฌ๋ฅผ ๋ ์ฌ๋ ค ๋ณด์ธ์. ๋๋ ๋ก์ปฌ ๋ก๊ทธ ํ์ผ์ด ์ ๋ฐ์ดํธ๋ ๋ ์ค์๊ฐ์ผ๋ก ์ฐจํธ๋ฅผ ๋ค์ ๊ทธ๋ฆฌ๋ ๋ฐ์ดํฐ ์๊ฐํ ๋๊ตฌ๋ฅผ ์๊ฐํด ๋ณด์ธ์. ์์ญ ๋ ๋์ ๋ก์ปฌ ํ์ผ ์์คํ ๊ณผ์ ์ด๋ฌํ ์์ค์ ํตํฉ์ ๋ค์ดํฐ๋ธ ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ ๋ฌผ์ด์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๋ ๋ณด์์์ ์ด์ ๋ก ์๋๋ฐ์ค ์์์ ์์ ํ ๊ฑฐ๋ฆฌ๋ฅผ ์ ์งํด์ผ ํ์ต๋๋ค.
์ค๋๋ , ๊ทธ ํจ๋ฌ๋ค์์ ๊ทน์ ์ผ๋ก ๋ณํํ๊ณ ์์ต๋๋ค. ์ต์ ๋ธ๋ผ์ฐ์ API ๋๋ถ์ ์น๊ณผ ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ์ ๊ฒฝ๊ณ๊ฐ ๋ชจํธํด์ง๊ณ ์์ต๋๋ค. ์ด๋ฌํ ๋ณํ๋ฅผ ์ด๋๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๋๊ตฌ ์ค ํ๋๋ File System Access API์ ๋๋ค. ์ด API๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ์์ ๋ก์ปฌ ํ์ผ ๋ฐ ๋๋ ํ ๋ฆฌ์ ๋ณ๊ฒฝ ์ฌํญ์ ์ฝ๊ณ , ์ฐ๊ณ , ๊ทธ๋ฆฌ๊ณ ์ด ๊ธ์ ํต์ฌ ์ฃผ์ ์ธ ๋ชจ๋ํฐ๋งํ ์ ์๋ ๊ถํ ๊ธฐ๋ฐ์ ์ ๊ทผ์ ํ์ฉํฉ๋๋ค. ๋๋ ํ ๋ฆฌ ๊ฐ์ ๋๋ ํ์ผ ๋ณ๊ฒฝ ๋ชจ๋ํฐ๋ง์ผ๋ก ์๋ ค์ง ์ด ๊ธฐ๋ฅ์ ๊ฐ๋ ฅํ๊ณ , ๋ฐ์์ฑ์ด ๋ฐ์ด๋๋ฉฐ, ๊ณ ๋๋ก ํตํฉ๋ ์น ๊ฒฝํ์ ์ฐฝ์ถํ ์ ์๋ ์๋ก์ด ์งํ์ ์ด์ด์ค๋๋ค.
์ด ์ข ํฉ ๊ฐ์ด๋์์๋ ํ๋ก ํธ์๋ ํ์ผ ์์คํ ๋๋ ํ ๋ฆฌ ๊ฐ์์ ์ธ๊ณ๋ฅผ ์ฌ์ธต์ ์ผ๋ก ํ๊ตฌํ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๋ ๊ธฐ๋ฐ์ด ๋๋ API๋ฅผ ์ดํด๋ณด๊ณ , ๊ฒฌ๊ณ ํ ๊ฐ์๊ธฐ๋ฅผ ์ฒ์๋ถํฐ ๊ตฌ์ถํ๋ ๊ธฐ์ ์ ๋ถ์ํ๋ฉฐ, ์ค์ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ๊ฒํ ํ๊ณ , ์ฑ๋ฅ, ๋ณด์ ๋ฐ ์ฌ์ฉ์ ๊ฒฝํ์ ์ค์ํ ๊ณผ์ ๋ค์ ํ์ํ ๊ฒ์ ๋๋ค. ์ฐจ์ธ๋ ์น ๊ธฐ๋ฐ IDE๋ฅผ ๊ตฌ์ถํ๋ ๊ฐ๋จํ ์ ํธ๋ฆฌํฐ ๋๊ตฌ๋ฅผ ๋ง๋ค๋ , ์ด ๊ธฐ์ ์ ์ดํดํ๋ ๊ฒ์ ํ๋ ์น์ ๋ชจ๋ ์ ์ฌ๋ ฅ์ ๋์ด๋ด๋ ๋ฐ ํต์ฌ์ ์ธ ์ด์ ์ ๋๋ค.
์งํ ๊ณผ์ : ๋จ์ํ ํ์ผ ์ ๋ ฅ์์ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง๊น์ง
File System Access API์ ์ค์์ฑ์ ์์ ํ ์ดํดํ๋ ค๋ฉด ์น์์ ํ์ผ ์ฒ๋ฆฌ๊ฐ ๊ฑธ์ด์จ ๊ธธ์ ๋๋์๋ณด๋ ๊ฒ์ด ๋์์ด ๋ฉ๋๋ค.
๊ณ ์ ์ ์ธ ์ ๊ทผ ๋ฐฉ์: <input type="file">
์ค๋ซ๋์ ์ฌ์ฉ์์ ํ์ผ ์์คํ ์ ์ ๊ทผํ ์ ์๋ ์ ์ผํ ๊ด๋ฌธ์ ๋ณด์๊ฒ์๋ <input type="file"> ์์์์ต๋๋ค. ์ด๊ฒ์ ๋จ์ํ ํ์ผ ์ ๋ก๋๋ฅผ ์ํ ์ ๋ขฐํ ์ ์๋ ์ผ๊พผ์ด์๊ณ ์ง๊ธ๋ ๊ทธ๋ ์ต๋๋ค. ํ์ง๋ง ๊ทธ ํ๊ณ๋ ๋ช ํํฉ๋๋ค.
- ์ฌ์ฉ์ ์ฃผ๋ ๋ฐ ์ผํ์ฑ: ์ฌ์ฉ์๋ ๋งค๋ฒ ์๋์ผ๋ก ๋ฒํผ์ ํด๋ฆญํ๊ณ ํ์ผ์ ์ ํํด์ผ ํฉ๋๋ค. ์์์ฑ์ด ์์ต๋๋ค.
- ํ์ผ ์ ์ฉ: ํ๋ ์ด์์ ํ์ผ์ ์ ํํ ์๋ ์์์ง๋ง, ์ ์ฒด ๋๋ ํ ๋ฆฌ๋ฅผ ์ ํํ ์๋ ์์์ต๋๋ค.
- ๋ชจ๋ํฐ๋ง ๋ถ๊ฐ: ํ์ผ์ด ์ ํ๋๋ฉด, ๋ธ๋ผ์ฐ์ ๋ ๋์คํฌ ์์ ์๋ณธ ํ์ผ์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋ฌ๋์ง ์ ์ ์์์ต๋๋ค. ํ์ผ์ด ์์ ๋๊ฑฐ๋ ์ญ์ ๋์ด๋ ์น ์ฑ์ ์์ง ๋ชปํ์ต๋๋ค.
ํ ๊ฑธ์ ๋ ๋์๊ฐ: ๋๋๊ทธ ์ค ๋๋กญ API
๋๋๊ทธ ์ค ๋๋กญ API๋ ์ฌ์ฉ์๊ฐ ํ์ผ๊ณผ ํด๋๋ฅผ ์น ํ์ด์ง์ ์ง์ ๋์ด๋ค ๋์ ์ ์๊ฒ ํ์ฌ ํจ์ฌ ๊ฐ์ ๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ์ต๋๋ค. ์ด๊ฒ์ ๋ ์ง๊ด์ ์ด๊ณ ๋ฐ์คํฌํฑ๊ณผ ์ ์ฌํ ๋๋์ ์ฃผ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํ์ผ ์ ๋ ฅ๊ณผ ๊ทผ๋ณธ์ ์ธ ํ๊ณ๋ฅผ ๊ณต์ ํ์ต๋๋ค. ์ฆ, ์ผํ์ฑ ์ด๋ฒคํธ๋ผ๋ ์ ์ ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ์๊ฐ์ ๋์ด์จ ํญ๋ชฉ์ ์ค๋ ์ท์ ๋ฐ์์ ๋ฟ, ์์ค ๋๋ ํ ๋ฆฌ์์ ์ง์์ ์ธ ์ฐ๊ฒฐ์ ์์์ต๋๋ค.
๊ฒ์ ์ฒด์ธ์ : File System Access API
File System Access API๋ ๊ทผ๋ณธ์ ์ธ ๋์ฝ์ ์๋ฏธํฉ๋๋ค. ์ด API๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ดํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ์ฌ์ฉ์์ ๋ก์ปฌ ํ์ผ ์์คํ ๊ณผ ์ง์์ ์ด๊ณ ๊ฐ๋ ฅํ ๋ฐฉ์์ผ๋ก ์ํธ ์์ฉํ ์ ์๋๋ก ์ค๊ณ๋์์ต๋๋ค. ํต์ฌ ์์น์ ๋ณด์, ์ฌ์ฉ์ ๋์ ๋ฐ ๊ธฐ๋ฅ์ฑ์ ์ค์ฌ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค.
- ์ฌ์ฉ์ ์ค์ฌ ๋ณด์: ์ ๊ทผ ๊ถํ์ ์ ๋ ์๋์ผ๋ก ๋ถ์ฌ๋์ง ์์ต๋๋ค. ์ฌ์ฉ์๋ ํญ์ ๋ค์ดํฐ๋ธ ๋ธ๋ผ์ฐ์ ๋ํ ์์๋ฅผ ํตํด ํน์ ํ์ผ์ด๋ ๋๋ ํ ๋ฆฌ์ ๋ํ ๊ถํ์ ๋ถ์ฌํ๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ฐ์ต๋๋ค.
- ์์์ ์ธ ํธ๋ค: ์ผํ์ฑ ๋ฐ์ดํฐ ๋ฉ์ด๋ฆฌ(blob)๋ฅผ ๋ฐ๋ ๋์ , ์ ํ๋ฆฌ์ผ์ด์ ์ ํธ๋ค(FileSystemFileHandle ๋๋ FileSystemDirectoryHandle)์ด๋ผ๋ ํน์ ๊ฐ์ฒด๋ฅผ ๋ฐ์ต๋๋ค. ์ด ํธ๋ค์ ๋์คํฌ ์์ ์ค์ ํ์ผ์ด๋ ๋๋ ํ ๋ฆฌ์ ๋ํ ์์์ ์ธ ํฌ์ธํฐ ์ญํ ์ ํฉ๋๋ค.
- ๋๋ ํ ๋ฆฌ ์์ค ์ ๊ทผ: ์ด๊ฒ์ด ํต์ฌ ๊ธฐ๋ฅ์ ๋๋ค. API๋ ์ฌ์ฉ์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ ํ์ ๋๋ ํ ๋ฆฌ์ ํ์ผ์ ํฌํจํ ์ ์ฒด ๋๋ ํ ๋ฆฌ์ ๋ํ ์ ๊ทผ ๊ถํ์ ๋ถ์ฌํ ์ ์๋๋ก ํฉ๋๋ค.
ํ๋ก ํธ์๋์์ ์ค์๊ฐ ํ์ผ ๋ชจ๋ํฐ๋ง์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๊ฒ์ ๋ฐ๋ก ์ด ์์์ ์ธ ๋๋ ํ ๋ฆฌ ํธ๋ค์ ๋๋ค.
File System Access API ์ดํดํ๊ธฐ: ํต์ฌ ๊ธฐ์
๋๋ ํ ๋ฆฌ ๊ฐ์๊ธฐ๋ฅผ ๋ง๋ค๊ธฐ ์ ์, ์ด๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ API์ ์ฃผ์ ๊ตฌ์ฑ ์์๋ฅผ ์ดํดํด์ผ ํฉ๋๋ค. ์ ์ฒด API๋ ๋น๋๊ธฐ์ ์ด๋ฏ๋ก ํ์ผ ์์คํ ๊ณผ ์ํธ ์์ฉํ๋ ๋ชจ๋ ์์ ์ Promise๋ฅผ ๋ฐํํ์ฌ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๊ฐ ๋ฐ์์ฑ์ ์ ์งํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
๋ณด์ ๋ฐ ๊ถํ: ์ฌ์ฉ์๊ฐ ํต์ ๊ถ์ ๊ฐ์ง๋๋ค
์ด API์ ๊ฐ์ฅ ์ค์ํ ์ธก๋ฉด์ ๋ณด์ ๋ชจ๋ธ์ ๋๋ค. ์น์ฌ์ดํธ๋ ์์๋ก ์ฌ์ฉ์์ ํ๋ ๋๋ผ์ด๋ธ๋ฅผ ์ค์บํ ์ ์์ต๋๋ค. ์ ๊ทผ์ ์๊ฒฉํ๊ฒ ์ตํธ์ธ(opt-in) ๋ฐฉ์์ ๋๋ค.
- ์ต์ด ์ ๊ทผ: ์ฌ์ฉ์๋ ๋ฒํผ ํด๋ฆญ๊ณผ ๊ฐ์ ์ก์ ์ ํธ๋ฆฌ๊ฑฐํด์ผ ํ๋ฉฐ, ์ด๋ window.showDirectoryPicker()์ ๊ฐ์ API ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ์ต์ํ OS ์์ค์ ๋ํ ์์๊ฐ ์ด๋ฆฌ๊ณ , ์ฌ์ฉ์๋ ๋๋ ํ ๋ฆฌ๋ฅผ ์ ํํ ํ ๋ช ์์ ์ผ๋ก "์ก์ธ์ค ๊ถํ ๋ถ์ฌ" ๋๋ ์ ์ฌํ ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค.
- ๊ถํ ์ํ: ํน์ ํธ๋ค์ ๋ํ ์ฌ์ดํธ์ ๊ถํ์ 'prompt' (๊ธฐ๋ณธ๊ฐ, ์ฌ์ฉ์์๊ฒ ์ง๋ฌธ ํ์), 'granted' (์ฌ์ดํธ๊ฐ ์ ๊ทผ ๊ถํ์ ๊ฐ์ง), ๋๋ 'denied' (์ฌ์ดํธ๊ฐ ์ ๊ทผํ ์ ์์ผ๋ฉฐ ๋์ผํ ์ธ์ ์์ ๋ค์ ์์ฒญํ ์ ์์)์ ์ธ ๊ฐ์ง ์ํ ์ค ํ๋์ผ ์ ์์ต๋๋ค.
- ์์์ฑ: ๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ํด, ๋ธ๋ผ์ฐ์ ๋ ์ค์น๋ PWA๋ ์ฐธ์ฌ๋๊ฐ ๋์ ์ฌ์ดํธ์ ๋ํด ์ธ์ ๊ฐ์ 'granted' ๊ถํ์ ์ ์งํ ์ ์์ต๋๋ค. ์ฆ, ์ฌ์ฉ์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐฉ๋ฌธํ ๋๋ง๋ค ํ๋ก์ ํธ ํด๋๋ฅผ ๋ค์ ์ ํํ ํ์๊ฐ ์์ ์๋ ์์ต๋๋ค. ํ์ฌ ๊ถํ ์ํ๋ directoryHandle.queryPermission()์ผ๋ก ํ์ธํ ์ ์์ผ๋ฉฐ, directoryHandle.requestPermission()์ผ๋ก ๊ถํ ์ํฅ์ ์์ฒญํ ์ ์์ต๋๋ค.
์ ๊ทผ ๊ถํ์ ์ป๊ธฐ ์ํ ์ฃผ์ ๋ฉ์๋
API์ ์ง์ ์ ์ window ๊ฐ์ฒด์ ์๋ ์ธ ๊ฐ์ง ์ ์ญ ๋ฉ์๋์ ๋๋ค.
- window.showOpenFilePicker(): ์ฌ์ฉ์์๊ฒ ํ๋ ์ด์์ ํ์ผ์ ์ ํํ๋ผ๋ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค. FileSystemFileHandle ๊ฐ์ฒด์ ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค.
- window.showDirectoryPicker(): ์ด๊ฒ์ด ์ฐ๋ฆฌ์ ์ฃผ์ ๋๊ตฌ์ ๋๋ค. ์ฌ์ฉ์์๊ฒ ๋๋ ํ ๋ฆฌ๋ฅผ ์ ํํ๋ผ๋ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค. ๋จ์ผ FileSystemDirectoryHandle์ ๋ฐํํฉ๋๋ค.
- window.showSaveFilePicker(): ์ฌ์ฉ์์๊ฒ ํ์ผ์ ์ ์ฅํ ์์น๋ฅผ ์ ํํ๋ผ๋ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค. ์ฐ๊ธฐ์ฉ FileSystemFileHandle์ ๋ฐํํฉ๋๋ค.
ํธ๋ค์ ํ: FileSystemDirectoryHandle
FileSystemDirectoryHandle์ ์ป์ผ๋ฉด, ํด๋น ๋๋ ํ ๋ฆฌ๋ฅผ ๋ํ๋ด๋ ๊ฐ๋ ฅํ ๊ฐ์ฒด๋ฅผ ๊ฐ๊ฒ ๋ฉ๋๋ค. ์ด ๊ฐ์ฒด๋ ๋๋ ํ ๋ฆฌ์ ๋ด์ฉ์ ํฌํจํ์ง๋ ์์ง๋ง, ๋ด์ฉ๊ณผ ์ํธ ์์ฉํ ์ ์๋ ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๋ฐ๋ณต: ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ(async iterator)๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ ํ ๋ฆฌ์ ๋ด์ฉ์ ๋ฐ๋ณตํ ์ ์์ต๋๋ค: for await (const entry of directoryHandle.values()) { ... }. ๊ฐ entry๋ FileSystemFileHandle ๋๋ ๋ค๋ฅธ FileSystemDirectoryHandle์ด ๋ฉ๋๋ค.
- ํน์ ํญ๋ชฉ ํ์ธ: directoryHandle.getFileHandle('filename.txt') ๋๋ directoryHandle.getDirectoryHandle('subfolder')๋ฅผ ์ฌ์ฉํ์ฌ ํน์ ํ์ผ์ด๋ ํ์ ๋๋ ํ ๋ฆฌ์ ๋ํ ํธ๋ค์ ์ป์ ์ ์์ต๋๋ค.
- ์์ : ์ ๋ฉ์๋์ { create: true } ์ต์ ์ ์ถ๊ฐํ์ฌ ์ ํ์ผ ๋ฐ ํ์ ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ค๊ฑฐ๋, directoryHandle.removeEntry('item-to-delete')๋ก ์ญ์ ํ ์ ์์ต๋๋ค.
๋ฌธ์ ์ ํต์ฌ: ๋๋ ํ ๋ฆฌ ๊ฐ์ ๊ตฌํํ๊ธฐ
์ฌ๊ธฐ์ ์ค์ํ ์ธ๋ถ ์ฌํญ์ด ์์ต๋๋ค: File System Access API๋ Node.js์ fs.watch()์ ๊ฐ์ ๋ค์ดํฐ๋ธ, ์ด๋ฒคํธ ๊ธฐ๋ฐ ๊ฐ์ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ง ์์ต๋๋ค. directoryHandle.on('change', ...)์ ๊ฐ์ ๋ฉ์๋๋ ์์ต๋๋ค. ์ด๋ ์์ฃผ ์์ฒญ๋๋ ๊ธฐ๋ฅ์ด์ง๋ง, ํ์ฌ๋ก์๋ ์ฐ๋ฆฌ๊ฐ ์ง์ ๊ฐ์ ๋ก์ง์ ๊ตฌํํด์ผ ํฉ๋๋ค.
๊ฐ์ฅ ์ผ๋ฐ์ ์ด๊ณ ์ค์ฉ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ์ฃผ๊ธฐ์ ์ธ ํด๋ง(polling)์ ๋๋ค. ์ด๋ ์ผ์ ํ ๊ฐ๊ฒฉ์ผ๋ก ๋๋ ํ ๋ฆฌ ์ํ์ "์ค๋ ์ท"์ ์ฐ๊ณ ์ด์ ์ค๋ ์ท๊ณผ ๋น๊ตํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ๊ฐ์งํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค.
๋จ์ํ ์ ๊ทผ๋ฒ: ๊ฐ๋จํ ํด๋ง ๋ฃจํ
๊ธฐ๋ณธ์ ์ธ ๊ตฌํ์ ๋ค์๊ณผ ๊ฐ์ ์ ์์ต๋๋ค:
// ๊ฐ๋ ์ ์ค๋ช ํ๊ธฐ ์ํ ๋จ์ํ๋ ์์
let initialFiles = new Set();
async function watchDirectory(directoryHandle) {
const currentFiles = new Set();
for await (const entry of directoryHandle.values()) {
currentFiles.add(entry.name);
}
// ์ด์ ์ํ์ ๋น๊ต (์ด ๋ก์ง์ ๋งค์ฐ ๋จ์ํจ)
console.log("๋๋ ํ ๋ฆฌ ํ์ธ๋จ. ํ์ฌ ํ์ผ๋ค:", Array.from(currentFiles));
// ๋ค์ ํ์ธ์ ์ํด ์ํ ์ ๋ฐ์ดํธ
initialFiles = currentFiles;
}
// ๊ฐ์ ์์
async function start() {
const directoryHandle = await window.showDirectoryPicker();
setInterval(() => watchDirectory(directoryHandle), 2000); // 2์ด๋ง๋ค ํ์ธ
}
์ด๊ฒ์ ์๋ํ์ง๋ง ๋งค์ฐ ์ ํ์ ์ ๋๋ค. ์ต์์ ๋๋ ํ ๋ฆฌ๋ง ํ์ธํ๊ณ , ์ถ๊ฐ/์ญ์ ๋ง ๊ฐ์งํ ์ ์์ผ๋ฉฐ(์์ ์ ๊ฐ์ง ๋ถ๊ฐ), ์บก์ํ๋์ด ์์ง ์์ต๋๋ค. ์์์ ์ ๋์ง๋ง, ํจ์ฌ ๋ ์ ๋ง๋ค ์ ์์ต๋๋ค.
๋ ์ ๊ตํ ์ ๊ทผ๋ฒ: ์ฌ๊ท์ ์ธ Watcher ํด๋์ค ๊ตฌ์ถํ๊ธฐ
์ ๋ง๋ก ์ ์ฉํ ๋๋ ํ ๋ฆฌ ๊ฐ์๊ธฐ๋ฅผ ๋ง๋ค๋ ค๋ฉด ๋ ๊ฒฌ๊ณ ํ ์๋ฃจ์ ์ด ํ์ํฉ๋๋ค. ๋๋ ํ ๋ฆฌ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ค์บํ๊ณ , ํ์ผ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ถ์ ํ์ฌ ์์ ์ ๊ฐ์งํ๋ฉฐ, ๋ค์ํ ์ ํ์ ๋ณ๊ฒฝ์ ๋ํด ๋ช ํํ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๋ ํด๋์ค๋ฅผ ์ค๊ณํด ๋ด ์๋ค.
1๋จ๊ณ: ์์ธํ ์ค๋ ์ท ์ฐ๊ธฐ
๋จผ์ , ๋๋ ํ ๋ฆฌ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ํํ๊ณ ๊ทธ ๋ด์ฉ์ ์์ธํ ๋งต์ ๊ตฌ์ถํ ์ ์๋ ํจ์๊ฐ ํ์ํฉ๋๋ค. ์ด ๋งต์๋ ํ์ผ ์ด๋ฆ๋ฟ๋ง ์๋๋ผ ๋ณ๊ฒฝ ๊ฐ์ง์ ์ค์ํ lastModified ํ์์คํฌํ์ ๊ฐ์ ๋ฉํ๋ฐ์ดํฐ๋ ํฌํจ๋์ด์ผ ํฉ๋๋ค.
// ๋๋ ํ ๋ฆฌ์ ์ค๋ ์ท์ ์ฌ๊ท์ ์ผ๋ก ์์ฑํ๋ ํจ์
async function createSnapshot(dirHandle, path = '') {
const snapshot = new Map();
for await (const entry of dirHandle.values()) {
const currentPath = path ? `${path}/${entry.name}` : entry.name;
if (entry.kind === 'file') {
const file = await entry.getFile();
snapshot.set(currentPath, {
lastModified: file.lastModified,
size: file.size,
handle: entry
});
} else if (entry.kind === 'directory') {
const subSnapshot = await createSnapshot(entry, currentPath);
subSnapshot.forEach((value, key) => snapshot.set(key, value));
}
}
return snapshot;
}
2๋จ๊ณ: ์ค๋ ์ท์ ๋น๊ตํ์ฌ ๋ณ๊ฒฝ ์ฌํญ ์ฐพ๊ธฐ
๋ค์์ผ๋ก, ์ด์ ์ค๋ ์ท๊ณผ ์ ์ค๋ ์ท์ ๋น๊ตํ์ฌ ์ ํํ ๋ฌด์์ด ๋ณ๊ฒฝ๋์๋์ง ์๋ณํ๋ ํจ์๊ฐ ํ์ํฉ๋๋ค.
// ๋ ์ค๋ ์ท์ ๋น๊ตํ๊ณ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐํํ๋ ํจ์
function compareSnapshots(oldSnapshot, newSnapshot) {
const changes = {
added: [],
modified: [],
deleted: []
};
// ์ถ๊ฐ ๋ฐ ์์ ๋ ํ์ผ ํ์ธ
newSnapshot.forEach((newFile, path) => {
const oldFile = oldSnapshot.get(path);
if (!oldFile) {
changes.added.push({ path, handle: newFile.handle });
} else if (oldFile.lastModified !== newFile.lastModified || oldFile.size !== newFile.size) {
changes.modified.push({ path, handle: newFile.handle });
}
});
// ์ญ์ ๋ ํ์ผ ํ์ธ
oldSnapshot.forEach((oldFile, path) => {
if (!newSnapshot.has(path)) {
changes.deleted.push({ path });
}
});
return changes;
}
3๋จ๊ณ: ๋ก์ง์ DirectoryWatcher ํด๋์ค๋ก ์บก์ํํ๊ธฐ
๋ง์ง๋ง์ผ๋ก, ์ํ์ ํด๋ง ๊ฐ๊ฒฉ์ ๊ด๋ฆฌํ๊ณ ๊ฐ๋จํ ์ฝ๋ฐฑ ๊ธฐ๋ฐ API๋ฅผ ์ ๊ณตํ๋ ๊น๋ํ๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํด๋์ค๋ก ๋ชจ๋ ๊ฒ์ ๊ฐ์๋๋ค.
class DirectoryWatcher {
constructor(directoryHandle, interval = 1000) {
this.directoryHandle = directoryHandle;
this.interval = interval;
this.lastSnapshot = new Map();
this.intervalId = null;
this.onChange = () => {}; // ๊ธฐ๋ณธ ๋น ์ฝ๋ฐฑ
}
async check() {
try {
const newSnapshot = await createSnapshot(this.directoryHandle);
const changes = compareSnapshots(this.lastSnapshot, newSnapshot);
if (changes.added.length > 0 || changes.modified.length > 0 || changes.deleted.length > 0) {
this.onChange(changes);
}
this.lastSnapshot = newSnapshot;
} catch (error) {
console.error("ํ์ผ ๋ณ๊ฒฝ ํ์ธ ์ค ์ค๋ฅ ๋ฐ์:", error);
// ๋๋ ํ ๋ฆฌ์ ๋ ์ด์ ์ ๊ทผํ ์ ์๋ ๊ฒฝ์ฐ ๊ฐ์ ์ค๋จ ๊ฐ๋ฅ
this.stop();
}
}
async start(callback) {
if (this.intervalId) {
console.log("๊ฐ์๊ธฐ๊ฐ ์ด๋ฏธ ์คํ ์ค์ ๋๋ค.");
return;
}
this.onChange = callback;
// ์ฆ์ ์ด๊ธฐ ํ์ธ ์ํ
this.lastSnapshot = await createSnapshot(this.directoryHandle);
this.intervalId = setInterval(() => this.check(), this.interval);
console.log(`"${this.directoryHandle.name}" ๋๋ ํ ๋ฆฌ ๊ฐ์๋ฅผ ์์ํ์ต๋๋ค.`);
}
stop() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
console.log(`"${this.directoryHandle.name}" ๋๋ ํ ๋ฆฌ ๊ฐ์๋ฅผ ์ค๋จํ์ต๋๋ค.`);
}
}
}
// DirectoryWatcher ํด๋์ค ์ฌ์ฉ ๋ฐฉ๋ฒ
const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');
let watcher;
startButton.addEventListener('click', async () => {
try {
const directoryHandle = await window.showDirectoryPicker();
watcher = new DirectoryWatcher(directoryHandle, 2000); // 2์ด๋ง๋ค ํ์ธ
watcher.start((changes) => {
console.log("๋ณ๊ฒฝ ์ฌํญ ๊ฐ์ง๋จ:", changes);
// ์ด์ ์ด ๋ณ๊ฒฝ ์ฌํญ์ ๊ธฐ๋ฐ์ผ๋ก UI๋ฅผ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค
});
} catch (error) {
console.error("์ฌ์ฉ์๊ฐ ๋ํ ์์๋ฅผ ์ทจ์ํ๊ฑฐ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.", error);
}
});
stopButton.addEventListener('click', () => {
if (watcher) {
watcher.stop();
}
});
์ค์ฉ์ ์ธ ์ฌ์ฉ ์ฌ๋ก ๋ฐ ๊ธ๋ก๋ฒ ์์
์ด ๊ธฐ์ ์ ๋จ์ํ ์ด๋ก ์ ์ฐ์ต์ด ์๋๋๋ค. ์ ์ธ๊ณ ์ฌ์ฉ์๊ฐ ์ ๊ทผํ ์ ์๋ ๊ฐ๋ ฅํ ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
1. ์น ๊ธฐ๋ฐ IDE ๋ฐ ์ฝ๋ ์๋ํฐ
์ด๊ฒ์ ์ ํ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์ ๋๋ค. VS Code for the Web์ด๋ GitHub Codespaces์ ๊ฐ์ ๋๊ตฌ๋ ๊ฐ๋ฐ์๊ฐ ๋ก์ปฌ ํ๋ก์ ํธ ํด๋๋ฅผ ์ด ์ ์๊ฒ ํด์ค๋๋ค. ๊ทธ๋ฌ๋ฉด ๋๋ ํ ๋ฆฌ ๊ฐ์๊ธฐ๊ฐ ๋ณ๊ฒฝ ์ฌํญ์ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
- ํ์ผ ํธ๋ฆฌ ๋๊ธฐํ: ๋์คํฌ์์ ํ์ผ์ด ์์ฑ, ์ญ์ ๋๋ ์ด๋ฆ์ด ๋ณ๊ฒฝ๋๋ฉด(์๋ง๋ ๋ค๋ฅธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉํ์ฌ), ์๋ํฐ์ ํ์ผ ํธ๋ฆฌ๊ฐ ์ฆ์ ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
- ์ค์๊ฐ ๋ฆฌ๋ก๋/๋ฏธ๋ฆฌ๋ณด๊ธฐ: ์น ๊ฐ๋ฐ์ ๊ฒฝ์ฐ, HTML, CSS ๋๋ JavaScript ํ์ผ์ ์ ์ฅ๋ ๋ณ๊ฒฝ ์ฌํญ์ ์๋ํฐ ๋ด์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ฐฝ์ ์๋์ผ๋ก ์๋ก ๊ณ ์น ์ ์์ต๋๋ค.
- ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ : ํ์ผ ์์ ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ฆฐํ , ํ์ ๊ฒ์ฌ ๋๋ ์ปดํ์ผ์ ํธ๋ฆฌ๊ฑฐํ ์ ์์ต๋๋ค.
2. ํฌ๋ฆฌ์์ดํฐ๋ธ ์ ๋ฌธ๊ฐ๋ฅผ ์ํ ๋์งํธ ์์ฐ ๊ด๋ฆฌ(DAM)
์ ์ธ๊ณ ์ด๋์์๋ ์ฌ์ง์๊ฐ๊ฐ ์นด๋ฉ๋ผ๋ฅผ ์ปดํจํฐ์ ์ฐ๊ฒฐํ๋ฉด ์ฌ์ง์ด ํน์ "์์ " ํด๋์ ์ ์ฅ๋ฉ๋๋ค. ์ด ํด๋์ ์ ๊ทผ ๊ถํ์ ๋ถ์ฌ๋ฐ์ ์น ๊ธฐ๋ฐ ์ฌ์ง ๊ด๋ฆฌ ๋๊ตฌ๋ ์๋ก์ด ์ถ๊ฐ ํญ๋ชฉ์ด ์๋์ง ๊ฐ์ํ ์ ์์ต๋๋ค. ์๋ก์ด JPEG ๋๋ RAW ํ์ผ์ด ๋ํ๋์๋ง์ ์น ์ฑ์ ์๋ ๊ฐ์ ์์ด ์๋์ผ๋ก ์ด๋ฅผ ๊ฐ์ ธ์ ์ธ๋ค์ผ์ ์์ฑํ๊ณ ์ฌ์ฉ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
3. ๊ณผํ ๋ฐ ๋ฐ์ดํฐ ๋ถ์ ๋๊ตฌ
์ฐ๊ตฌ์์ ์ฅ๋น๋ ์๊ฐ๋น ์๋ฐฑ ๊ฐ์ ์์ CSV ๋๋ JSON ๋ฐ์ดํฐ ํ์ผ์ ์ง์ ๋ ์ถ๋ ฅ ๋๋ ํ ๋ฆฌ์ ์์ฑํ ์ ์์ต๋๋ค. ์น ๊ธฐ๋ฐ ๋์๋ณด๋๋ ์ด ๋๋ ํ ๋ฆฌ๋ฅผ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค. ์๋ก์ด ๋ฐ์ดํฐ ํ์ผ์ด ์ถ๊ฐ๋๋ฉด ์ด๋ฅผ ํ์ฑํ์ฌ ๊ทธ๋ํ, ์ฐจํธ ๋ฐ ํต๊ณ ์์ฝ์ ์ค์๊ฐ์ผ๋ก ์ ๋ฐ์ดํธํ์ฌ ์งํ ์ค์ธ ์คํ์ ๋ํ ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ์๋ฌผํ์์ ๊ธ์ต์ ์ด๋ฅด๊ธฐ๊น์ง ์ ์ธ๊ณ์ ์ผ๋ก ์ ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
4. ๋ก์ปฌ ์ฐ์ ๋ ธํธ ํ๊ธฐ ๋ฐ ๋ฌธ์ ์ฑ
๋ง์ ์ฌ์ฉ์๋ ๋ ธํธ๋ฅผ ๋ก์ปฌ ํด๋์ ์ผ๋ฐ ํ ์คํธ๋ ๋งํฌ๋ค์ด ํ์ผ๋ก ๋ณด๊ดํ์ฌ Obsidian์ด๋ Typora์ ๊ฐ์ ๊ฐ๋ ฅํ ๋ฐ์คํฌํฑ ํธ์ง๊ธฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ ํธํฉ๋๋ค. ํ๋ก๊ทธ๋ ์๋ธ ์น ์ฑ(PWA)์ ์ด ํด๋๋ฅผ ๊ฐ์ํ๋ ๋๋ฐ์ ์ญํ ์ ํ ์ ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ํ์ผ์ ํธ์งํ๊ณ ์ ์ฅํ๋ฉด ์น ์ฑ์ ์์ ์ ๊ฐ์งํ๊ณ ์์ฒด ๋ทฐ๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค. ์ด๋ ๋ค์ดํฐ๋ธ ๋๊ตฌ์ ์น ๋๊ตฌ ๊ฐ์ ์ํํ๊ณ ๋๊ธฐํ๋ ๊ฒฝํ์ ๋ง๋ค์ด๋ด๋ฉฐ, ์ฌ์ฉ์์ ๋ฐ์ดํฐ ์์ ๊ถ์ ์กด์คํฉ๋๋ค.
๊ณผ์ , ํ๊ณ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๋๋ ํ ๋ฆฌ ๊ฐ์ ๊ตฌํ์ ๋งค์ฐ ๊ฐ๋ ฅํ์ง๋ง, ์ผ๋ จ์ ๊ณผ์ ์ ์ฑ ์์ด ๋ฐ๋ฆ ๋๋ค.
๋ธ๋ผ์ฐ์ ํธํ์ฑ
File System Access API๋ ์ต์ ๊ธฐ์ ์ ๋๋ค. 2023๋ ๋ง ๊ธฐ์ค์ผ๋ก, ์ฃผ๋ก Google Chrome, Microsoft Edge, Opera์ ๊ฐ์ Chromium ๊ธฐ๋ฐ ๋ธ๋ผ์ฐ์ ์์ ์ง์๋ฉ๋๋ค. Firefox๋ Safari์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ค์์ด ์ค์ํฉ๋๋ค.
- ๊ธฐ๋ฅ ๊ฐ์ง: API๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ ํญ์ 'showDirectoryPicker' in window์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ํ์ธํ์ญ์์ค.
- ๋์ฒด ์๋จ ์ ๊ณต: API๊ฐ ์ง์๋์ง ์๋ ๊ฒฝ์ฐ, ๊ฒฝํ์ ์ฐ์ํ๊ฒ ์ ํ์ํค์ญ์์ค. ์ ํต์ ์ธ <input type="file" multiple> ์์๋ก ๋์ฒดํ๊ณ , ์ง์๋๋ ๋ธ๋ผ์ฐ์ ์์ ์ฌ์ฉํ ์ ์๋ ํฅ์๋ ๊ธฐ๋ฅ์ ๋ํด ์ฌ์ฉ์์๊ฒ ์๋ฆด ์ ์์ต๋๋ค.
์ฑ๋ฅ ๊ณ ๋ ค ์ฌํญ
ํด๋ง์ ๋ณธ์ง์ ์ผ๋ก ์์คํ ์์ค์ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์๋ณด๋ค ํจ์จ์ฑ์ด ๋จ์ด์ง๋๋ค. ์ฑ๋ฅ ๋น์ฉ์ ๊ฐ์ ๋์ ๋๋ ํ ๋ฆฌ์ ํฌ๊ธฐ์ ๊น์ด, ๊ทธ๋ฆฌ๊ณ ํด๋ง ๊ฐ๊ฒฉ์ ๋น๋์ ์ง์ ์ ์ผ๋ก ๊ด๋ จ๋ฉ๋๋ค.
- ๋๊ท๋ชจ ๋๋ ํ ๋ฆฌ: ์๋ง ๊ฐ์ ํ์ผ์ด ์๋ ๋๋ ํ ๋ฆฌ๋ฅผ ๋งค์ด ์ค์บํ๋ ๊ฒ์ ์๋นํ CPU ์์์ ์๋ชจํ๊ณ ๋ ธํธ๋ถ์ ๋ฐฐํฐ๋ฆฌ๋ฅผ ๊ณ ๊ฐ์ํฌ ์ ์์ต๋๋ค.
- ํด๋ง ๋น๋: ์ฌ์ฉ ์ฌ๋ก์ ํ์ฉ๋๋ ๊ฐ์ฅ ๊ธด ๊ฐ๊ฒฉ์ ์ ํํ์ญ์์ค. ์ค์๊ฐ ์ฝ๋ ์๋ํฐ๋ 1-2์ด ๊ฐ๊ฒฉ์ด ํ์ํ ์ ์์ง๋ง, ์ฌ์ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ํฌํฐ๋ 10-15์ด ๊ฐ๊ฒฉ์ผ๋ก๋ ์ถฉ๋ถํ ์ ์์ต๋๋ค.
- ์ต์ ํ: ์ฐ๋ฆฌ์ ์ค๋ ์ท ๋น๊ต๋ ํ์ผ ๋ด์ฉ์ ํด์ฑํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋น ๋ฅธ lastModified์ size๋ง ํ์ธํ์ฌ ์ด๋ฏธ ์ต์ ํ๋์ด ์์ต๋๋ค. ์ ๋์ ์ผ๋ก ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด ํด๋ง ๋ฃจํ ๋ด์์ ํ์ผ ๋ด์ฉ์ ์ฝ์ง ๋ง์ญ์์ค.
- ํฌ์ปค์ค ๋ณ๊ฒฝ: ํ๋ช ํ ์ต์ ํ ๋ฐฉ๋ฒ์ ํ์ด์ง ๊ฐ์์ฑ API(Page Visibility API)๋ฅผ ์ฌ์ฉํ์ฌ ๋ธ๋ผ์ฐ์ ํญ์ด ํฌ์ปค์ค๋ฅผ ์์์ ๋ ๊ฐ์๊ธฐ๋ฅผ ์ผ์ ์ค์งํ๋ ๊ฒ์ ๋๋ค.
๋ณด์ ๋ฐ ์ฌ์ฉ์ ์ ๋ขฐ
์ ๋ขฐ๋ ๊ฐ์ฅ ์ค์ํฉ๋๋ค. ์ฌ์ฉ์๋ ์น์ฌ์ดํธ์ ๋ก์ปฌ ํ์ผ ์ ๊ทผ ๊ถํ์ ๋ถ์ฌํ๋ ๊ฒ์ ๋ํด ๋น์ฐํ ์ ์คํฉ๋๋ค. ๊ฐ๋ฐ์๋ก์ ์ด ๊ถํ์ ์ฑ ์๊ฐ ์๊ฒ ๊ด๋ฆฌํด์ผ ํฉ๋๋ค.
- ํฌ๋ช ์ฑ ์ ์ง: UI์์ ๋๋ ํ ๋ฆฌ ์ ๊ทผ์ด ์ ํ์ํ์ง ๋ช ํํ๊ฒ ์ค๋ช ํ์ญ์์ค. "ํด๋ ์ด๊ธฐ"๋ผ๋ ์ผ๋ฐ์ ์ธ ๋ฒํผ๋ณด๋ค "ํ๋ก์ ํธ ํด๋๋ฅผ ์ ํํ์ฌ ์ค์๊ฐ ํ์ผ ๋๊ธฐํ๋ฅผ ํ์ฑํํ์ธ์"์ ๊ฐ์ ๋ฉ์์ง๊ฐ ํจ์ฌ ์ข์ต๋๋ค.
- ์ฌ์ฉ์ ํ๋์ ๋ฐ๋ผ ์ ๊ทผ ์์ฒญ: ๋ฒํผ ํด๋ฆญ๊ณผ ๊ฐ์ ์ง์ ์ ์ด๊ณ ๋ช ๋ฐฑํ ์ฌ์ฉ์ ํ๋ ์์ด๋ ์ ๋ showDirectoryPicker() ํ๋กฌํํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ์ง ๋ง์ญ์์ค.
- ๊ฑฐ๋ถ ์ฒ๋ฆฌ: ์ฌ์ฉ์๊ฐ "์ทจ์"๋ฅผ ํด๋ฆญํ๊ฑฐ๋ ๊ถํ ์์ฒญ์ ๊ฑฐ๋ถํ๋ ๊ฒฝ์ฐ, ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๋จ ์์ด ์ด ์ํ๋ฅผ ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
UI/UX ๋ชจ๋ฒ ์ฌ๋ก
์ข์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ด ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์ง๊ด์ ์ด๊ณ ์์ ํ๊ฒ ๋๋ผ๊ฒ ํ๋ ๋ฐ ํต์ฌ์ ๋๋ค.
- ๋ช ํํ ํผ๋๋ฐฑ ์ ๊ณต: ํ์ฌ ๊ฐ์ ์ค์ธ ๋๋ ํ ๋ฆฌ์ ์ด๋ฆ์ ํญ์ ํ์ํ์ญ์์ค. ์ด๋ ์ฌ์ฉ์์๊ฒ ์ด๋ค ์ ๊ทผ ๊ถํ์ด ๋ถ์ฌ๋์๋์ง ์๊ธฐ์์ผ ์ค๋๋ค.
- ๋ช ์์ ์ธ ์ ์ด ๊ธฐ๋ฅ ์ ๊ณต: ๋ช ํํ "๊ฐ์ ์์" ๋ฐ "๊ฐ์ ์ค์ง" ๋ฒํผ์ ํฌํจํ์ญ์์ค. ์ฌ์ฉ์๋ ํญ์ ํ๋ก์ธ์ค๋ฅผ ์ ์ดํ๊ณ ์๋ค๊ณ ๋๊ปด์ผ ํฉ๋๋ค.
- ์ค๋ฅ ์ฒ๋ฆฌ: ์ฑ์ด ์คํ๋๋ ๋์ ์ฌ์ฉ์๊ฐ ๊ฐ์ ์ค์ธ ํด๋์ ์ด๋ฆ์ ๋ฐ๊พธ๊ฑฐ๋ ์ญ์ ํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ๋ค์ ํด๋ง์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ์ด๋ฌํ ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ๊ณ ์ฌ์ฉ์์๊ฒ ์๋ ค, ๊ฐ์๊ธฐ๋ฅผ ์ค์งํ๊ณ ์ ๋๋ ํ ๋ฆฌ๋ฅผ ์ ํํ๋๋ก ์ ๋ํ ์ ์์ต๋๋ค.
๋ฏธ๋: ์น์์์ ํ์ผ ์์คํ ์ ๊ทผ, ๋ค์ ๋จ๊ณ๋?
ํ์ฌ์ ํด๋ง ๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ ์๋ฆฌํ๊ณ ํจ๊ณผ์ ์ธ ํด๊ฒฐ์ฑ ์ด์ง๋ง, ์ด์์ ์ธ ์ฅ๊ธฐ ์๋ฃจ์ ์ ์๋๋๋ค. ์น ํ์ค ์ปค๋ฎค๋ํฐ๋ ์ด๋ฅผ ์ ์๊ณ ์์ต๋๋ค.
๊ฐ์ฅ ๊ธฐ๋๋๋ ๋ฏธ๋์ ๋ฐ์ ์ API์ ๋ค์ดํฐ๋ธ, ์ด๋ฒคํธ ๊ธฐ๋ฐ ํ์ผ ์์คํ ๊ฐ์ ๋ฉ์ปค๋์ฆ์ด ์ถ๊ฐ๋ ๊ฐ๋ฅ์ฑ์ ๋๋ค. ์ด๊ฒ์ ์ง์ ํ ๊ฒ์ ์ฒด์ธ์ ๊ฐ ๋ ๊ฒ์ด๋ฉฐ, ๋ธ๋ผ์ฐ์ ๊ฐ ์ด์ ์ฒด์ ์์ฒด์ ํจ์จ์ ์ธ ์๋ฆผ ์์คํ (Linux์ inotify, macOS์ FSEvents, Windows์ ReadDirectoryChangesW ๋ฑ)์ ์ฐ๊ฒฐ๋ ์ ์๊ฒ ํ ๊ฒ์ ๋๋ค. ์ด๋ ํด๋ง์ ํ์์ฑ์ ์์ ๊ณ , ํนํ ๋๊ท๋ชจ ๋๋ ํ ๋ฆฌ์ ๋ฐฐํฐ๋ฆฌ๋ก ๊ตฌ๋๋๋ ์ฅ์น์์ ์ฑ๋ฅ๊ณผ ํจ์จ์ฑ์ ๊ทน์ ์ผ๋ก ํฅ์์ํฌ ๊ฒ์ ๋๋ค.
์ด๋ฌํ ๊ธฐ๋ฅ์ ๋ํ ํ์ ๋ ์ผ์ ์ ์์ง๋ง, ๊ทธ ์ ์ฌ๋ ฅ์ ์น ํ๋ซํผ์ด ๋์๊ฐ๊ณ ์๋ ๋ฐฉํฅ์ ๋ช ํํ๊ฒ ๋ณด์ฌ์ค๋๋ค. ์ฆ, ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฅ๋ ฅ์ด ๋ธ๋ผ์ฐ์ ์ ์๋๋ฐ์ค๊ฐ ์๋ ์ค์ง ์ฐ๋ฆฌ์ ์์๋ ฅ์ ์ํด์๋ง ์ ํ๋๋ ๋ฏธ๋๋ฅผ ํฅํ๊ณ ์์ต๋๋ค.
๊ฒฐ๋ก
File System Access API๋ก ๊ตฌ๋๋๋ ํ๋ก ํธ์๋ ํ์ผ ์์คํ ๋๋ ํ ๋ฆฌ ๊ฐ์๋ ํ์ ์ ์ธ ๊ธฐ์ ์ ๋๋ค. ์ด๋ ์น๊ณผ ๋ก์ปฌ ๋ฐ์คํฌํฑ ํ๊ฒฝ ์ฌ์ด์ ์ค๋ ์ฅ๋ฒฝ์ ํ๋ฌผ๊ณ , ์ ๊ตํ๊ณ ์ํธ์์ฉ์ ์ด๋ฉฐ ์์ฐ์ ์ธ ์ฐจ์ธ๋ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. ํต์ฌ API๋ฅผ ์ดํดํ๊ณ , ๊ฒฌ๊ณ ํ ํด๋ง ์ ๋ต์ ๊ตฌํํ๋ฉฐ, ์ฑ๋ฅ ๋ฐ ์ฌ์ฉ์ ์ ๋ขฐ์ ๋ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ค์ํจ์ผ๋ก์จ ๊ฐ๋ฐ์๋ ์ด์ ๋ณด๋ค ํจ์ฌ ๋ ํตํฉ๋๊ณ ๊ฐ๋ ฅํ๊ฒ ๋๊ปด์ง๋ ๊ฒฝํ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค.
ํ์ฌ๋ ์์ฒด ๊ฐ์๊ธฐ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ์์กดํ๊ณ ์์ง๋ง, ์ฐ๋ฆฌ๊ฐ ๋ ผ์ํ ์์น๋ค์ ๊ทผ๋ณธ์ ์ ๋๋ค. ์น ํ๋ซํผ์ด ๊ณ์ ์งํํจ์ ๋ฐ๋ผ, ์ฌ์ฉ์์ ๋ก์ปฌ ๋ฐ์ดํฐ์ ์ํํ๊ณ ํจ์จ์ ์ผ๋ก ์ํธ ์์ฉํ๋ ๋ฅ๋ ฅ์ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ด์์ผ๋ก ๋จ์ ๊ฒ์ด๋ฉฐ, ๊ฐ๋ฐ์๋ค์ด ๋ธ๋ผ์ฐ์ ๋ง ์์ผ๋ฉด ๋๊ตฌ๋ ์ ๊ทผํ ์ ์๋ ์ง์ ํ ๊ธ๋ก๋ฒ ๋๊ตฌ๋ฅผ ๊ตฌ์ถํ ์ ์๋๋ก ํ์ ์ค์ด์ค ๊ฒ์ ๋๋ค.