Java IO 기반 입출력 관련 정리 from 이것이 자바다(책)

Updated:

IO 기반 입출력 및 네트워킹

java.io 패키지에는 파일 시스템 정보를 얻기 위한 File 클래스와 데이터를 입출력하기 위해 다양한 입출력 스트림 클래스를 제공하고 있다.

스트림 클래스는 크게 두 종류로 구분이 됨

IO2

다음처럼 바이트기반 스트림과 문자 기반 스트림이 있다.

바이트 기반 스트림은 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 받고 보낼 수 있다.

그러나 문자 기반은 오로지 문자만 보내는데 특화 되어있다.

그래서 대표적인 read()메소드와 write()메소드를 보도록하겠다.

IO2

우선 read()메소드를 보면, 결국 한개씩 읽거나, byte[] 배열의 길이만큼 읽거나, 아니면 len개만큼 읽는데, off부터 시작해서 읽고, 그렇게 읽은 값을 리턴을 한다는 의미이다. 해당 메소드는 InputStream 추상 클래스를 기준으로 작성 하였다.

다음은 write메소드이다.

IO3

마찬가지로, read()메소드와 아주 유사하다는 것을 알수 있다. 다만 다른것이 하나 있다면, flush() 메소드인데, 이 메소드는 그냥 버퍼에 쌓여있는것을 콘솔창에 출력을 하는 것이라고 보면된다.


다양한 입출력 형태가 있을수 있지만, 어려울수도 있는 File 클래스 관련해서만 서술을 하도록 하겠습니다.

File 클래스는 IO패키지에서 제공하며, 파일 크기, 속성, 이름 등의 정보를 얻어 낼뿐만 아니라, 파일 생성 및 삭제 기능도 제공하고 있다. 대표적으로는 다음과 같은 메소드들이 존재한다

파일 생성 및 삭제 그리고 파일의 존재 유무에 관한 메소드이다

IO4

주로 쓰이는 메소드들이다.

IO5

그리고 자바에서는 파일 입출력의 실행 성능을 향상 하기 위해, 중간에 메모리 버퍼를 이용하기도 한다.

대표적인 예가 입력에서는, BufferedInputStream과 BufferedReader가 존재한다. BufferedInputStream의 경우는 일반적인 파일의 형태의 입력을 향상시키기 위한 목적으로 존재하고, BufferedReader는 문자 입출력의 속도를 향상시키는 목적으로 존재한다. 실제로, BufferedReader의 경우는 Java로 문제를 푸시는 분들에 한해서, 누구나 다 알고있을 내용이기도 하다.

반대로 출력은 BufferedOutputStream과 BufferedWriter가 존재한다. 이외에도 다양하게 성능 향상을 위한 보조 스트림들이 존재한다고 한다.

다음은 직렬화(Serializable)에 대해 설명을 하려고 한다. 직렬화라는 것은 말그대로, 데이터들을 일렬로 길게 바이트 데이터로 변환하는 것을 말한다. 그리고 다음과 같은 형태로 쓰여야 직렬화를 할수 있습니다.

public class XXX implements Serializable {}

일반적으로, static과 transient가 붙어있는 경우를 제외하고는 모든 필드가 직렬화 대상이 가능하다. 그러나, 클래스내의 필드 멤버 변수가 변경이 될때, 직렬화나 역직렬화가 잘 안될수 있다. 왜냐하면, serialVersionUID 필드가 다를수 있기 때문이다. 이것은 직렬화 그리고 역직렬화할 클래스의 UID가 동일해야 한다는 조건이 필요하다. 사실 선언하지 않아도, 컴파일시 내부적으로 자동으로 만들어주지만, 클래스의 멤버 필드가 변경이 되고나서 컴파일을 다시 하면 UID가 달라지고, 역직렬화할 클래스의 UID가 달라지기 때문에, 제대로 역직렬화가 안될수 있다는 것이다.

이렇게 직렬화의 경우는 외부 API를 통해 데이터를 주고받을 경우 편하게 값을 직렬화하거나 역직렬화 할 용도로 쓰입니다. 그러나 ,왠만하면 다음과 같은 경우를 자제해야 합니다.

  1. 클래스의 변경이 빈번한 경우
  2. 외부에 보관할 경우(DB에 보관을 말함)

다음의 관련한 링크에서 serializable에 대해 깊게 설명이 되고있으니, 참고바랍니다

https://woowabros.github.io/experience/2017/10/17/java-serialize2.html


다음은 IP주소와 포트에 대해서 얘기를 하려고 한다. IP는 예로, 정확하게 집 주소라고 보면 될거같다. 그런데 이제 컴퓨터는 여러개의 IP주소를 가질수 있는데, 이런 경우는 한 개의 컴퓨터에 여러개의 네트워크 어댑터가 장착된 형태라고 생각을 하면 될거같다.

자바에서는 InetAddress 라는 클래스를 이용하여, IP주소를 알수 있다.

InetAddress[] iaArr = InetAddress.getAllByName("www.naver.com");
for(InetAddress remote : iaArr) {
	System.out.println("www.naver.com IP주소 : " + remote.getHostAddress());
}
// 다음과 같이 도메인주소(www.naver.com)을 입력을 해서도 해당 도메인의 IP를 얻을 수있다.
// 위처럼 여러개일수 있는게, 네이버의 경우는 실제로 IP가 한개는 아니기 때문

TCP 네트워킹 : TCP(Transmission Control Protocol)은 연결 지향적인 프로토콜이다. 여기서 프로토콜이라는 말이 어려울수있는데, 쉽게 말하면 서로 통신을 할때, 특정한 규칙을 만들어 놓고 , 그 규칙을 준수하면서 통신을 할때, 그 규칙과 관련한것이 프로토콜이라고 보면된다.

즉, 연결을 지향하는 규칙을 준수하며 상대방과 통신을 하겠다 라고 이해하면 될거같다

그럼 연결을 지향한다는게 무슨말인가, 클라이언트와 서버가 연결이 된 상태에서, 연결이 된 채널 혹은 선로를 통해 데이터를 주고 받겠다는 것이다. 그때 데이터를 Socket이라는 포맷을 이용해 주고 받겠다 라는 것이다. 여기서 연결이 되는 과정을 좀더 전문적인 용어로 풀면, 3-way-handshake, 4-way-handshake 라는 용어로 보통 나온다. 궁금하면 검색을 해보길 추천한다.

여기서 그럼 연결을 지향하지 않는다는 말도 있을것이다. 그게 우리가 익숙한 http통신 이라고 볼수 있다. http통신은 비연결지향으로 TCP 네트워킹과 성격이 다르다는 것만 우선 알아두자

그래서 클라이언트가 서버에 연결을 요청(connect())하면, 서버가 연결을 수락(accept())하고, 양쪽의 Socket 객체로부터 입력 스트림(InputStream)과 출력 스트림(OutputStream)을 통해 데이터를 얻을 수있다.

UDP 네트워킹 : UDP(User Datagram Protocol)는 비연결 지향이다. 여기서 http통신이 UDP통신과 똑같다라고 생각은 하면 안된다. (아이러니하게도, http/3 이전까지는 http는 TCP를 기반으로 한다)

그래서, TCP와는 다르게 클라이언트와 서버의 연결과정이 존재하지 않고, 발신자가 일방적으로 데이터를 보내는 형태이다. 그러다보니, 일부 패킷은 제대로 전달이 되지 않을수도 있다는 것이다. 그리고 패킷을 먼저 보낸다고 해서, 먼저 도착하는 것이 아니라, 느린 선로로 가게 되면 늦게 출발한 것이 먼저 도착을 할수도있다. 그러다보니, 데이터 전달의 신뢰보다는 속도가 중요한 곳에서 UDP를 사용하게 된다. 아무래도 간단한 예중에 하나가, 동영상 스트리밍이다. 물론 데이터의 화질이 중요할수 있겠지만, 버퍼링이 끊기지 않고 계속 본다는 것이 좀더 중요한 초점이기 때문이다.

위와 관련한 모든 예제들은 아래 링크 주소에 있으니 참고해주시면 감사하겠습니다.
https://github.com/goodgood619/ThisIsJava

Leave a comment