Node.js - File System의 사용과 async & await 처리

JUGNMIN LEE·2021년 6월 18일
3

Node.js

목록 보기
2/2
post-thumbnail

Node.js에 fs라는 객체와 async & await에 대해 포스팅을 해본다


fs ??

파일 처리와 관련된 작업을 하는 모듈로, 보통 FileSystem을 줄여서 fs 모듈이라고 줄여 부릅니다. 노드에서 가장 중요한 모듈 중 하나이다.

이와 관련된 메소드는 엄청 많지만 기초적인 파일 읽기와 쓰기 기능에만 초점을 맞춰 정리를 해보려한다

그에 따른 대부분의 메소드들이 동기/비동기로 나뉘는데, Sync라는 이름이 붙어있는 메소드가 동기방식을 사용한다고 보면 된다

동기적 읽기 방식을 사용하면 파일을 읽으면서 다른 작업을 동시에 할 수 없다 하지만 비동기적으로 읽으면 파일을 읽으면서 다른 작업도 동시에 수행할 수 있고, 파일을 다 읽으면 매개변수 callback으로 전달한 함수가 호출이 된다 그리고 비동기 형식은 항상 마지막 인수가 수행 완료 시 호출할 콜백 함수로 작성되어야 한다

주로 비동기적 형식을 많이 사용하지만, 서버 시작 시 설정 파일을 읽는 작업과 같이 동기적 형식이 더 적절한 경우도 있으니 잘 확인해야한다




fs method type

fs.readFile(filename, [options], callback) : filename의 파일을 [options]의 방식으로 읽은 후 callback으로 전달된 함수를 호출합니다. (비동기적)
fs.readFileSync(filename, [options]) : filename의 파일을 [options]의 방식으로 읽은 후 문자열을 반환합니다.(동기적)
fs.writeFile(filename, data, [options], callback) : filename의 파일에 [options]의 방식으로 data 내용을 쓴 후 callback 함수를 호출합니다.(비동기적)
fs.writeFileSync(filename, data, [options]) : filename의 파일에 [options]의 방식으로 data 내용을 씁니다.(동기적)
goormEdu 발췌 내용

아래로 예제를 확인하며 read와 write 하는 방법 그리고 동기 비동기 처리 코드에 대해 확인해보자.

readFile.js를 확인하자

const fs = require('fs').promises;

fs.readFile('./README.md')
    .then((data)=>{
        console.log(data);
        console.log(data.toString());
    })
    .catch ((err) => {
        throw err;
    });

README.md라는 파일을 읽어 달라는 내용이다
그래서 노드를 실행하면 정상적으로 읽어 내는 것을 확인 할 수 있다.


그러면 읽기가 된다면 쓰기는??

아래의 writeFile.js를 확인하자

const fs = require('fs').promises;

fs.writeFile('./readme.txt', '글이 입력됩니다.')
    .then(() => {
        return fs.readFile('./readme.txt');
    })
    .then((data) => {
        console.log(data.toString());
    })
    .catch ((err) => {
        throw err;
    });

위의코드는 readme.txt라는 파일을 만들어 거기에 '글이 입력됩니다' 라는 문자열이 작성이 되고
then을 이용하여 아까 확인했던 readFile이라는 메소드로 작성한 파일을 읽어내는 것을 볼 수 있다.


요번엔 readFile에 Sync를 붙인 readFileSync라는 메소드로 읽는 것을 동기적으로 실행해보자

sync.js 를 확인하자

const fs = require('fs');

let data = fs.readFileSync('./readme.txt')
console.log('1번', data.toString())
data = fs.readFileSync('./readme.txt')
console.log('2번', data.toString())
data = fs.readFileSync('./readme.txt')
console.log('3번', data.toString())
data = fs.readFileSync('./readme.txt')
console.log('4번', data.toString())
data = fs.readFileSync('./readme.txt')
console.log('5번', data.toString())

동기적이지 않은 비동기적인 일반 readFile의 경우 여러번 실행이 되면 어떻게 될까?
아래의 비동기코드인 async.js 를 보자

const fs = require('fs');

fs.readFile('./readme.txt', (err, data) => {
    if (err) {
        throw err;
    }
    console.log('1번', data.toString())
})
fs.readFile('./readme.txt', (err, data) => {
    if (err) {
        throw err;
    }
    console.log('2번', data.toString())
})
fs.readFile('./readme.txt', (err, data) => {
    if (err) {
        throw err;
    }
    console.log('3번', data.toString())
})
fs.readFile('./readme.txt', (err, data) => {
    if (err) {
        throw err;
    }
    console.log('4번', data.toString())
})

위의 코드는 비동기적으로 실행이된다

값이 랜덤으로 섞여서 찍히게 된다


그렇다면 이 비동기를 동기적으로 바꾸는 코드에 대해 아래의 첫번째 방법인 콜백으로 나타낼 수 있다.

asyncOrder.js 를 보자

const fs = require('fs');

fs.readFile('./readme.txt', (err, data) => {
    if (err) {
        throw err;
    }
    console.log('1번', data.toString())
    fs.readFile('./readme.txt', (err, data) => {
        if (err) {
            throw err;
        }
        console.log('2번', data.toString())
        fs.readFile('./readme.txt', (err, data) => {
            if (err) {
                throw err;
            }
            console.log('3번', data.toString())
            fs.readFile('./readme.txt', (err, data) => {
                if (err) {
                    throw err;
                }
                console.log('4번', data.toString())
            })
        })
    })
})

아주 지저분한 콜백지옥이다 그래도 그 위의 비동기 코드를 동기적으로 실행으로 바꾸었다

여기서 궁금증이 생기기 마련이다 이것도 동기코드인데 그렇다면 똑같은 동기 코드인 Sync와는 무슨 차이가 있을까?

똑같은 동기 코드 아닌가????

그 차이는 바로 해당 파일이 여러번 실행 될 경우에 달라진다 readFileSync의 경우 해당 파일이 여러번 실행된다면 백그라운드로 하나씩 실행되지만

asyncOrder의 경우에는 백그라운드에 실행되는 횟수만큼 다같이 넘어가서 실행이된다는 점이 차이가 있다.


요번엔 위의 콜백지옥을 promise로 해결하여 간편하게 바꿔보자

asyncOrderPromise부분을 보자

const fs = require('fs').promises;

fs.readFile('./readme.txt')
    .then((data)=>{
        console.log('1번', data.toString());
        return fs.readFile('./readme.txt');
    })
    .then((data)=>{
        console.log('2번', data.toString());
        return fs.readFile('./readme.txt');
    })
    .then((data)=>{
        console.log('3번', data.toString());
        return fs.readFile('./readme.txt');
    })
    .then((data)=>{
        console.log('4번', data.toString());
    })
    .catch ((err) => {
        throw err;
    });

promise를 이용하여 깔금하게 구성이 됬음을 알 수 있다.


요번엔 async await을 사용하여 더 깔끔한 코드를 만들자

asyncOrderPromise.js를 확인하자

const fs = require('fs').promises;

async function main() {
    let data = await fs.readFile('./readme.txt')
    console.log('1번', data.toString());
    data = await fs.readFile('./readme.txt')
    console.log('2번', data.toString());
    data = await fs.readFile('./readme.txt')
    console.log('3번', data.toString());
    data = await fs.readFile('./readme.txt')
    console.log('4번', data.toString());
}
main();

이로써 fs에 read와 write 그리고 읽기의 동기 비동기적 코드 작성에 대해 알아 봤다

비동기로 하되 순서를 지키는게 동시성도 살리고 순서도 지키는 좋은 방법이다

sync는 편하긴 하지만 실제로 서버에서 사용하면 문제가 발생한다는 것을 알아두자 !

profile
Frontend Developer

0개의 댓글