BE전문가 프로젝트

18. 보조 스트림 본문

JAVA

18. 보조 스트림

원호보고서 2023. 11. 23. 12:49

이전 포스팅에서 바이트 기반 스트림과 문자 기반 스트림에 대해서 알아봤다. 직접 사용할 수도 있지만 입출력의 성능을 향상 시키거나 데이터 출력의 형식을 지정하고 싶을 때 보조 스트림을 연결하여 사용할 수 있다.

 

보조 스트림은 문자 변환, 입출력 성능 향상, 기본 타입 입출력 등 여러 가지 편리한 기능을 제공해주는 스트림이다. 말 그대로 보조이기 때문에 자체적으로 입출력을 수행할 수 없으며 바이트 기반 입출력 스트림의 최상위 클래스인 InputStream, OutputSteam과 문자 기반 최상위 클래스인 Writer, Reader 등에 연결하여 입출력한다.

보조 스트림 연결

보조 스트림 연결은 보조스트림 생성할 때 자신이 연결될 스트림을 생성자의 매개값으로 제공하면 된다.

InputStream is = System.in;
InputStreamReader reader = new InputStreamReader(is);

 

보조 스트림은 하나만 연결되는 것이 아니라 연속적으로 연결할 수 있다.

InputStream is = System.in;
InputStreamReader reader = new InputStreamReader(is);
BufferedReader br = new BufferdReader(reader);

 

문자 변환 보조 스트림

바이트 기반 스트림이면서 입출력 데이터가 문자라면 문자 출력에 최적화된 Reader와 Writer로 변환해서 사용이 가능하다.

 

OutputStreamWriter

바이트 기반 스트림 출력 스트림에 연결되어 문자 출력 스트림(Writer)로 변환하는 보조 스트림

public class WriteTest {

    public void write(String str) throws Exception {
        FileOutputStream fos = new FileOutputStream("파일 위치");
        Writer writer = new OutputStreamWriter(fos);
        
        writer.write(str);
        writer.flush();
        writer.close();
    }
}

 

InputStreamReader

바이트 기반 스트림 입력 스트림에 연결되어 문자 입력 스트림(Reader)로 변환하는 보조 스트림

public class ReadTest {

    public void write(String str) throws Exception {
        FileInputStream fis = new FileInputStream("파일 위치");
        Reader reader = new InputStreamReader(fis);

        char[] buffer = new char[100];
        int readCharNum = reader.read(buffer);
        
        reader.close();
        
        System.out.println(new String(buffer, 0, readCharNum));
    }
}

 

성능 향성 보조 스트림

컴퓨터 성능이 좋아도 네트워크가 느리면 인터넷이 느리듯 프로그램 역시 입출력이 가장 느린 장치를 따라간다.

랜선을 바꾸어서 성능을 조금이나마 업그레이드 하듯 프로그램에서도 완전한 해결책은 아니더라도 중간에 메모리 버퍼와 작업함으로써 성능을 향상시킬 수 있다.

 

메모리 버퍼에 쌓아놨다가 꽉 차게되면 한번에 전송하여 출력 횟수를 줄여 성능을 향상시킬 수 있다. 바이트 기반 스트림에서는 BufferedInputStream, BufferedOutputStream이 있고 문자 기반 스트림에는 BufferdReader, BufferdWriter가 있다.

출력 프로그램에서 전송한 데이터가 내부 버퍼에 전부 쌓이면 모든 데이터를 한번에 보낸다. BufferedOutputStream
BufferdWriter
입력 입력 소스로부터 버퍼 크기만큼 데이터를 미리 읽고 버퍼에 저장한다. BufferedInputStream
BufferdReader

 

public class HelloWorld {

    public static void main(String[] args) throws Exception {

        HelloWorld helloWorld = new HelloWorld();
        
        //1. 버퍼를 사용하지 않은 스트림
        String originalFilePath1 = HelloWorld.class.getResource("originalFile1.jpg").getPath();
        String targetFilePath1 = "복사할 주소";

        FileInputStream fis1 = new FileInputStream(originalFilePath1);
        FileOutputStream fos1 = new FileOutputStream(targetFilePath1);


        //2. 버퍼를 사용한 스트림
        String originalFilePath2 = HelloWorld.class.getResource("originalFile2.jpg").getPath();
        String targetFilePath2 = "복사할 주소";

        FileInputStream fis2 = new FileInputStream(originalFilePath2);
        FileOutputStream fos2 = new FileOutputStream(targetFilePath2);
        BufferedInputStream bis = new BufferedInputStream(fis2);
        BufferedOutputStream bos = new BufferedOutputStream(fos2);
        
        
        long nonBufferTime = helloWorld.copy(fis1, fos1);
        System.out.println("버퍼 사용하지 않은 시간 : " + nonBufferTime);
        
        long bufferTime = helloWorld.copy(bis, bos);
        System.out.println("버퍼 사용한 시간 : " + bufferTime);
    }
    
    public long copy(InputStream is, OutputStream os) throws Exception {
        
        int data = -1;
        
        long startTime = System.nanoTime();
        
        while (true) {
            data = is.read();
            
            if (data == -1) break;
            
            os.write(data);
        }
        
        os.flush();
        
        long endTime = System.nanoTime();
        
        return (endTime - startTime);
    }
}

 

위에 코드를 실행해보면 버퍼를 사용한 입출력 스트림이 속도가 더 빠른 것을 확인할 수 있다.

 

기본타입 보조 스트림

int, char, long과 같이 기본 타입을 DataInputStream과 DataoutputStream 보조 스트림에 연결하여 입출력할 수 있다.

DataInputStream DataOutputStream
boolean readBoolean() void writeBoolean(boolean v)
byte readByte() void wirteByte(int v)
char readChar() void wirteChar(int v)
double readDouble() void wirteDouble(int v)
float readFloat() void wirteFloat(int v)
int readInt() void wirteInt(int v)
long readLong() void wirteLong(int v)
short readShort void wirteShort(int v)
String readUTF() void wirteUTF(int v)
public class HelloWorld {

    public static void main(String[] args) throws Exception {

        FileOutputStream fos = new FileOutputStream("D:/workspace/Baekjoon/src/test1.db");
        DataOutputStream dos = new DataOutputStream(fos);

        dos.writeUTF("김깐따");
        dos.writeDouble(180.6);
        dos.writeInt(28);

        dos.flush();
        dos.close();

        FileInputStream fis = new FileInputStream("D:/workspace/Baekjoon/src/test1.db");
        DataInputStream dis = new DataInputStream(fis);

        System.out.printf("이름 %s 키 : %.1f 나이 : %d", dis.readUTF(), dis.readDouble(), dis.readInt());
    }
}

 

객체 입출력 보조 스트림

ObjectOutputStream과 ObjectInputStream 보조 스트림을 연결하여 메모리에 생성된 객체를 파일 및 네트워크로 출력할 수 있다.

 

ObjectOutputStream

  • 객체를 직렬화(객체를 바이트 배열로 만드는 것)

ObjectIntputStream

  • 객체를 역직렬화(바이트 배열을 다시 객체로 복원하는 것)

Serializable 인터페이스를 구현한 객체만 직렬화 및 역직렬화가 가능하다. JVM에게 직렬화하는 객체라고 알리는 역할을 한다.

public class Board implements Serializable {

    private int no;
    private String title;
    private String content;
    private String writer;
    private Date date;

    public Board(int no, String title, String content, String writer, Date date) {
        this.no = no;
        this.title = title;
        this.content = content;
        this.writer = writer;
        this.date = date;
    }

    public int getNo() {return no;}
    public String getTitle() {return title;}
    public String getContent() {return content;}
    public String getWriter() {return writer;}
    public Date getDate() {return date;}
}
public class HelloWorld {

    public static void main(String[] args) throws Exception {

        writeList();
        List<Board> list = readList();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.mm.dd");

        for (Board board: list) {
            System.out.printf("%d\t%s\t%s\t%s\t%s", board.getNo(), board.getTitle(), board.getContent(), board.getWriter(), sdf.format(board.getDate()));

        }

    }

    public static void writeList() throws Exception {
        List<Board> list = new ArrayList<Board>();

        list.add(new Board(1, "title1", "content1", "writer1", new Date()));
        list.add(new Board(2, "title2", "content2", "writer2", new Date()));
        list.add(new Board(3, "title3", "content3", "writer3", new Date()));

        FileOutputStream fos = new FileOutputStream("D:/workspace/Baekjoon/src/test1.db");
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        oos.writeObject(oos);
        oos.flush();
        oos.close();
    }

    public static List<Board> readList() throws Exception {

        FileInputStream fis = new FileInputStream("D:/workspace/Baekjoon/src/test1.db");
        ObjectInputStream ois = new ObjectInputStream(fis);

        List<Board> list = (List<Board>) ois.readObject();
        return list;
    }
}

'JAVA' 카테고리의 다른 글

17. 입출력 스트림  (1) 2023.11.23
16-2 스레드 - 제어  (0) 2023.11.21
16-1. 스레드 - 멀티스레드  (2) 2023.11.20
15. java.lang에 대하여  (0) 2023.11.15
14. Object 클래스(hashcode() 및 equals())  (0) 2023.11.15
Comments