[자바스크립트] fs 모듈, readline 모듈

송히·2023년 7월 31일
1

개발 공부 🐨

목록 보기
1/15
post-thumbnail

node.js에서 fs 모듈로 입력을 받아 문제를 풀다보면 런타임 에러 (EACCES)가 발생할 수 있습니다.
이러한 문제들은 readline 모듈을 사용하여 풀어야 합니다.

저도 몇 번을 시도해도 자꾸 런타임 에러가 뜨길래 구글링 해보고 알게 되었습니다 ㅎㅎ ㅠㅠ

fs모듈과 readline모듈의 사용법, 간단히 두 가지를 비교한 것에 대해 공부했습니다😊


1. fs 모듈

fs는 FileSystem의 약자로, 파일 처리와 관련된 모듈입니다.
fs 모듈은 Node.js에 내장되어 있기 때문에 불러와서 사용하면 됩니다.

1-1. fs 모듈 불러오기

fs 모듈을 불러오는 방법은 CommonJS, ES6 2가지 방식이 있습니다.

const fs = require("fs");

먼저 CommonJS 방식입니다. 저는 이 방식을 사용하여 진행하겠습니다.
자바스크립트의 모듈화 명세를 만든 그룹 중 하나인 CommonJS에서는 모듈을 이용할 때 require()를 사용했고, 이것은 큰 의미를 가져 하나의 방식이 되었습니다.

import fs from "fs";

다음은 ES6 방식입니다.
ES6(ES2015) 부터는 ES6 Module이라는 개념으로 자바스크립트에서 자체 모듈화를 지원합니다. import / export 로 모듈을 사용할 수 있고, 이 방법을 사용하려면 ES 모듈 시스템을 사용하는 프로젝트여야 합니다.

1-2. 입출력 처리

let input = fs.readFileSync("/dev/stdin").toString().trim();
  • readFileSync(): 입력 값을 가져온 후 그 값을 이용해 문제를 푸는 것이므로, 파일을 읽어온 후 코드가 동작해야함. 따라서 동기식을 사용함

  • "/dev/stdin": 백준 사이트에서 문제를 풀 때 사용되는 문장. 필요에 맞게 경로를 바꾸어 사용

  • toString(): 입력 값을 받을 때 toString()을 포함시키는 이유는 fs.readFileSync("/dev/stdin")의 반환값은 버퍼 객체이기 때문에 fs.readFileSync("/dev/stdin", "utf8")처럼 인수로 인코딩 지정을 하지 않으면 사람이 읽을 수 없는 형식이기 때문. 따라서 문자열로 바꿔주는 메서드를 사용해줌

  • trim(): 입력 값을 받을 때 trim()을 사용하는 이유는 입력 값의 마지막에 개행문자("\n")이 포함되는 경우가 있는데, 이를 제거하지 않고 사용하면 의도하지 않은 값이 나올 수 있기 때문. 따라서 미리 제거해주는 것

    ex) let input = "1\n2\n3\n";
        console.log(input.split("\n")); // ['1', '2', '3', '']
        console.log(input.trim().split("\n")); // ['1', '2', '3']

vscode에서 문제를 풀어보고, 정답일 때 백준에서 채점 돌리는 사람이 많을 것이라고 생각합니다.
이때마다 파일 경로를 변경해주기 귀찮다면 다음과 같은 방법 사용을 추천합니다.

const filePath = process.platform === "linux" ? "/dev/stdin" : "./입력값.txt";
let input = fs.readFileSync(filePath).toString().trim();

백준 채점 서버는 리눅스이므로 리눅스 환경이라면 "/dev/stdin"를, 아니라면 본인 컴퓨터 속 입력값을 담아두는 파일("./입력값.txt")에서 값을 가져오도록 지정했습니다. 이 방법을 사용하면 매번 경로를 바꾸지 않아도 되어 간편합니다😄

1-2-1. 입력 값의 형식에 따른 입출력 처리

  • 입력 값이 하나일 때
const input=fs.readFileSync(/dev/stdin”).toString().trim();
  • 입력 값이 공백으로 구분된 한 줄일 때
const input=fs.readFileSync(/dev/stdin”).toString().trim().split(“ ”);
  • 입력 값이 여러 줄일 때
const input=fs.readFileSync(/dev/stdin”).toString().trim().split(“\n”);

이 외에도 다양한 경우가 있을 수 있는데, 상황에 맞게 응용하여 사용하시면 됩니다.

1-3. fs 모듈 최종 코드

const fs = require("fs");
let input = fs.readFileSync("/dev/stdin").toString().trim();

2. readline 모듈

Readable Stream에서 한 번에 한 줄씩 데이터를 읽을 수 있는 인터페이스를 제공하는 것으로, input과 output을 이용해 입출력을 한 줄씩 처리하는 모듈입니다.

2-1. readline 모듈 불러오기

const readline = require('readline')

readline 모듈을 불러오는 방법에도 CommonJS, ES6 2가지 방식이 있습니다.
저는 주로 사용되는 CommonJS 방식으로 진행하겠습니다.

2-2. 인터페이스 생성

const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
});

stdin는 standard input의 약자, stdout는 standard output의 약자입니다.

vscode에서 문제를 풀고 싶을 때는, input의 경로를 본인 컴퓨터 속 입력값를 담아두는 파일("./입력값.txt")로 변경하면 됩니다.

input: require("fs").createReadStream("./입력값.txt"),

2-3. 입출력 처리

rl.on("line", (line) => {
	/*입력 값을 처리하는 코드(내가 작성하는 부분)*/
	rl.close();
});

rl.on("close", () => {
	/*입력이 끝나고 실행할 코드, 출력 값 부분(내가 작성하는 부분)*/
	process.exit();
});
  • on(): 해당 메서드로 이벤트("line", "close")와 콜백함수(내가 작성하는 부분) 전달
  • “line”: 입력 값을 한 줄씩 읽어와 문자열 타입으로 전달하는 역할의 이벤트
  • rl.close(): 인터페이스를 종료하는 함수로, 무한히 입력 받는 것을 방지함

  • "close": 더 이상 입력 값이 없을 때 실행되는 이벤트. rl.close()로 인터페이스가 끝나면 시작됨
  • process.exit(): 프로세스를 종료하는 함수

rl.close()를 쓰지 않고 인터페이스를 종료시키고 싶다면, ctrl+c를 사용하면 됩니다.

rl.on("line", (line) => {
	/*입력 값을 처리하는 코드(내가 작성하는 부분)*/
	rl.close();
}).on("close", () => {
	/*입력이 끝나고 실행할 코드, 출력 값 부분(내가 작성하는 부분)*/
	process.exit();
});

위 코드처럼 on()메소드를 연결하여 하나의 입출력 코드로 작성할 수 있습니다.

2-3-1. 입력 값의 형식에 따른 입출력 처리

입력 값을 원하는 형태로 사용하기 위해서는 /*입력 값을 처리하는 코드(내가 작성하는 부분)*/에 직접 코드를 작성해야합니다.

  • 입력 값이 하나 혹은 한 줄일 때
  rl.on("line", (line) => {
      /*입력 값(하나 혹은 한 줄)은 line에 저장됨*/
      rl.close();
  });

  rl.on("close", () => {
      /*입력이 끝나고 실행할 코드, 출력 값 부분(내가 작성하는 부분)*/
      process.exit();
  });
  • 입력 값이 공백으로 구분된 한 줄일 때
rl.on("line", (line) {
  input = line.split(" ");
  rl.close();
});

rl.on("close", () {
  	/*입력이 끝나고 실행할 코드, 출력 값 부분(내가 작성하는 부분)*/
	process.exit();
});
  • 입력 값이 여러 줄일 때
rl.on("line", (line) {
  input.push(line);
  rl.close();
});

rl.on("close", () {
  	/*입력이 끝나고 실행할 코드, 출력 값 부분(내가 작성하는 부분)*/
	process.exit();
});

fs 모듈과 마찬가지로 기본 형태에서 상황에 맞게 응용하여 사용하시면 됩니다.

2-4. readline 모듈 최종 코드

const readline = require("readline");

const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
});

rl.on("line", (line) => {
	/*입력 값을 처리하는 코드(내가 작성하는 부분)*/
	rl.close();
});

rl.on("close", () => {
	/*입력이 끝나고 실행할 코드, 출력 값 부분(내가 작성하는 부분)*/
	process.exit();
});

3. fs 모듈readline 모듈 비교

fs 모듈readline 모듈
속도예제 입력 파일을 읽어오기에 빠름한 줄씩 처리해서 상대적으로 느림
발생 가능 오류런타임 에러 (EACCES) - 접근 권한 오류시간 초과
코드 길이짧음상대적으로 긺

참고한 자료: [백준] Node.js fs모듈로 입력값 받기
Node.js의 fs 모듈로 파일 입출력 처리하기
readline 모듈 사용하기
JavaScript readline 사용하기
[백준]node.js readline모듈로 입력받기

profile
데브코스 프론트엔드 5기

0개의 댓글

관련 채용 정보