[JAVA] I/O

스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O

Stream

Stream이란 데이터가 이동하는 통로이다.

1. Input, Output 

2. Reader & Writer - 문자 스트림
InputStream & OutputStream - 바이트 스트림 (입출력 단위가 1byte)

3. nodeStream(기반 스트림) - 리소스에 직접적으로 연결되는 스트림
filterStream(보조 스트림) - 다른 스트림을 거쳐서 리소스와 연결되는 스트림
<그 외의 바이트 기반 스트림>
ByteArrayInputStream, ByteArrayOutputStream - 메모리(byte 배열)
PipedInputStream, PipedOutputStream - 프로세스(프로세스 간의 통신)
AudioInputStream, AudioOutputStream - 오디오 장치

Buffer 기반 스트림과 보조 스트림

보조 스트림은 직접적으로 리소스와 연결되지는 않지만, 다른 스트림에 연결되어 성능 향상을 돕는다.

BufferedReader br = null;
BufferedWriter bw = null;
// Scanner 클래스가 추가되기 전에는 이렇게 받아야 했음
br = new BufferedReader(new InputStreamReader(System.in));
bw = new BufferedWriter(new FileWriter("output.txt"));

while((str = br.readLine()) != null) {
	str += "\n";
	bw.write(str);
}
// System.in이라는 InputStream이 InputStreamReader에 
// 연결되고 이것이 마지막으로 BufferedReader와 연결

// BufferedReader(or InputStream_을 사용하면 read() 메소드를 호출했을 때 입력 소스로부터
// 데이터를 읽어서 버퍼에 저장
// 버퍼로부터 읽으면 외부의 입력소스를 바로 읽는 것보다 작업이 훨씬 빨라짐
// BufferedWriter도 유사하게 write() 메소드를 호출했을 때 출력이 버퍼에 저장된 후, 버퍼가 가득 차면
// 모든 내용을 출력 소스에 출력
// 버퍼에 남은 데이터가 있을 수 있으므로 flush()나 close()를 통해 남은 데이터를 출력 후 종료

Channel

blocking I/O와 달리 중간에 Thread와 data가 들어간 channel이 존재

채널의 특징

  • Socket과 연결 되어, 입출력 역할을 수행한다.
  • 입력과 출력을 동시에 수행한다.
  • Selector와 연결되어 있고, 하나에 Selector에는 다수의 채널이 존재할 수 있다.
  • Blocking된 스레드를 깨우거나, 다시 Blocking할 수 있다.

Selector

JAVA NIO는 하나의 스레드에 여러개의 연결이 있기 때문에 Selector를 이용해 어느 연결과 I/O를 실시할지 정한다.

public static Selector open() throws IOException
// 새로운 Selector 생성
public final SelectionKey register(Selector sel, int ops) throws ClosedChannelException
// Selector에는 서로 다른 채널들이 등록되어야 하며 채널에 할당하기 위해 SelectionKey를 사용
// 그 다음 프로그램에서 Selector 객체에 작업을 수행할 준비가 된 채널 키의 세트를요청
// SelectionKey는 채널에서 포인터로 제공, Selector에 채널을 등록하게 되면 (register) SelectionKey를 반환
// Selector에 채널을 할당하기 위해서는 Selector가 아닌 채널에서 register() 메소드 호출

// int ops values
SelectionKey.OP_ACCEPT -> public fianl boolean isAcceptable()
SelectionKey.OP_CONNECT -> public fianl boolean isConnectable()
SelectionKey.OP_READ -> public fianl boolean isReadable()
SelectionKey.OP_WRITE -> public fianl boolean isWritable()

SocketChannel 클래스

Socket의 수정이 필요할 경우 해당 클래스를 수정

public static SocketChannel open(SocketAddress remote) throws IOException
// 만약 파라미터 없이 open() 메소드 사용 시, open으로 channel의 실행만 실시하고 connect() 메소드를 통해 연결

public static SocketChannel connect(SocketAddress remote) throws IOException
public static SocketChannel read(SocketAddress remote) throws IOException
// ByteBuffer를 파라미터로 사용해 읽기

public abstract write(SocketAddress remote) throws IOException
// ByteBuffer를 파라미터로 사용해 읽기

public void close() throws IOException
// 포트와 리소스 해제를 위해 채널을 닫음

ServerSocketChannel

들어오는 연결을 수용하기 위해 만들어짐. Selector에서 채널이 선택되면 연결의 알림을 받는 목적으로 사용되는 accept() 메소드만 사용

 public static ServerSocketChannel open() throws IOException
 // open() 메소드를 통해 서버소켓으 만들 수 있다.
 // SocketChannel의 open()과 달리 객체만 만들고 실제로 연결을 제공해주지는 않는다.
 
 public abstract SocketChannel accept() throws IOException
 // accept() 메소드를 통해 들어오는연결을 대기할 수 있다.

InputStream과 OutputStream

InputStream

바이트 기반 입력 스트림의 최상위 클래스로 추상 클래스

모든 바이트 기반 입력 스트림은 이 클래스를 상속받아서 만들어짐

InputStream 클래스에는 바이트 기반 입력 스트림이 기본적으로 가져야 할 메소드들이 정의 되어 있음

메소드 설명
int available() 현재 읽을 수 있는 바이트 수를 반환한다
void close() 현재 열려있는 InputStream을 닫는다
void mark(int readlimit) InputStream에서 현재의 위치를 표시해준다
boolean markSupported() 해당 InputStream에서 mark()로 지정된 지점이 있는 지에 대한 여부를 확인한다
abstarct int read() InputStream에서 한 바이트를 읽어서 int값으로 반환한다
int ready(byte[] b) byte[] b 만큼의 데이터를 읽어서 b에 저장하고 읽은 바이트 수를 반환한다
int read(byte[] b, int off, int len) len만큼 읽어서 byte[] b의 off위치에 저장하고 읽은 바이트 수를 반환한다
void reset() mark()를 마지막으로 호출한 위치로 이동
long skip(long n) InputStream에서 n바이트만큼 데이터를 스킵하고 바이트 수를 반환한다

OutputStream

바이트 기반 출력 스틀미의 최상위 클래스로 추상 클래스

모든 바이트 기반 출력 스트림 클래스는 이 클래스를 상속받아서 만들어짐

OutputStream 클래스에는 모든 바이트 기반 출력 스트림이 기본적으로 가져야할 메소드가 정의되어 있음

메소드 설명
void close() OutputStream을 닫는다
void flush() 버퍼에 남아있는 출력 스트림을 출력한다
void write(byte[] b) 버퍼의 내용을 출력한다
void write(byte[] b, int off, int len) b 배열 안에 있는 시작 off부터 len만큼 출력한다
abstarct void write(int b) 정수 b의 하위 1바이트를 출력한다

Byte와 Character 스트림

Byte Stream

Byte Stream은 1 byte를 Input/Output 할 수 있는 스트림이다.

동영상 이미지 음악 파일을 처리하기에 적합하다.

Byte Input Stream

자바는 객체를 생성하고 생성된 객체와 Byte Stream과 연결함으로서 파일을 연다

Byte Output Stream

장치와 연결딘 두 개의 Output Stream은 System.out, System.err를 생성한다.

Character Stream

자바 스트림 클래스 중에서 처리할 데이터가 문자인 경우에 사용한다

문자 스트림은 16bit 유니코드 문자를 주고 받는다

public class CharacterStreamStudy {
    public static void main(String[] args) {
        try{
            FileReader input = new FileReader("a.txt");
            FileWriter output = new FileWriter("b.txt");
            int a;

            while((a=input.read()) != -1){
                output.write(a);
            }

            input.close();
            output.close();

        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

표준 스트림 (System.in, System.out, System.err)

표준 입출력(Standard I/O)

콘솔을 통한 데이터의 입력과 콘솔로의 출력을 의미

System.out : 표준 출력

System.in : 표준 입력

System.err : System.out과같은 역할 + 입출력을 콘솔 이외 다른 대상으로 변경하는 것이 가능(표준 에러)

Scanner

메소드 설명
next() 문자열 입력(공백, 엔터 전까지 입력)
nextLine() 문자열 입력(엔터 전까지 입력)
next.charAt(0) 문자 입력
nextInt() 정수 입력
nextDouble() 실수 입력

Scanner와 BufferedReader 차이

  BufferedReader Scanner
BufferSize 8192 1024
Synchronized O X
문자열 파싱 단순히 읽어 들임 문자열 파싱 가능
Exception IOException 던짐 IOException 숨김

파일 읽고 쓰기

파일 쓰기(File Write)

import java.io.*;

//파일 쓰고 읽기 테스트
public class FileMake {

    public static void main(String[] args) {

        /***********************FILE WRITE***********************/
        try( //요기서 객체를 생성하면 try종료 후 자동으로 close처리됨
                //true : 기존 파일에 이어서 작성 (default는 false임)
                FileWriter fw = new FileWriter( "coding532.txt" ,true);
                BufferedWriter bw = new BufferedWriter( fw );
                )
        {
            bw.write("손흥민"); //버퍼에 데이터 입력
            bw.newLine(); //버퍼에 개행 삽입
            bw.write("이강인");
            bw.newLine();
            bw.flush(); //버퍼의 내용을 파일에 쓰기
        }catch ( IOException e ) {
            System.out.println(e);
        }

        File f = new File("coding532.txt");
        // 파일 존재 여부 판단
        if (f.isFile()) {
            System.out.println("coding532.txt 파일이 있습니다.");
        }
    }

}

파일 읽기(File Read)

import java.io.*;

//파일 쓰고 읽기 테스트
public class FileMake {

    public static void main(String[] args) {

        /***********************FILE WRITE***********************/
        try( //요기서 객체를 생성하면 try종료 후 자동으로 close처리됨
                //true : 기존 파일에 이어서 작성 (default는 false임)
                FileWriter fw = new FileWriter( "coding532.txt" ,true);
                BufferedWriter bw = new BufferedWriter( fw );
                )
        {
            bw.write("손흥민"); //버퍼에 데이터 입력
            bw.newLine(); //버퍼에 개행 삽입
            bw.write("이강인");
            bw.newLine();
            bw.flush(); //버퍼의 내용을 파일에 쓰기
        }catch ( IOException e ) {
            System.out.println(e);
        }

        File f = new File("coding532.txt");
        // 파일 존재 여부 판단
        if (f.isFile()) {
            System.out.println("coding532.txt 파일이 있습니다.");
        }

        /***********************FILE READ***********************/
        try(
                FileReader rw = new FileReader("coding532.txt");
                BufferedReader br = new BufferedReader( rw );
                ){
            
            //읽을 라인이 없을 경우 br은 null을 리턴한다.
            String readLine = null ;
            while( ( readLine =  br.readLine()) != null ){
                System.out.println(readLine);
            }
        }catch ( IOException e ) {
            System.out.println(e);
        }

    }

}

ref {

  https://velog.io/@bahar-j/자바의-입출력IO와-스트림

  https://adrian0220.tistory.com/150

  https://develop-im.tistory.com/54

  https://velog.io/@rabbit/Byte-Character-스트림

 

}

'Programming > Java' 카테고리의 다른 글

[JAVA] 람다식  (0) 2022.04.18
[JAVA] 제네릭  (0) 2022.04.11
[JAVA] Annotation  (0) 2022.03.28
[JAVA] ENUM  (0) 2022.03.21
[JAVA]멀티쓰레드 프로그래밍  (0) 2022.03.14

댓글