본래 표준 입력이란 키보드로 직접 받아오고
표준 출력은 이를 화면에 그대로 출력되는 것을 말하는데,
키보드로 표준 입력을 받거나 화면으로 표준 출력을 하는 것이 아닌
사용자의 마음대로 입력, 출력을 재지정하겠다는 말이다.
대표적으로 파일로 표준 입력을 받고 파일로 표준 출력을 받는 등의 행위가 이에 속한다.
자바에선 표준 입출력을 지원하는 도구들이 존재한다.
System.in 은 자바에서 표준 입력을 나타내며 InputStream 로 반환 → 바이트 스트림으로 처리
System.out 은 자바에서 표준 출력을 나타내는 PrintStream 로 반환 → 문자 스트림으로 처리
이 표준 입출력을 가로채서 리다이렉션 하는 기능들 역시 존재한다.
System.setIn() 에 데이터를 입력하면 System.in 에 해당 데이터가 리다이렉션 되며,
System.setOut() 에 데이터를 입력하면 System.out 에 해당 데이터가 리다이렉션 된다.
원하는 파일을 System.setIn() 으로 리다이렉션 하려면 아래와 같이 사용하면 된다.
public class Main {
public static void main(String[] args) throws IOException {
// 가로채서 System.in 에 해당 파일이 주입
System.setIn(new FileInputStream("원하는 파일 경로"));
BufferedReader = reader = new BufferedReader(new InputStreamReader(System.in));
reader.leadLine()
}
}
매개변수로 데이터를 받아와 원하는 데이터를 주입하려면
아래와 같이 Scanner 를 만들어 이용하는 것이 더 좋은 방법일 수 있다.
// 입력
public static Scanner genScanner (final String input) {
final InputStream in = new ByteArrayInputStream(input.getByte();
return new Scanner
}
// 출력
public static ByteArrayOutputStream setOutToByteArray() {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));
return output;
}
// setOutToByteArray 메서드 사용 후 정리, 다시 정상화 작업
public static void clearSetOutToByteArray(final ByteArrayOutputStream output) {
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
try {
output.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Scanner 를 이용하는 방식과
System.setIn() + BufferedReader 를 조합하여 사용하는 방식은
각각의 장단점이 존재한다.
| 항목 | Scanner 이용 방식 | System.setIn + BufferedReader 방식 |
|---|---|---|
| 편리성 | Scanner는 공백으로 구분된 단어 단위 또는 숫자 읽기 등 고수준 입력 처리 가능 | BufferedReader는 한 줄씩 읽기 등 문자 스트림에 적합 |
| 표준 입력 변경 여부 | 표준 입력 변경 없음 | System.setIn으로 실제 표준 입력을 변경 |
| 테스트 시 의존성 | 독립적 (표준 입력 변경 없이 메모리에서 동작) | 표준 입력을 변경하므로 테스트 후 복원이 필요 |
class Test {
AppConfig appConfig = new AppConfig();
@Test
@DisplayName("등록 명령 정상 작동")
void register_test() {
ByteArrayOutputStream output = TestUtil.setOutToByteArray();
Scanner scanner = TestUtil.genScanner(
"""
등록
명언1
사람1
종료
"""
);
appConfig.wiseSayingController(scanner).run();
String result = output.toString().trim();
assertTrue(result.contains("명언이 등록되었습니다."));
TestUtil.clearSetOutToByteArray(output);
}
여기서 중요한건 입출력 리다이렉션을 Scanner 호출보다 먼저 해줘야한다.
Sysyem.setOut() 은 전역 설정으로, 이를 호출하면 이후 발생하는 모든
System.out.printIn() 출력이 ByteArrayOutputStream 로 리다이렉션된다.
Scanner 가 먼저 실행되면 System.out 에 대한 리다이렉션 설정이 제대로 이루어지지 않는다.