Java ‐ Input & Output - dnwls16071/Backend_Study_TIL GitHub Wiki
- 자바 프로세스가 가지고 있는 데이터를 밖으로 보내려면 출력 스트림을 사용하면 되고 반대로 외부 데이터를 자바 프로세스 안으로 가져오려면 입력 스트림을 사용하면 된다.
- 참고로 각 스트림은 단방향으로 흐른다.
-
FileOutputStream
- 파일에 데이터를 출력하는 스트림
- 파일이 없으면 파일을 자동으로 만들고 데이터를 해당 파일에 저장한다.
- 폴더는 미리 만들어두어야 한다.
-
write()
- byte 단위로 값을 출력한다.
-
FileInputStream
- 파일에서 데이터를 읽어오는 스트림
-
read()
- 파일에서 데이터를 byte 단위로 하나씩 읽어온다.
- 파일의 끝(EOF, End of File)에 도달하면 -1을 리턴한다.
-
close()
- 파일에 접근하는 것은 자바 입장에서 외부 자원을 사용하는 것이다.
- 자바에서 내부 객체는 자동으로 GC가 되지만 외부 자원은 사용 후 반드시 닫아주어야 한다.
-
read(byte[], offset, length)
- 스트림의 내용을 부분적으로 읽거나, 읽은 내용을 처리하면서 스트림을 계속해서 읽어야 할 경우에 적합하다.
- 메모리 사용량을 제어할 수 있다.
- 파일이나 스트림에서 일정한 크기의 데이터를 반복적으로 읽어야 할 때 유용하다.
-
readAllBytes()
- 한 번의 호출로 모든 데이터를 읽을 수 있어 편리하다.
- 작은 파일이나 메모리에 모든 내용을 올려 처리해야 하는 경우에 적합하다.
- 메모리 사용량을 제어할 수 없다.
- 큰 파일의 경우 OutOfMemoryError가 발생할 수 있다.
- 현대 컴퓨터는 대부분 byte 단위로 데이터를 주고 받는다. 참고로 bit 단위는 너무 작기 때문에 byte 단위를 기본으로 사용한다.
- 이렇게 데이터를 주고받는 것을 Input/Output(I/O)라 한다.
- 자바 내부에 있는 데이터를 외부에 전달할 때 각각 데이터를 주고 받는 방식이 다르면 불편하기 때문에 이런 문제를 해결하기 위해 자바는
InputStream
,OutputStream
이라는 기본 추상 클래스를 제공한다.
-
InputStream
과OutputStream
이 다양한 스트림을 추상화하고 기본 기능에 대한 표준을 잡아둔 덕에 편리하게 입출력 작업을 수행할 수 있다.- 일관성 : 모든 종류 입출력 작업에 대해 동일한 인터페이스를 사용할 수 있어 코드 일관성이 유지된다.
- 유연성 : 실제 데이터 소스나 목적지가 무엇인지에 관계없이 동일한 방식으로 코드를 작성할 수 있다.
- 확장성 : 새로운 유형의 입출력 스트림을 쉽게 추가할 수 있다.
- 재사용성 : 다양한 스트림 클래스들을 조합해 복잡한 입출력 작업을 수행할 수 있다.
- 에러 처리 : 표준화된 예외 처리 메커니즘을 통해 일관된 방식으로 오류를 처리할 수 있다.
- 자바에서 운영체제를 통해 디스크에 1Byte씩 전달하면 운영체제나 하드웨어 레벨에서 여러가지 최적화가 발생한다.
- 따라서 실제로 디스크에 1Byte씩 계속 쓰는 것은 아니다.
- 자바에서 1Byte씩
write()
나read()
를 호출할 때마다 운영체제로의 시스템 콜이 발생하고 이 시스템 콜 자체가 상당한 오버헤드를 유발한다. - 운영체제와 하드웨어가 어느 정도 최적화를 제공하더라도 자주 발생하는 시스템 콜로 인한 성능 저하는 피할 수 없다. 결국 자바에서
read()
,write()
호출 횟수를 줄여서 시스템 콜 횟수를 줄여야 한다.
- 스트림은
byte
만 사용할 수 있다. - 스트림을 문자로 저장할 수 있도록 해주는 것이 바로
OutputStreamWriter
,InputStreamReader
이다.
- 모든 데이터는
byte
단위로 저장된다. - 따라서 Reader/Writer가 아무리 문자를 다룬다고 해도 문자를 바로 저장할 순 없다.
- 결과적으로 해당 클래스에 문자를 전달하면 결과적으로 내부에서는 지정된 문자 집합을 사용해서 문자를
byte
를 인코딩해서 저장한다.
-
객체 직렬화를 사용하지 않는 이유
- 버전 관리의 어려움 - 클래스 구조가 변경되면 이전에 직렬화된 객체와의 호환성 문제가 발생, serialVersionUID 관리가 복잡하다.
- 플랫폼 종속성 - 자바 직렬화는 자바 플랫폼에 종속적이어서 다른 언어나 시스템과의 상호 운용성이 떨어진다.
- 성능 이슈 - 직렬화/역직렬화 과정이 상대적으로 느리고 리소스를 많이 사용한다.
- 유연성 부족 - 직렬화된 형식은 커스터마이징하기 어렵다.
- 크기 효율성 - 직렬화된 데이터 크기가 상대적으로 크다.
- 플랫폼 종속성 문제를 해결하기 위해 XML이라는 기술이 인기를 끌었다.
- 허나 XML은 복잡성과 무거움이라는 문제가 존재한다.
- 태그를 포함한 XML 문서 크기가 커서 네트워크 전송 비용도 증가했다.
- JSON은 가볍고 간결하며 자바스크립트와의 자연스러운 호환성 덕분에 웹 개발자들 사이에서 빠르게 확산되었다.
- 웹 API와 RESTful 서비스가 대중화되면서 JSON은 표준 데이터 교환 포맷으로 자리 잡았다.
- JSON은 거의 모든 곳에서 호환이 가능하고 사람이 읽고 쓰기 쉬운 포맷이어서 디버깅과 개발이 쉽다.
- 매우 작은 용량으로 더 빠른 속도가 필요하다면 Protobuf, Avro 등을 고려할 수 있다.
- 하지만 이런 기술들은 호환성은 떨어지지만 용량과 성능 최적화가 되어 있어 매우 빠르다.
- 다만 byte 기반이기 때문에 사람이 읽기 쉽지 않다.
결론 : 자바 객체 직렬화는 사용하지 마라.