TypeScript๋ก ๊ฒฌ๊ณ ํ Node.js ํ์ผ ์์ ์ ๊ตฌํํ์ธ์. ์ด ์ข ํฉ ๊ฐ์ด๋๋ ํ์ ์์ ์ฑ, ์ค๋ฅ ์ฒ๋ฆฌ, ๊ธ๋ก๋ฒ ๊ฐ๋ฐํ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ฐ์กฐํ๋ฉฐ ๋๊ธฐ, ๋น๋๊ธฐ, ์คํธ๋ฆผ ๊ธฐ๋ฐ FS ๋ฉ์๋๋ฅผ ํ๊ตฌํฉ๋๋ค.
TypeScript ํ์ผ ์์คํ ๋ง์คํฐํ๊ธฐ: ๊ธ๋ก๋ฒ ๊ฐ๋ฐ์๋ฅผ ์ํ ํ์ ์์ ์ฑ์ ๊ฐ์ถ Node.js ํ์ผ ์์
ํ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์ ๊ดํํ ํ๊ฒฝ์์ Node.js๋ ํ์ฅ ๊ฐ๋ฅํ ์๋ฒ์ธก ์ ํ๋ฆฌ์ผ์ด์ , ๋ช ๋ น์ค ๋๊ตฌ ๋ฑ์ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ฐ๋ ฅํ ๋ฐํ์์ผ๋ก ์๋ฆฌ๋งค๊นํ๊ณ ์์ต๋๋ค. ๋ง์ Node.js ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ธฐ๋ณธ์ ์ธ ์ธก๋ฉด์ ํ์ผ ์์คํ ๊ณผ์ ์ํธ ์์ฉ, ์ฆ ํ์ผ ๋ฐ ๋๋ ํ ๋ฆฌ ์ฝ๊ธฐ, ์ฐ๊ธฐ, ์์ฑ ๋ฐ ๊ด๋ฆฌ์ ๊ด๋ จ์ด ์์ต๋๋ค. JavaScript๋ ์ด๋ฌํ ์์ ์ ์ฒ๋ฆฌํ๋ ์ ์ฐ์ฑ์ ์ ๊ณตํ์ง๋ง, TypeScript์ ๋์ ์ ์ ์ ํ์ ๊ฒ์ฌ, ํฅ์๋ ๋๊ตฌ, ๊ทธ๋ฆฌ๊ณ ๊ถ๊ทน์ ์ผ๋ก ํ์ผ ์์คํ ์ฝ๋์ ๋ ํฐ ์ ๋ขฐ์ฑ๊ณผ ์ ์ง ๊ด๋ฆฌ ์ฉ์ด์ฑ์ ์ ๊ณตํ์ฌ ์ด๋ฌํ ๊ฒฝํ์ ํฅ์์ํต๋๋ค.
์ด ์ข ํฉ ๊ฐ์ด๋๋ ๋ฌธํ์ ๋ฐฐ๊ฒฝ์ด๋ ์ง๋ฆฌ์ ์์น์ ๊ด๊ณ์์ด TypeScript๊ฐ ์ ๊ณตํ๋ ๊ฒฌ๊ณ ํจ์ผ๋ก Node.js ํ์ผ ์์ ์ ๋ง์คํฐํ๊ณ ์ ํ๋ ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ค์ ์ํด ์์ฑ๋์์ต๋๋ค. ์ฐ๋ฆฌ๋ ํต์ฌ์ ์ธ `fs` ๋ชจ๋์ ๊น์ด ํ๊ตฌํ๊ณ , ๋ค์ํ ๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ํจ๋ฌ๋ค์์ ์ดํด๋ณด๊ณ , ์ต์ ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ API๋ฅผ ๊ฒํ ํ๋ฉฐ, TypeScript์ ํ์ ์์คํ ์ด ์ด๋ป๊ฒ ์ผ๋ฐ์ ์ธ ์ค๋ฅ๋ฅผ ํฌ๊ฒ ์ค์ด๊ณ ์ฝ๋์ ๋ช ํ์ฑ์ ํฅ์์ํฌ ์ ์๋์ง ๋ฐํ๋ผ ๊ฒ์ ๋๋ค.
์ด์: Node.js ํ์ผ ์์คํ (`fs`) ์ดํดํ๊ธฐ
Node.js์ `fs` ๋ชจ๋์ ํ์ค POSIX ํจ์๋ฅผ ๋ชจ๋ธ๋ก ํ ๋ฐฉ์์ผ๋ก ํ์ผ ์์คํ ๊ณผ ์ํธ ์์ฉํ๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ธ ํ์ผ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ๋ถํฐ ๋ณต์กํ ๋๋ ํ ๋ฆฌ ์กฐ์ ๋ฐ ํ์ผ ๊ฐ์์ ์ด๋ฅด๊ธฐ๊น์ง ๋ค์ํ ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ ํต์ ์ผ๋ก ์ด๋ฌํ ์์ ์ ์ฝ๋ฐฑ์ผ๋ก ์ฒ๋ฆฌ๋์์ผ๋ฉฐ, ๋ณต์กํ ์๋๋ฆฌ์ค์์๋ ์ ๋ช ๋์ "์ฝ๋ฐฑ ์ง์ฅ"์ผ๋ก ์ด์ด์ง๊ณค ํ์ต๋๋ค. Node.js์ ๋ฐ์ ๊ณผ ํจ๊ป ํ๋ก๋ฏธ์ค์ `async/await`๋ ๋น๋๊ธฐ ์์ ์ ์ํ ์ ํธ๋๋ ํจํด์ผ๋ก ๋ถ์ํ์ฌ ์ฝ๋๋ฅผ ๋ ์ฝ๊ธฐ ์ฝ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์์ต๋๋ค.
ํ์ผ ์์คํ ์์ ์ TypeScript๋ฅผ ์ฌ์ฉํ๋ ์ด์ ?
Node.js์ `fs` ๋ชจ๋์ ์ผ๋ฐ JavaScript์์๋ ์๋ฒฝํ๊ฒ ์๋ํ์ง๋ง, TypeScript๋ฅผ ํตํฉํ๋ฉด ๋ช ๊ฐ์ง ์ค๋๋ ฅ ์๋ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค:
- ํ์ ์์ ์ฑ: ์ฝ๋ ์คํ ์ , ์ปดํ์ผ ์์ ์ ์๋ชป๋ ์ธ์ ํ์ , ๋๋ฝ๋ ๋งค๊ฐ๋ณ์ ๋๋ ์๊ธฐ์น ์์ ๋ฐํ ๊ฐ๊ณผ ๊ฐ์ ์ผ๋ฐ์ ์ธ ์ค๋ฅ๋ฅผ ์ก์๋ ๋๋ค. ์ด๋ ํนํ ๋ค์ํ ํ์ผ ์ธ์ฝ๋ฉ, ํ๋๊ทธ ๋ฐ `Buffer` ๊ฐ์ฒด๋ฅผ ๋ค๋ฃฐ ๋ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ํฅ์๋ ๊ฐ๋ ์ฑ: ๋ช ์์ ์ธ ํ์ ์ฃผ์์ ํจ์๊ฐ ์ด๋ค ์ข ๋ฅ์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ํ๊ณ ๋ฌด์์ ๋ฐํํ ์ง ๋ช ํํ๊ฒ ํด์ฃผ์ด ๋ค์ํ ํ์ ๊ฐ๋ฐ์๋ค์ด ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋๋ก ๋์ต๋๋ค.
- ๋ ๋์ ๋๊ตฌ ๋ฐ ์๋ ์์ฑ: IDE(์: VS Code)๋ TypeScript์ ํ์ ์ ์๋ฅผ ํ์ฉํ์ฌ ์ง๋ฅํ ์๋ ์์ฑ, ๋งค๊ฐ๋ณ์ ํํธ ๋ฐ ์ธ๋ผ์ธ ๋ฌธ์๋ฅผ ์ ๊ณตํ์ฌ ์์ฐ์ฑ์ ํฌ๊ฒ ํฅ์์ํต๋๋ค.
- ๋ฆฌํฉํ ๋ง ์์ ๊ฐ: ์ธํฐํ์ด์ค๋ ํจ์ ์๊ทธ๋์ฒ๋ฅผ ๋ณ๊ฒฝํ ๋, TypeScript๋ ์ฆ์ ์ํฅ์ ๋ฐ๋ ๋ชจ๋ ์์ญ์ ํ๋๊ทธ๋ฅผ ์ง์ ํ์ฌ ๋๊ท๋ชจ ๋ฆฌํฉํ ๋ง ์ ์ค๋ฅ ๋ฐ์ ๊ฐ๋ฅ์ฑ์ ์ค์ฌ์ค๋๋ค.
- ๊ธ๋ก๋ฒ ์ผ๊ด์ฑ: ๊ตญ์ ๊ฐ๋ฐํ ์ ์ฒด์์ ์ผ๊ด๋ ์ฝ๋ฉ ์คํ์ผ๊ณผ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๋ํ ์ดํด๋ฅผ ๋ณด์ฅํ์ฌ ๋ชจํธ์ฑ์ ์ค์ ๋๋ค.
๋๊ธฐ vs. ๋น๋๊ธฐ ์์ : ๊ธ๋ก๋ฒ ๊ด์
ํนํ ์ฑ๋ฅ๊ณผ ์๋ต์ฑ์ด ๊ฐ์ฅ ์ค์ํ ์ ์ธ๊ณ ๋ฐฐํฌ์ฉ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ๋ ๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ์์ ๊ฐ์ ์ฐจ์ด๋ฅผ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋๋ถ๋ถ์ `fs` ๋ชจ๋ ํจ์๋ ๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ์ ๊ณต๋ฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ๋น๋๊ธฐ ๋ฉ์๋๋ Node.js ์๋ฒ์ ์๋ต์ฑ์ ์ ์งํ๋ ๋ฐ ํ์์ ์ธ ๋น์ฐจ๋จ I/O ์์ ์ ์ ํธ๋ฉ๋๋ค.
- ๋น๋๊ธฐ (๋น์ฐจ๋จ): ์ด๋ฌํ ๋ฉ์๋๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ๋ง์ง๋ง ์ธ์๋ก ๋ฐ๊ฑฐ๋ `Promise`๋ฅผ ๋ฐํํฉ๋๋ค. ํ์ผ ์์คํ ์์ ์ ์์ํ๊ณ ์ฆ์ ๋ฐํํ์ฌ ๋ค๋ฅธ ์ฝ๋๊ฐ ์คํ๋๋๋ก ํฉ๋๋ค. ์์ ์ด ์๋ฃ๋๋ฉด ์ฝ๋ฐฑ์ด ํธ์ถ๋๊ฑฐ๋(๋๋ Promise๊ฐ ํด๊ฒฐ/๊ฑฐ๋ถ๋ฉ๋๋ค). ์ด๋ ์ ์ธ๊ณ์ ์ฌ๋ฌ ๋์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด์์ ์ด๋ฉฐ, ํ์ผ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ์๋ฒ๊ฐ ๋ฉ์ถ๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
- ๋๊ธฐ (์ฐจ๋จ): ์ด๋ฌํ ๋ฉ์๋๋ ๋ฐํํ๊ธฐ ์ ์ ์์ ์ ์์ ํ ์ํํฉ๋๋ค. ์ฝ๋ฉํ๊ธฐ๋ ๋ ๊ฐ๋จํ์ง๋ง, Node.js ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์ฐจ๋จํ์ฌ ํ์ผ ์์คํ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ๋ค๋ฅธ ์ฝ๋๊ฐ ์คํ๋์ง ๋ชปํ๊ฒ ํฉ๋๋ค. ์ด๋ ํนํ ํธ๋ํฝ์ด ๋ง์ ํ๊ฒฝ์์ ์๋นํ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์๊ณผ ์๋ต ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ก์ง ๋๋ ์ฐจ๋จ์ด ํ์ฉ๋๋ ๊ฐ๋จํ ์คํฌ๋ฆฝํธ์์๋ง ๋๋ฌผ๊ฒ ์ฌ์ฉํ์ญ์์ค.
TypeScript์ ํต์ฌ ํ์ผ ์์ ํ์
์ผ๋ฐ์ ์ธ ํ์ผ ์์คํ ์์ ์ TypeScript๋ฅผ ์ค์ ๋ก ์ ์ฉํด ๋ณด๊ฒ ์ต๋๋ค. Node.js์ฉ ๋ด์ฅ ํ์ ์ ์๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ด๋ ์ผ๋ฐ์ ์ผ๋ก `@types/node` ํจํค์ง๋ฅผ ํตํด ์ ๊ณต๋ฉ๋๋ค.
์์ํ๋ ค๋ฉด ํ๋ก์ ํธ์ TypeScript์ Node.js ํ์ ์ด ์ค์น๋์ด ์๋์ง ํ์ธํ์ญ์์ค:
npm install typescript @types/node --save-dev
์๋ฅผ ๋ค์ด, `tsconfig.json`์ ์ ์ ํ๊ฒ ๊ตฌ์ฑ๋์ด์ผ ํฉ๋๋ค:
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"]
}
ํ์ผ ์ฝ๊ธฐ: `readFile`, `readFileSync`, ๊ทธ๋ฆฌ๊ณ Promises API
ํ์ผ์์ ์ฝํ ์ธ ๋ฅผ ์ฝ๋ ๊ฒ์ ๊ธฐ๋ณธ์ ์ธ ์์ ์ ๋๋ค. TypeScript๋ ํ์ผ ๊ฒฝ๋ก, ์ธ์ฝ๋ฉ ๋ฐ ์ ์ฌ์ ์ค๋ฅ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋๋ก ๋์ต๋๋ค.
๋น๋๊ธฐ ํ์ผ ์ฝ๊ธฐ (์ฝ๋ฐฑ ๊ธฐ๋ฐ)
`fs.readFile` ํจ์๋ ๋น๋๊ธฐ ํ์ผ ์ฝ๊ธฐ๋ฅผ ์ํ ํต์ฌ ์์ ์ ๋๋ค. ๊ฒฝ๋ก, ์ ํ์ ์ธ์ฝ๋ฉ ๋ฐ ์ฝ๋ฐฑ ํจ์๋ฅผ ๋ฐ์ต๋๋ค. TypeScript๋ ์ฝ๋ฐฑ ์ธ์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํ์ ์ง์ ๋๋๋ก ๋ณด์ฅํฉ๋๋ค (`Error | null`, `Buffer | string`).
import * as fs from 'fs';
const filePath: string = 'data/example.txt';
fs.readFile(filePath, 'utf8', (err: NodeJS.ErrnoException | null, data: string) => {
if (err) {
// ๊ตญ์ ๋๋ฒ๊น
์ ์ํ ์ค๋ฅ ๋ก๊น
, ์: 'ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.'
console.error(`Error reading file '${filePath}': ${err.message}`);
return;
}
// 'utf8' ์ธ์ฝ๋ฉ์ ๋ฐ๋ผ ๋ฌธ์์ด์ธ์ง ํ์ธํ๋ฉฐ ํ์ผ ๋ด์ฉ์ ์ฒ๋ฆฌ
console.log(`File content (${filePath}):\n${data}`);
});
// ์์: ์ด์ง ๋ฐ์ดํฐ ์ฝ๊ธฐ (์ธ์ฝ๋ฉ ์ง์ ์ ํจ)
const binaryFilePath: string = 'data/image.png';
fs.readFile(binaryFilePath, (err: NodeJS.ErrnoException | null, data: Buffer) => {
if (err) {
console.error(`Error reading binary file '${binaryFilePath}': ${err.message}`);
return;
}
// ์ฌ๊ธฐ์ 'data'๋ Buffer์ด๋ฉฐ ์ถ๊ฐ ์ฒ๋ฆฌ(์: ํด๋ผ์ด์ธํธ์ ์คํธ๋ฆฌ๋ฐ)ํ ์ค๋น๊ฐ ๋์ด ์์ต๋๋ค.
console.log(`Read ${data.byteLength} bytes from ${binaryFilePath}`);
});
๋๊ธฐ ํ์ผ ์ฝ๊ธฐ
`fs.readFileSync`๋ ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์ฐจ๋จํฉ๋๋ค. ๋ฐํ ํ์ ์ ์ธ์ฝ๋ฉ์ด ์ ๊ณต๋์๋์ง ์ฌ๋ถ์ ๋ฐ๋ผ `Buffer` ๋๋ `string`์ ๋๋ค. TypeScript๋ ์ด๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ถ๋ก ํฉ๋๋ค.
import * as fs from 'fs';
const syncFilePath: string = 'data/sync_example.txt';
try {
const content: string = fs.readFileSync(syncFilePath, 'utf8');
console.log(`Synchronous read content (${syncFilePath}):\n${content}`);
} catch (error: any) {
console.error(`Synchronous read error for '${syncFilePath}': ${error.message}`);
}
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ํ์ผ ์ฝ๊ธฐ (`fs/promises`)
์ต์ `fs/promises` API๋ ๋ ๊น๋ํ ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ฉฐ, ๋น๋๊ธฐ ์์ ์ ๊ฐ๋ ฅํ ๊ถ์ฅ๋ฉ๋๋ค. TypeScript๋ ํนํ `async/await`์ ํจ๊ป ์ฌ๊ธฐ์ ๋ฐ์ด๋ ์ฑ๋ฅ์ ๋ฐํํฉ๋๋ค.
import * as fsPromises from 'fs/promises';
async function readTextFile(path: string): Promise
ํ์ผ ์ฐ๊ธฐ: `writeFile`, `writeFileSync`, ๊ทธ๋ฆฌ๊ณ ํ๋๊ทธ
ํ์ผ์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๋ ๊ฒ๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์ค์ํฉ๋๋ค. TypeScript๋ ํ์ผ ๊ฒฝ๋ก, ๋ฐ์ดํฐ ํ์ (๋ฌธ์์ด ๋๋ Buffer), ์ธ์ฝ๋ฉ ๋ฐ ํ์ผ ์ด๊ธฐ ํ๋๊ทธ ๊ด๋ฆฌ๋ฅผ ๋์ต๋๋ค.
๋น๋๊ธฐ ํ์ผ ์ฐ๊ธฐ
`fs.writeFile`์ ํ์ผ์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ผ์ด ์ด๋ฏธ ์กด์ฌํ๋ฉด ํ์ผ์ ๋ฐ๊ฟ๋๋ค. `flags`๋ก ์ด ๋์์ ์ ์ดํ ์ ์์ต๋๋ค.
import * as fs from 'fs';
const outputFilePath: string = 'data/output.txt';
const fileContent: string = 'This is new content written by TypeScript.';
fs.writeFile(outputFilePath, fileContent, 'utf8', (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`Error writing file '${outputFilePath}': ${err.message}`);
return;
}
console.log(`File '${outputFilePath}' written successfully.`);
});
// Buffer ๋ฐ์ดํฐ ์์
const bufferContent: Buffer = Buffer.from('Binary data example');
const binaryOutputFilePath: string = 'data/binary_output.bin';
fs.writeFile(binaryOutputFilePath, bufferContent, (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`Error writing binary file '${binaryOutputFilePath}': ${err.message}`);
return;
}
console.log(`Binary file '${binaryOutputFilePath}' written successfully.`);
});
๋๊ธฐ ํ์ผ ์ฐ๊ธฐ
`fs.writeFileSync`๋ ์ฐ๊ธฐ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ์ด๋ฒคํธ ๋ฃจํ๋ฅผ ์ฐจ๋จํฉ๋๋ค.
import * as fs from 'fs';
const syncOutputFilePath: string = 'data/sync_output.txt';
try {
fs.writeFileSync(syncOutputFilePath, 'Synchronously written content.', 'utf8');
console.log(`File '${syncOutputFilePath}' written synchronously.`);
} catch (error: any) {
console.error(`Synchronous write error for '${syncOutputFilePath}': ${error.message}`);
}
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ํ์ผ ์ฐ๊ธฐ (`fs/promises`)
`async/await` ๋ฐ `fs/promises`๋ฅผ ์ฌ์ฉํ๋ ์ต์ ์ ๊ทผ ๋ฐฉ์์ ๋น๋๊ธฐ ์ฐ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ๋ ๊น๋ํฉ๋๋ค.
import * as fsPromises from 'fs/promises';
import { constants as fsConstants } from 'fs'; // ํ๋๊ทธ์ฉ
async function writeDataToFile(path: string, data: string | Buffer): Promise
์ค์ ํ๋๊ทธ:
- `'w'` (๊ธฐ๋ณธ๊ฐ): ์ฐ๊ธฐ์ฉ์ผ๋ก ํ์ผ ์ด๊ธฐ. ํ์ผ์ด ์์ฑ๋๊ฑฐ๋(์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ) ์๋ ค์ง๋๋ค(์กด์ฌํ๋ ๊ฒฝ์ฐ).
- `'w+'`: ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ์ฉ์ผ๋ก ํ์ผ ์ด๊ธฐ. ํ์ผ์ด ์์ฑ๋๊ฑฐ๋(์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ) ์๋ ค์ง๋๋ค(์กด์ฌํ๋ ๊ฒฝ์ฐ).
- `'a'` (์ถ๊ฐ): ์ถ๊ฐ์ฉ์ผ๋ก ํ์ผ ์ด๊ธฐ. ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด ์์ฑ๋ฉ๋๋ค.
- `'a+'`: ์ฝ๊ธฐ ๋ฐ ์ถ๊ฐ์ฉ์ผ๋ก ํ์ผ ์ด๊ธฐ. ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด ์์ฑ๋ฉ๋๋ค.
- `'r'` (์ฝ๊ธฐ): ์ฝ๊ธฐ์ฉ์ผ๋ก ํ์ผ ์ด๊ธฐ. ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค.
- `'r+'`: ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ์ฉ์ผ๋ก ํ์ผ ์ด๊ธฐ. ํ์ผ์ด ์กด์ฌํ์ง ์์ผ๋ฉด ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค.
- `'wx'` (๋ฐฐํ์ ์ฐ๊ธฐ): `'w'`์ ๊ฐ์ง๋ง ๊ฒฝ๋ก๊ฐ ์กด์ฌํ๋ฉด ์คํจํฉ๋๋ค.
- `'ax'` (๋ฐฐํ์ ์ถ๊ฐ): `'a'`์ ๊ฐ์ง๋ง ๊ฒฝ๋ก๊ฐ ์กด์ฌํ๋ฉด ์คํจํฉ๋๋ค.
ํ์ผ์ ์ถ๊ฐ: `appendFile`, `appendFileSync`
๊ธฐ์กด ํ์ผ์ ๋ด์ฉ์ ๋ฎ์ด์ฐ์ง ์๊ณ ํ์ผ ๋์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด์ผ ํ ๋ `appendFile`์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ๋ก๊น , ๋ฐ์ดํฐ ์์ง ๋๋ ๊ฐ์ฌ ์ถ์ ์ ํนํ ์ ์ฉํฉ๋๋ค.
๋น๋๊ธฐ ์ถ๊ฐ
import * as fs from 'fs';
const logFilePath: string = 'data/app_logs.log';
function logMessage(message: string): void {
const timestamp: string = new Date().toISOString();
const logEntry: string = `${timestamp} - ${message}\n`;
fs.appendFile(logFilePath, logEntry, 'utf8', (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`Error appending to log file '${logFilePath}': ${err.message}`);
return;
}
console.log(`Logged message to '${logFilePath}'.`);
});
}
logMessage('User "Alice" logged in.');
setTimeout(() => logMessage('System update initiated.'), 50);
logMessage('Database connection established.');
๋๊ธฐ ์ถ๊ฐ
import * as fs from 'fs';
const syncLogFilePath: string = 'data/sync_app_logs.log';
function logMessageSync(message: string): void {
const timestamp: string = new Date().toISOString();
const logEntry: string = `${timestamp} - ${message}\n`;
try {
fs.appendFileSync(syncLogFilePath, logEntry, 'utf8');
console.log(`Logged message synchronously to '${syncLogFilePath}'.`);
} catch (error: any) {
console.error(`Synchronous error appending to log file '${syncLogFilePath}': ${error.message}`);
}
}
logMessageSync('Application started.');
logMessageSync('Configuration loaded.');
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ์ถ๊ฐ (`fs/promises`)
import * as fsPromises from 'fs/promises';
const promiseLogFilePath: string = 'data/promise_app_logs.log';
async function logMessagePromise(message: string): Promise
ํ์ผ ์ญ์ : `unlink`, `unlinkSync`
ํ์ผ ์์คํ ์์ ํ์ผ์ ์ ๊ฑฐํฉ๋๋ค. TypeScript๋ ์ ํจํ ๊ฒฝ๋ก๋ฅผ ์ ๋ฌํ๊ณ ์ค๋ฅ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋๋ก ๋์ต๋๋ค.
๋น๋๊ธฐ ์ญ์
import * as fs from 'fs';
const fileToDeletePath: string = 'data/temp_to_delete.txt';
// ๋จผ์ , ์ญ์ ๋ฐ๋ชจ๋ฅผ ์ํด ํ์ผ์ด ์กด์ฌํ๋์ง ํ์ธํ๋ฉฐ ์์ฑํฉ๋๋ค.
fs.writeFile(fileToDeletePath, 'Temporary content.', 'utf8', (err) => {
if (err) {
console.error('Error creating file for deletion demo:', err);
return;
}
console.log(`File '${fileToDeletePath}' created for deletion demo.`);
fs.unlink(fileToDeletePath, (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`Error deleting file '${fileToDeletePath}': ${err.message}`);
return;
}
console.log(`File '${fileToDeletePath}' deleted successfully.`);
});
});
๋๊ธฐ ์ญ์
import * as fs from 'fs';
const syncFileToDeletePath: string = 'data/sync_temp_to_delete.txt';
try {
fs.writeFileSync(syncFileToDeletePath, 'Sync temp content.', 'utf8');
console.log(`File '${syncFileToDeletePath}' created.`);
fs.unlinkSync(syncFileToDeletePath);
console.log(`File '${syncFileToDeletePath}' deleted synchronously.`);
} catch (error: any) {
console.error(`Synchronous deletion error for '${syncFileToDeletePath}': ${error.message}`);
}
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ์ญ์ (`fs/promises`)
import * as fsPromises from 'fs/promises';
const promiseFileToDeletePath: string = 'data/promise_temp_to_delete.txt';
async function deleteFile(path: string): Promise
ํ์ผ ์กด์ฌ ์ฌ๋ถ ๋ฐ ๊ถํ ํ์ธ: `existsSync`, `access`, `accessSync`
ํ์ผ์ ๋ํ ์์ ์ ์ํํ๊ธฐ ์ ์ ํ์ผ์ด ์กด์ฌํ๋์ง ๋๋ ํ์ฌ ํ๋ก์ธ์ค์ ํ์ํ ๊ถํ์ด ์๋์ง ํ์ธํด์ผ ํ ์๋ ์์ต๋๋ค. TypeScript๋ `mode` ๋งค๊ฐ๋ณ์์ ๋ํ ํ์ ์ ์ ๊ณตํ์ฌ ์ด๋ฅผ ์ง์ํฉ๋๋ค.
๋๊ธฐ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ
`fs.existsSync`๋ ๊ฐ๋จํ๊ณ ๋๊ธฐ์ ์ธ ํ์ธ์ ๋๋ค. ํธ๋ฆฌํ์ง๋ง, ๊ฒฝ์ ์กฐ๊ฑด ์ทจ์ฝ์ (ํ์ผ์ด `existsSync`์ ํ์ ์์ ์ฌ์ด์ ์ญ์ ๋ ์ ์์)์ด ์์ผ๋ฏ๋ก, ์ค์ํ ์์ ์๋ `fs.access`๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข ์ข ๋ ์ข์ต๋๋ค.
import * as fs from 'fs';
const checkFilePath: string = 'data/example.txt';
if (fs.existsSync(checkFilePath)) {
console.log(`File '${checkFilePath}' exists.`);
} else {
console.log(`File '${checkFilePath}' does not exist.`);
}
๋น๋๊ธฐ ๊ถํ ํ์ธ (`fs.access`)
`fs.access`๋ `path`๋ก ์ง์ ๋ ํ์ผ ๋๋ ๋๋ ํ ๋ฆฌ์ ๋ํ ์ฌ์ฉ์ ๊ถํ์ ํ ์คํธํฉ๋๋ค. ๋น๋๊ธฐ์์ด๋ฉฐ `mode` ์ธ์๋ฅผ ๋ฐ์ต๋๋ค (์: ์กด์ฌ ์ฌ๋ถ๋ `fs.constants.F_OK`, ์ฝ๊ธฐ์ฉ์ `R_OK`, ์ฐ๊ธฐ์ฉ์ `W_OK`, ์คํ์ฉ์ `X_OK`).
import * as fs from 'fs';
import { constants } from 'fs';
const accessFilePath: string = 'data/example.txt';
fs.access(accessFilePath, constants.F_OK, (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`File '${accessFilePath}' does not exist or access denied.`);
return;
}
console.log(`File '${accessFilePath}' exists.`);
});
fs.access(accessFilePath, constants.R_OK | constants.W_OK, (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`File '${accessFilePath}' is not readable/writable or access denied: ${err.message}`);
return;
}
console.log(`File '${accessFilePath}' is readable and writable.`);
});
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ๊ถํ ํ์ธ (`fs/promises`)
import * as fsPromises from 'fs/promises';
import { constants } from 'fs';
async function checkFilePermissions(path: string, mode: number): Promise
ํ์ผ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ: `stat`, `statSync`, `fs.Stats`
`fs.stat` ๊ณ์ด ํจ์๋ ํ์ผ ๋๋ ๋๋ ํ ๋ฆฌ์ ๋ํ ํฌ๊ธฐ, ์์ฑ ๋ ์ง, ์์ ๋ ์ง, ๊ถํ๊ณผ ๊ฐ์ ์์ธํ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค. TypeScript์ `fs.Stats` ์ธํฐํ์ด์ค๋ ์ด ๋ฐ์ดํฐ๋ฅผ ๋งค์ฐ ๊ตฌ์กฐ์ ์ด๊ณ ์์ ์ ์ผ๋ก ๋ค๋ฃฐ ์ ์๊ฒ ํฉ๋๋ค.
๋น๋๊ธฐ Stat
import * as fs from 'fs';
import { Stats } from 'fs';
const statFilePath: string = 'data/example.txt';
fs.stat(statFilePath, (err: NodeJS.ErrnoException | null, stats: Stats) => {
if (err) {
console.error(`Error getting stats for '${statFilePath}': ${err.message}`);
return;
}
console.log(`Stats for '${statFilePath}':`);
console.log(` Is file: ${stats.isFile()}`);
console.log(` Is directory: ${stats.isDirectory()}`);
console.log(` Size: ${stats.size} bytes`);
console.log(` Creation time: ${stats.birthtime.toISOString()}`);
console.log(` Last modified: ${stats.mtime.toISOString()}`);
});
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ Stat (`fs/promises`)
import * as fsPromises from 'fs/promises';
import { Stats } from 'fs'; // 'fs' ๋ชจ๋์ Stats ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ ํ ์ฌ์ฉํฉ๋๋ค.
async function getFileStats(path: string): Promise
TypeScript๋ฅผ ์ฌ์ฉํ ๋๋ ํ ๋ฆฌ ์์
๋๋ ํ ๋ฆฌ ๊ด๋ฆฌ๋ ํ์ผ ์ ๋ฆฌ, ์ ํ๋ฆฌ์ผ์ด์ ๋ณ ์ ์ฅ์ ์์ฑ ๋๋ ์์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ผ๋ฐ์ ์ธ ์๊ตฌ ์ฌํญ์ ๋๋ค. TypeScript๋ ์ด๋ฌํ ์์ ์ ๊ฐ๋ ฅํ ํ์ ์ง์ ์ ์ ๊ณตํฉ๋๋ค.
๋๋ ํ ๋ฆฌ ์์ฑ: `mkdir`, `mkdirSync`
`fs.mkdir` ํจ์๋ ์ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. `recursive` ์ต์ ์ ์์ ๋๋ ํ ๋ฆฌ๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๋ ๋ฐ ๋งค์ฐ ์ ์ฉํ๋ฉฐ, Unix ๊ณ์ด ์์คํ ์ `mkdir -p` ๋์์ ๋ชจ๋ฐฉํฉ๋๋ค.
๋น๋๊ธฐ ๋๋ ํ ๋ฆฌ ์์ฑ
import * as fs from 'fs';
const newDirPath: string = 'data/new_directory';
const recursiveDirPath: string = 'data/nested/path/to/create';
// ๋จ์ผ ๋๋ ํ ๋ฆฌ ์์ฑ
fs.mkdir(newDirPath, (err: NodeJS.ErrnoException | null) => {
if (err) {
// ๋๋ ํ ๋ฆฌ๊ฐ ์ด๋ฏธ ์กด์ฌํ๋ ๊ฒฝ์ฐ EEXIST ์ค๋ฅ๋ฅผ ๋ฌด์ํฉ๋๋ค.
if (err.code === 'EEXIST') {
console.log(`Directory '${newDirPath}' already exists.`);
} else {
console.error(`Error creating directory '${newDirPath}': ${err.message}`);
}
return;
}
console.log(`Directory '${newDirPath}' created successfully.`);
});
// ์ค์ฒฉ ๋๋ ํ ๋ฆฌ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์์ฑ
fs.mkdir(recursiveDirPath, { recursive: true }, (err: NodeJS.ErrnoException | null) => {
if (err) {
if (err.code === 'EEXIST') {
console.log(`Directory '${recursiveDirPath}' already exists.`);
} else {
console.error(`Error creating recursive directory '${recursiveDirPath}': ${err.message}`);
}
return;
}
console.log(`Recursive directories '${recursiveDirPath}' created successfully.`);
});
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ๋๋ ํ ๋ฆฌ ์์ฑ (`fs/promises`)
import * as fsPromises from 'fs/promises';
async function createDirectory(path: string, recursive: boolean = false): Promise
๋๋ ํ ๋ฆฌ ๋ด์ฉ ์ฝ๊ธฐ: `readdir`, `readdirSync`, `fs.Dirent`
์ฃผ์ด์ง ๋๋ ํ ๋ฆฌ ๋ด์ ํ์ผ ๋ฐ ํ์ ๋๋ ํ ๋ฆฌ๋ฅผ ๋์ดํ๋ ค๋ฉด `fs.readdir`๋ฅผ ์ฌ์ฉํฉ๋๋ค. `withFileTypes` ์ต์ ์ ๊ฐ ํญ๋ชฉ์ ๊ฐ๋ณ์ ์ผ๋ก `stat`ํ ํ์ ์์ด ๋ ์์ธํ ์ ๋ณด๋ฅผ ์ง์ ์ ๊ณตํ๋ `fs.Dirent` ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ์ต์ ์ถ๊ฐ ๊ธฐ๋ฅ์ ๋๋ค.
๋น๋๊ธฐ ๋๋ ํ ๋ฆฌ ์ฝ๊ธฐ
import * as fs from 'fs';
const readDirPath: string = 'data';
fs.readdir(readDirPath, (err: NodeJS.ErrnoException | null, files: string[]) => {
if (err) {
console.error(`Error reading directory '${readDirPath}': ${err.message}`);
return;
}
console.log(`Contents of directory '${readDirPath}':`);
files.forEach(file => {
console.log(` - ${file}`);
});
});
// `withFileTypes` ์ต์
์ฌ์ฉ
fs.readdir(readDirPath, { withFileTypes: true }, (err: NodeJS.ErrnoException | null, dirents: fs.Dirent[]) => {
if (err) {
console.error(`Error reading directory with file types '${readDirPath}': ${err.message}`);
return;
}
console.log(`Contents of directory '${readDirPath}' (with types):`);
dirents.forEach(dirent => {
const type: string = dirent.isFile() ? 'File' : dirent.isDirectory() ? 'Directory' : 'Other';
console.log(` - ${dirent.name} (${type})`);
});
});
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ๋๋ ํ ๋ฆฌ ์ฝ๊ธฐ (`fs/promises`)
import * as fsPromises from 'fs/promises';
import { Dirent } from 'fs'; // 'fs' ๋ชจ๋์ Dirent ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ ํ ์ฌ์ฉํฉ๋๋ค.
async function listDirectoryContents(path: string): Promise
๋๋ ํ ๋ฆฌ ์ญ์ : `rmdir` (์ฌ์ฉ ์ค๋จ), `rm`, `rmSync`
Node.js๋ ๋๋ ํ ๋ฆฌ ์ญ์ ๋ฉ์๋๋ฅผ ๋ฐ์ ์์ผ ์์ต๋๋ค. `fs.rmdir`์ ์ด์ ์ฌ๊ท์ ์ญ์ ๋ฅผ ์ํด `fs.rm`์ผ๋ก ๋๋ถ๋ถ ๋์ฒด๋์์ผ๋ฉฐ, ๋ ๊ฒฌ๊ณ ํ๊ณ ์ผ๊ด๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋น๋๊ธฐ ๋๋ ํ ๋ฆฌ ์ญ์ (`fs.rm`)
`fs.rm` ํจ์(Node.js 14.14.0๋ถํฐ ์ฌ์ฉ ๊ฐ๋ฅ)๋ ํ์ผ ๋ฐ ๋๋ ํ ๋ฆฌ๋ฅผ ์ ๊ฑฐํ๋ ๊ถ์ฅ ๋ฐฉ๋ฒ์ ๋๋ค. `recursive: true` ์ต์ ์ ๋น์ด ์์ง ์์ ๋๋ ํ ๋ฆฌ๋ฅผ ์ญ์ ํ๋ ๋ฐ ์ค์ํฉ๋๋ค.
import * as fs from 'fs';
const dirToDeletePath: string = 'data/dir_to_delete';
const nestedDirToDeletePath: string = 'data/nested_dir/sub';
// ์ค์ : ์ฌ๊ท์ ์ญ์ ๋ฐ๋ชจ๋ฅผ ์ํด ๋ด๋ถ์ ํ์ผ์ด ์๋ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค.
fs.mkdir(nestedDirToDeletePath, { recursive: true }, (err) => {
if (err && err.code !== 'EEXIST') {
console.error('Error creating nested directory for demo:', err);
return;
}
fs.writeFile(`${nestedDirToDeletePath}/file_inside.txt`, 'Some content', (err) => {
if (err) { console.error('Error creating file inside nested directory:', err); return; }
console.log(`Directory '${nestedDirToDeletePath}' and file created for deletion demo.`);
fs.rm(nestedDirToDeletePath, { recursive: true, force: true }, (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`Error deleting recursive directory '${nestedDirToDeletePath}': ${err.message}`);
return;
}
console.log(`Recursive directory '${nestedDirToDeletePath}' deleted successfully.`);
});
});
});
// ๋น ๋๋ ํ ๋ฆฌ ์ญ์
fs.mkdir(dirToDeletePath, (err) => {
if (err && err.code !== 'EEXIST') {
console.error('Error creating empty directory for demo:', err);
return;
}
console.log(`Directory '${dirToDeletePath}' created for deletion demo.`);
fs.rm(dirToDeletePath, { recursive: false }, (err: NodeJS.ErrnoException | null) => {
if (err) {
console.error(`Error deleting empty directory '${dirToDeletePath}': ${err.message}`);
return;
}
console.log(`Empty directory '${dirToDeletePath}' deleted successfully.`);
});
});
ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ๋๋ ํ ๋ฆฌ ์ญ์ (`fs/promises`)
import * as fsPromises from 'fs/promises';
async function deleteDirectory(path: string, recursive: boolean = false): Promise
TypeScript๋ฅผ ์ฌ์ฉํ ๊ณ ๊ธ ํ์ผ ์์คํ ๊ฐ๋
๊ธฐ๋ณธ์ ์ธ ์ฝ๊ธฐ/์ฐ๊ธฐ ์์ ์ ๋์ด, Node.js๋ ๋์ฉ๋ ํ์ผ, ์ง์์ ์ธ ๋ฐ์ดํฐ ํ๋ฆ, ํ์ผ ์์คํ ์ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง์ ์ฒ๋ฆฌํ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. TypeScript์ ํ์ ์ ์ธ์ ์ด๋ฌํ ๊ณ ๊ธ ์๋๋ฆฌ์ค์๋ ์ ์ฐํ๊ฒ ํ์ฅ๋์ด ๊ฒฌ๊ณ ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
ํ์ผ ๋์คํฌ๋ฆฝํฐ ๋ฐ ์คํธ๋ฆผ
๋งค์ฐ ํฐ ํ์ผ์ ๊ฒฝ์ฐ ๋๋ ํ์ผ ์ก์ธ์ค์ ๋ํ ์ธ๋ถํ๋ ์ ์ด(์: ํ์ผ ๋ด ํน์ ์์น)๊ฐ ํ์ํ ๊ฒฝ์ฐ ํ์ผ ๋์คํฌ๋ฆฝํฐ์ ์คํธ๋ฆผ์ด ํ์์ ์ ๋๋ค. ์คํธ๋ฆผ์ ์ ์ฒด ํ์ผ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋ํ๋ ๋์ ๋ฐ์ดํฐ๋ฅผ ์ฒญํฌ ๋จ์๋ก ์ฝ๊ฑฐ๋ ์ฐ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ฉฐ, ์ด๋ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ ์ ์ธ๊ณ ์๋ฒ์ ํจ์จ์ ์ธ ๋ฆฌ์์ค ๊ด๋ฆฌ์ ์ค์ํฉ๋๋ค.
๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฌ์ฉํ์ฌ ํ์ผ ์ด๊ธฐ ๋ฐ ๋ซ๊ธฐ (`fs.open`, `fs.close`)
ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ ์ด์ ์ฒด์ ์์ ์ด๋ฆฐ ํ์ผ์ ํ ๋นํ๋ ๊ณ ์ ์๋ณ์(์ซ์)์ ๋๋ค. `fs.open`์ ์ฌ์ฉํ์ฌ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ๊ฐ์ ธ์จ ๋ค์, ํด๋น ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ฌ์ฉํ์ฌ `fs.read` ๋๋ `fs.write`์ ๊ฐ์ ์์ ์ ์ํํ๊ณ ๋ง์ง๋ง์ผ๋ก `fs.close`๋ก ๋ซ์ ์ ์์ต๋๋ค.
import * as fs from 'fs';
import { promises as fsPromises } from 'fs';
import { constants } from 'fs';
const descriptorFilePath: string = 'data/descriptor_example.txt';
async function demonstrateFileDescriptorOperations(): Promise
ํ์ผ ์คํธ๋ฆผ (`fs.createReadStream`, `fs.createWriteStream`)
์คํธ๋ฆผ์ ๋์ฉ๋ ํ์ผ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐ ๊ฐ๋ ฅํฉ๋๋ค. `fs.createReadStream` ๋ฐ `fs.createWriteStream`์ ๊ฐ๊ฐ `Readable` ๋ฐ `Writable` ์คํธ๋ฆผ์ ๋ฐํํ๋ฉฐ, ์ด๋ Node.js์ ์คํธ๋ฆฌ๋ฐ API์ ์ํํ๊ฒ ํตํฉ๋ฉ๋๋ค. TypeScript๋ ์ด๋ฌํ ์คํธ๋ฆผ ์ด๋ฒคํธ(์: `'data'`, `'end'`, `'error'`)์ ๋ํ ๋ฐ์ด๋ ํ์ ์ ์๋ฅผ ์ ๊ณตํฉ๋๋ค.
import * as fs from 'fs';
const largeFilePath: string = 'data/large_file.txt';
const copiedFilePath: string = 'data/copied_file.txt';
// ์์ฐ์ ์ํ ๋๋ฏธ ๋์ฉ๋ ํ์ผ ์์ฑ
function createLargeFile(path: string, sizeInMB: number): void {
const content: string = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '; // 56 ๋ฌธ์
const stream = fs.createWriteStream(path);
const totalChars = sizeInMB * 1024 * 1024; // MB๋ฅผ ๋ฐ์ดํธ๋ก ๋ณํ
const iterations = Math.ceil(totalChars / content.length);
for (let i = 0; i < iterations; i++) {
stream.write(content);
}
stream.end(() => console.log(`Created large file '${path}' (${sizeInMB}MB).`));
}
// ์์ฐ์ ์ํด 'data' ๋๋ ํ ๋ฆฌ๊ฐ ๋จผ์ ์กด์ฌํ๋์ง ํ์ธํฉ๋๋ค.
fs.mkdir('data', { recursive: true }, (err) => {
if (err && err.code !== 'EEXIST') {
console.error('Error creating data directory:', err);
return;
}
createLargeFile(largeFilePath, 1); // 1MB ํ์ผ ์์ฑ
});
// ์คํธ๋ฆผ์ ์ฌ์ฉํ์ฌ ํ์ผ ๋ณต์ฌ
function copyFileWithStreams(source: string, destination: string): void {
const readStream = fs.createReadStream(source);
const writeStream = fs.createWriteStream(destination);
readStream.on('open', () => console.log(`Reading stream for '${source}' opened.`));
writeStream.on('open', () => console.log(`Writing stream for '${destination}' opened.`));
// ์ฝ๊ธฐ ์คํธ๋ฆผ์์ ์ฐ๊ธฐ ์คํธ๋ฆผ์ผ๋ก ๋ฐ์ดํฐ ํ์ดํ
readStream.pipe(writeStream);
readStream.on('error', (err: Error) => {
console.error(`Read stream error: ${err.message}`);
});
writeStream.on('error', (err: Error) => {
console.error(`Write stream error: ${err.message}`);
});
writeStream.on('finish', () => {
console.log(`File '${source}' copied to '${destination}' successfully using streams.`);
// ๋ณต์ฌ ํ ๋๋ฏธ ๋์ฉ๋ ํ์ผ ์ ๋ฆฌ
fs.unlink(largeFilePath, (err) => {
if (err) console.error('Error deleting large file:', err);
else console.log(`Large file '${largeFilePath}' deleted.`);
});
});
}
// ๋์ฉ๋ ํ์ผ์ด ์์ฑ๋ ๋๊น์ง ์ ์ ๊ธฐ๋ค๋ฆฐ ๋ค์ ๋ณต์ฌ๋ฅผ ์๋ํฉ๋๋ค.
setTimeout(() => {
copyFileWithStreams(largeFilePath, copiedFilePath);
}, 1000);
๋ณ๊ฒฝ ์ฌํญ ๊ฐ์: `fs.watch`, `fs.watchFile`
ํ์ผ ์์คํ ์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ชจ๋ํฐ๋งํ๋ ๊ฒ์ ํซ ๋ฆฌ๋ก๋ ๊ฐ๋ฐ ์๋ฒ, ๋น๋ ํ๋ก์ธ์ค ๋๋ ์ค์๊ฐ ๋ฐ์ดํฐ ๋๊ธฐํ์ ๊ฐ์ ์์ ์ ํ์์ ์ ๋๋ค. Node.js๋ ์ด๋ฅผ ์ํ ๋ ๊ฐ์ง ์ฃผ์ ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค: `fs.watch` ๋ฐ `fs.watchFile`. TypeScript๋ ์ด๋ฒคํธ ํ์ ๊ณผ ๋ฆฌ์ค๋ ๋งค๊ฐ๋ณ์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
`fs.watch`: ์ด๋ฒคํธ ๊ธฐ๋ฐ ํ์ผ ์์คํ ๊ฐ์
`fs.watch`๋ ์ผ๋ฐ์ ์ผ๋ก ์ด์ ์ฒด์ ์์ค์ ์๋ฆผ(์: Linux์ `inotify`, macOS์ `kqueue`, Windows์ `ReadDirectoryChangesW`)์ ์ฌ์ฉํ๋ฏ๋ก ๋ ํจ์จ์ ์ ๋๋ค. ํน์ ํ์ผ ๋๋ ๋๋ ํ ๋ฆฌ์ ๋ณ๊ฒฝ, ์ญ์ ๋๋ ์ด๋ฆ ๋ณ๊ฒฝ์ ๋ชจ๋ํฐ๋งํ๋ ๋ฐ ์ ํฉํฉ๋๋ค.
import * as fs from 'fs';
const watchedFilePath: string = 'data/watched_file.txt';
const watchedDirPath: string = 'data/watched_dir';
// ๊ฐ์๋ฅผ ์ํด ํ์ผ/๋๋ ํ ๋ฆฌ๊ฐ ์กด์ฌํ๋์ง ํ์ธํฉ๋๋ค.
fs.writeFileSync(watchedFilePath, 'Initial content.');
fs.mkdirSync(watchedDirPath, { recursive: true });
console.log(`Watching '${watchedFilePath}' for changes...`);
const fileWatcher = fs.watch(watchedFilePath, (eventType: string, filename: string | Buffer | null) => {
const fname = typeof filename === 'string' ? filename : filename?.toString('utf8');
console.log(`File '${fname || 'N/A'}' event: ${eventType}`);
if (eventType === 'change') {
console.log('File content potentially changed.');
}
// ์ค์ ์ ํ๋ฆฌ์ผ์ด์
์์๋ ์ฌ๊ธฐ์ ํ์ผ์ ์ฝ๊ฑฐ๋ ์ฌ๋น๋๋ฅผ ํธ๋ฆฌ๊ฑฐํ ์ ์์ต๋๋ค.
});
console.log(`Watching directory '${watchedDirPath}' for changes...`);
const dirWatcher = fs.watch(watchedDirPath, (eventType: string, filename: string | Buffer | null) => {
const fname = typeof filename === 'string' ? filename : filename?.toString('utf8');
console.log(`Directory '${watchedDirPath}' event: ${eventType} on '${fname || 'N/A'}'`);
});
fileWatcher.on('error', (err: Error) => console.error(`File watcher error: ${err.message}`));
dirWatcher.on('error', (err: Error) => console.error(`Directory watcher error: ${err.message}`));
// ์ง์ฐ ํ ๋ณ๊ฒฝ ์๋ฎฌ๋ ์ด์
setTimeout(() => {
console.log('\n--- Simulating changes ---');
fs.appendFileSync(watchedFilePath, '\nNew line added.');
fs.writeFileSync(`${watchedDirPath}/new_file.txt`, 'Content.');
fs.unlinkSync(`${watchedDirPath}/new_file.txt`); // ์ญ์ ๋ ํ
์คํธ
setTimeout(() => {
fileWatcher.close();
dirWatcher.close();
console.log('\nWatchers closed.');
// ์์ ํ์ผ/๋๋ ํ ๋ฆฌ ์ ๋ฆฌ
fs.unlinkSync(watchedFilePath);
fs.rmSync(watchedDirPath, { recursive: true, force: true });
}, 2000);
}, 1000);
`fs.watch` ์ฐธ๊ณ : ๋ชจ๋ ํ๋ซํผ์์ ๋ชจ๋ ์ ํ์ ์ด๋ฒคํธ(์: ํ์ผ ์ด๋ฆ ๋ณ๊ฒฝ์ด ์ญ์ ๋ฐ ์์ฑ์ผ๋ก ๋ณด๊ณ ๋ ์ ์์)์ ๋ํด ํญ์ ์ ๋ขฐํ ์ ์๋ ๊ฒ์ ์๋๋๋ค. ๊ฐ๋ ฅํ ํฌ๋ก์ค ํ๋ซํผ ํ์ผ ๊ฐ์๋ฅผ ์ํด์๋ `chokidar`์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ณ ๋ คํ์ญ์์ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ข ์ข ๋ด๋ถ์ ์ผ๋ก `fs.watch`๋ฅผ ์ฌ์ฉํ์ง๋ง ์ ๊ทํ ๋ฐ ๋์ฒด ๋ฉ์ปค๋์ฆ์ ์ถ๊ฐํฉ๋๋ค.
`fs.watchFile`: ํด๋ง ๊ธฐ๋ฐ ํ์ผ ๊ฐ์
`fs.watchFile`์ ํด๋ง(ํ์ผ์ `stat` ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ํ์ธ)์ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ๊ฐ์งํฉ๋๋ค. ํจ์จ์ฑ์ ๋จ์ด์ง์ง๋ง ๋ค๋ฅธ ํ์ผ ์์คํ ๋ฐ ๋คํธ์ํฌ ๋๋ผ์ด๋ธ์์ ๋ ์ผ๊ด์ ์ ๋๋ค. `fs.watch`๊ฐ ์ ๋ขฐํ ์ ์๋ ํ๊ฒฝ(์: NFS ๊ณต์ )์ ๋ ์ ํฉํฉ๋๋ค.
import * as fs from 'fs';
import { Stats } from 'fs';
const pollFilePath: string = 'data/polled_file.txt';
fs.writeFileSync(pollFilePath, 'Initial polled content.');
console.log(`Polling '${pollFilePath}' for changes...`);
fs.watchFile(pollFilePath, { interval: 1000 }, (curr: Stats, prev: Stats) => {
// TypeScript๋ 'curr'์ 'prev'๊ฐ fs.Stats ๊ฐ์ฒด์์ ๋ณด์ฅํฉ๋๋ค.
if (curr.mtimeMs !== prev.mtimeMs) {
console.log(`File '${pollFilePath}' modified (mtime changed). New size: ${curr.size} bytes.`);
}
});
setTimeout(() => {
console.log('\n--- Simulating polled file change ---');
fs.appendFileSync(pollFilePath, '\nAnother line added to polled file.');
setTimeout(() => {
fs.unwatchFile(pollFilePath);
console.log(`\nStopped watching '${pollFilePath}'.`);
fs.unlinkSync(pollFilePath);
}, 2000);
}, 1500);
๊ธ๋ก๋ฒ ํ๊ฒฝ์์์ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ๋ ํ์ผ ์์คํ ๊ณผ ์ํธ ์์ฉํ๋ ๋ชจ๋ ํ๋ก๋์ ์ค๋น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ์ฅ ์ค์ํฉ๋๋ค. ํ์ผ ์์ ์ ๊ถํ ๋ฌธ์ , ๋์คํฌ ๊ณต๊ฐ ๋ถ์กฑ ์ค๋ฅ, ํ์ผ์ ์ฐพ์ ์ ์์, I/O ์ค๋ฅ, ๋คํธ์ํฌ ๋ฌธ์ (๋คํธ์ํฌ ๋ง์ดํธ ๋๋ผ์ด๋ธ์ ๊ฒฝ์ฐ) ๋๋ ๋์ ์ก์ธ์ค ์ถฉ๋๊ณผ ๊ฐ์ ์๋ง์ ์ด์ ๋ก ์คํจํ ์ ์์ต๋๋ค. TypeScript๋ ํ์ ๊ด๋ จ ๋ฌธ์ ๋ฅผ ํฌ์ฐฉํ๋ ๋ฐ ๋์์ด ๋์ง๋ง, ๋ฐํ์ ์ค๋ฅ๋ ์ฌ์ ํ ์ ์คํ ๊ด๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
์ค๋ฅ ์ฒ๋ฆฌ ์ ๋ต
- ๋๊ธฐ ์์ : ํญ์ `fs.xxxSync` ํธ์ถ์ `try...catch` ๋ธ๋ก์ผ๋ก ๋ํํ์ญ์์ค. ์ด๋ฌํ ๋ฉ์๋๋ ์ค๋ฅ๋ฅผ ์ง์ ๋์ง๋๋ค.
- ๋น๋๊ธฐ ์ฝ๋ฐฑ: `fs` ์ฝ๋ฐฑ์ ์ฒซ ๋ฒ์งธ ์ธ์๋ ํญ์ `err: NodeJS.ErrnoException | null`์ ๋๋ค. ํญ์ ์ด `err` ๊ฐ์ฒด๋ฅผ ๋จผ์ ํ์ธํ์ญ์์ค.
- ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ (`fs/promises`): `await`์ ํจ๊ป `try...catch`๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ `.then()` ์ฒด์ธ๊ณผ ํจ๊ป `.catch()`๋ฅผ ์ฌ์ฉํ์ฌ ๊ฑฐ๋ถ๋ฅผ ์ฒ๋ฆฌํ์ญ์์ค.
์ค๋ฅ ๋ก๊น ํ์์ ํ์คํํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๋ฅ ํผ๋๋ฐฑ์ด ์ฌ์ฉ์ ๋๋ฉด์ธ ๊ฒฝ์ฐ ์ค๋ฅ ๋ฉ์์ง์ ๋ํ ๊ตญ์ ํ(i18n)๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
import * as fs from 'fs';
import { promises as fsPromises } from 'fs';
import * as path from 'path';
const problematicPath = path.join('non_existent_dir', 'file.txt');
// ๋๊ธฐ ์ค๋ฅ ์ฒ๋ฆฌ
try {
fs.readFileSync(problematicPath, 'utf8');
} catch (error: any) {
console.error(`Sync Error: ${error.code} - ${error.message} (Path: ${problematicPath})`);
}
// ์ฝ๋ฐฑ ๊ธฐ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ
fs.readFile(problematicPath, 'utf8', (err, data) => {
if (err) {
console.error(`Callback Error: ${err.code} - ${err.message} (Path: ${problematicPath})`);
return;
}
// ... ๋ฐ์ดํฐ ์ฒ๋ฆฌ
});
// ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ
async function safeReadFile(filePath: string): Promise
๋ฆฌ์์ค ๊ด๋ฆฌ: ํ์ผ ๋์คํฌ๋ฆฝํฐ ๋ซ๊ธฐ
`fs.open`(๋๋ `fsPromises.open`)์ ์ฌ์ฉํ ๋๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ์์ ์๋ฃ ํ `fs.close`(๋๋ `fileHandle.close()`)๋ฅผ ์ฌ์ฉํ์ฌ ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ํญ์ ๋ซ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๊ทธ๋ ๊ฒ ํ์ง ์์ผ๋ฉด ๋ฆฌ์์ค ๋์๊ฐ ๋ฐ์ํ์ฌ ์ด์ ์ฒด์ ์ ์ด๋ฆฐ ํ์ผ ์ ํ์ ๋๋ฌํ๊ณ ์ ์ฌ์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ถฉ๋ํ๊ฑฐ๋ ๋ค๋ฅธ ํ๋ก์ธ์ค์ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.
`FileHandle` ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ `fs/promises` API๋ ์ผ๋ฐ์ ์ผ๋ก ์ด ์์ ์ ๋จ์ํํฉ๋๋ค. `fileHandle.close()`๋ ์ด ๋ชฉ์ ์ ์ํด ํน๋ณํ ์ค๊ณ๋์์ผ๋ฉฐ, `FileHandle` ์ธ์คํด์ค๋ `Disposable`์ ๋๋ค (Node.js 18.11.0+ ๋ฐ TypeScript 5.2+๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ).
๊ฒฝ๋ก ๊ด๋ฆฌ ๋ฐ ํฌ๋ก์ค ํ๋ซํผ ํธํ์ฑ
ํ์ผ ๊ฒฝ๋ก๋ ์ด์ ์ฒด์ ๋ง๋ค ํฌ๊ฒ ๋ค๋ฆ ๋๋ค (์: Windows์ `\`, Unix ๊ณ์ด ์์คํ ์ `/`). Node.js `path` ๋ชจ๋์ ํฌ๋ก์ค ํ๋ซํผ ํธํ ๋ฐฉ์์ผ๋ก ํ์ผ ๊ฒฝ๋ก๋ฅผ ๊ตฌ์ถํ๊ณ ํ์ฑํ๋ ๋ฐ ํ์์ ์ด๋ฉฐ, ์ด๋ ๊ธ๋ก๋ฒ ๋ฐฐํฌ์ ํ์์ ์ ๋๋ค.
- `path.join(...paths)`: ์ฃผ์ด์ง ๋ชจ๋ ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ๋ฅผ ํจ๊ป ์ฐ๊ฒฐํ์ฌ ๊ฒฐ๊ณผ ๊ฒฝ๋ก๋ฅผ ์ ๊ทํํฉ๋๋ค.
- `path.resolve(...paths)`: ๊ฒฝ๋ก ๋๋ ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ ์ํ์ค๋ฅผ ์ ๋ ๊ฒฝ๋ก๋ก ํด๊ฒฐํฉ๋๋ค.
- `path.basename(path)`: ๊ฒฝ๋ก์ ๋ง์ง๋ง ๋ถ๋ถ์ ๋ฐํํฉ๋๋ค.
- `path.dirname(path)`: ๊ฒฝ๋ก์ ๋๋ ํ ๋ฆฌ ์ด๋ฆ์ ๋ฐํํฉ๋๋ค.
- `path.extname(path)`: ๊ฒฝ๋ก์ ํ์ฅ์๋ฅผ ๋ฐํํฉ๋๋ค.
TypeScript๋ `path` ๋ชจ๋์ ๋ํ ์ ์ฒด ํ์ ์ ์๋ฅผ ์ ๊ณตํ์ฌ ํด๋น ํจ์๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
import * as path from 'path';
const dir = 'my_app_data';
const filename = 'config.json';
// ํฌ๋ก์ค ํ๋ซํผ ๊ฒฝ๋ก ๊ฒฐํฉ
const fullPath: string = path.join(__dirname, dir, filename);
console.log(`Cross-platform path: ${fullPath}`);
// ๋๋ ํ ๋ฆฌ ์ด๋ฆ ๊ฐ์ ธ์ค๊ธฐ
const dirname: string = path.dirname(fullPath);
console.log(`Directory name: ${dirname}`);
// ๊ธฐ๋ณธ ํ์ผ ์ด๋ฆ ๊ฐ์ ธ์ค๊ธฐ
const basename: string = path.basename(fullPath);
console.log(`Base name: ${basename}`);
// ํ์ผ ํ์ฅ์ ๊ฐ์ ธ์ค๊ธฐ
const extname: string = path.extname(fullPath);
console.log(`Extension: ${extname}`);
๋์์ฑ ๋ฐ ๊ฒฝ์ ์กฐ๊ฑด
ํนํ ์ฐ๊ธฐ ๋๋ ์ญ์ ์ ๊ฐ์ ์ฌ๋ฌ ๋น๋๊ธฐ ํ์ผ ์์ ์ด ๋์์ ์์๋ ๋ ๊ฒฝ์ ์กฐ๊ฑด์ด ๋ฐ์ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ํ ์์ ์ด ํ์ผ์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ ๋ค๋ฅธ ์์ ์ด ์ฒซ ๋ฒ์งธ ์์ ์ด ์คํ๋๊ธฐ ์ ์ ํ์ผ์ ์ญ์ ํ๋ฉด ์ฒซ ๋ฒ์งธ ์์ ์ด ์๊ธฐ์น ์๊ฒ ์คํจํ ์ ์์ต๋๋ค.
- ์ค์ ๊ฒฝ๋ก ๋ก์ง์ `fs.existsSync` ์ฌ์ฉ์ ํผํ๊ณ ; `fs.access`๋ฅผ ์ ํธํ๊ฑฐ๋ ๋จ์ํ ์์ ์ ์๋ํ๊ณ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ์ญ์์ค.
- ๋ฐฐํ์ ์ก์ธ์ค๊ฐ ํ์ํ ์์ ์๋ ์ ์ ํ `flag` ์ต์ (์: ๋ฐฐํ์ ์ฐ๊ธฐ์ฉ `'wx'`)์ ์ฌ์ฉํ์ญ์์ค.
- ๋งค์ฐ ์ค์ํ ๊ณต์ ๋ฆฌ์์ค ์ก์ธ์ค๋ฅผ ์ํด ์ ๊ธ ๋ฉ์ปค๋์ฆ(์: ํ์ผ ์ ๊ธ ๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ค ์ ๊ธ)์ ๊ตฌํํ์ญ์์ค. ํ์ง๋ง ์ด๋ ๋ณต์ก์ฑ์ ์ถ๊ฐํฉ๋๋ค.
๊ถํ (ACL)
ํ์ผ ์์คํ ๊ถํ(์ก์ธ์ค ์ ์ด ๋ชฉ๋ก ๋๋ ํ์ค Unix ๊ถํ)์ ์ผ๋ฐ์ ์ธ ์ค๋ฅ ์์ธ์ ๋๋ค. Node.js ํ๋ก์ธ์ค์ ํ์ผ ๋ฐ ๋๋ ํ ๋ฆฌ๋ฅผ ์ฝ๊ณ , ์ฐ๊ณ , ์คํํ๋ ๋ฐ ํ์ํ ๊ถํ์ด ์๋์ง ํ์ธํ์ญ์์ค. ์ด๋ ์ปจํ ์ด๋ํ๋ ํ๊ฒฝ์ด๋ ํ๋ก์ธ์ค๊ฐ ํน์ ์ฌ์ฉ์ ๊ณ์ ์ผ๋ก ์คํ๋๋ ๋ค์ค ์ฌ์ฉ์ ์์คํ ์์ ํนํ ์ค์ํฉ๋๋ค.
๊ฒฐ๋ก : ๊ธ๋ก๋ฒ ํ์ผ ์์คํ ์์ ์ ์ํ ํ์ ์์ ์ฑ ์์ฉ
Node.js `fs` ๋ชจ๋์ ํ์ผ ์์คํ ๊ณผ ์ํธ ์์ฉํ๊ธฐ ์ํ ๊ฐ๋ ฅํ๊ณ ๋ค์ฌ๋ค๋ฅํ ๋๊ตฌ์ด๋ฉฐ, ๊ธฐ๋ณธ์ ์ธ ํ์ผ ์กฐ์๋ถํฐ ๊ณ ๊ธ ์คํธ๋ฆผ ๊ธฐ๋ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊น์ง ๋ค์ํ ์ต์ ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ์์ ์์ TypeScript๋ฅผ ๊ณ์ธตํํ๋ฉด ์ปดํ์ผ ์๊ฐ ์ค๋ฅ ๊ฐ์ง, ํฅ์๋ ์ฝ๋ ๋ช ํ์ฑ, ์ฐ์ํ ๋๊ตฌ ์ง์ ๋ฐ ๋ฆฌํฉํ ๋ง ์ค ํฅ์๋ ์ ๋ขฐ์ฑ๊ณผ ๊ฐ์ ๊ท์คํ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค. ์ด๋ ๋ค์ํ ์ฝ๋๋ฒ ์ด์ค์ ๊ฑธ์ณ ์ผ๊ด์ฑ๊ณผ ๋ชจํธ์ฑ ๊ฐ์๊ฐ ํ์์ ์ธ ๊ธ๋ก๋ฒ ๊ฐ๋ฐํ์ ํนํ ์ค์ํฉ๋๋ค.
์์ ์ ํธ๋ฆฌํฐ ์คํฌ๋ฆฝํธ๋ฅผ ๊ตฌ์ถํ๋ ๋๊ท๋ชจ ์ํฐํ๋ผ์ด์ฆ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ , Node.js ํ์ผ ์์ ์ TypeScript์ ๊ฐ๋ ฅํ ํ์ ์์คํ ์ ํ์ฉํ๋ฉด ๋ ์ ์ง ๊ด๋ฆฌ ๊ฐ๋ฅํ๊ณ ์ ๋ขฐํ ์ ์์ผ๋ฉฐ ์ค๋ฅ ๋ฐฉ์ง ์ฝ๋๋ฅผ ์ป์ ์ ์์ต๋๋ค. ๋ ๊น๋ํ ๋น๋๊ธฐ ํจํด์ ์ํด `fs/promises` API๋ฅผ ์์ฉํ๊ณ , ๋๊ธฐ ๋ฐ ๋น๋๊ธฐ ํธ์ถ ๊ฐ์ ๋ฏธ๋ฌํ ์ฐจ์ด๋ฅผ ์ดํดํ๋ฉฐ, ํญ์ ๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ ๋ฐ ํฌ๋ก์ค ํ๋ซํผ ๊ฒฝ๋ก ๊ด๋ฆฌ๋ฅผ ์ฐ์ ์ํ์ญ์์ค.
์ด ๊ฐ์ด๋์์ ๋ ผ์๋ ์์น๊ณผ ์์๋ฅผ ์ ์ฉํจ์ผ๋ก์จ ์ ์ธ๊ณ ๊ฐ๋ฐ์๋ค์ ์ฑ๋ฅ์ด ๋ฐ์ด๋๊ณ ํจ์จ์ ์ผ ๋ฟ๋ง ์๋๋ผ ๋ณธ์ง์ ์ผ๋ก ๋ ์์ ํ๊ณ ์ดํดํ๊ธฐ ์ฌ์ด ํ์ผ ์์คํ ์ํธ ์์ฉ์ ๊ตฌ์ถํ์ฌ ๊ถ๊ทน์ ์ผ๋ก ๋ ๋์ ํ์ง์ ์ํํธ์จ์ด ๊ฒฐ๊ณผ๋ฌผ์ ๊ธฐ์ฌํ ์ ์์ต๋๋ค.