[Day 8 | Java] IO Stream

y♡ding·2024년 10월 23일
0

데브코스 TIL

목록 보기
46/163

1. 스트림(Stream) 개념

스트림데이터의 흐름을 의미하며, 데이터를 읽고 쓰는 과정을 추상화한 개념입니다. 자바의 입출력 시스템은 스트림을 통해 데이터를 주고받습니다. 자바에서는 크게 두 가지 스트림을 사용합니다:

  • 입력 스트림 (Input Stream): 외부로부터 데이터를 읽어오는 스트림입니다. 예를 들어, 파일이나 키보드 입력으로부터 데이터를 읽을 때 사용됩니다.
  • 출력 스트림 (Output Stream): 데이터를 외부로 출력하는 스트림입니다. 예를 들어, 파일에 데이터를 기록하거나 콘솔에 출력을 할 때 사용됩니다.

2. 스트림의 종류

자바의 입출력 스트림은 데이터의 형태에 따라 바이트 스트림문자 스트림으로 나뉩니다.

(1) 바이트 스트림 (Byte Stream)

  • 이트 단위(8비트)로 데이터를 처리하는 스트림입니다.
  • 모든 유형의 데이터를 처리할 수 있으며, 파일, 이미지, 오디오 등의 바이너리 데이터에 적합합니다.
  • 바이트 스트림 클래스:
    • 입력: InputStream
    • 출력: OutputStream

(2) 문자 스트림 (Character Stream)

* 문자 단위(16비트)로 데이터를 처리하는 스트림입니다.

  • 텍스트 데이터를 읽거나 쓸 때 사용되며, 유니코드 문자를 처리하기 위해 설계되었습니다.
  • 문자 스트림 클래스:
    • 입력: Reader
    • 출력: Writer

3. 바이트 스트림의 주요 클래스

  • 입력 스트림: InputStream을 상속하는 클래스들이 있으며, 파일로부터 데이터를 읽어오는 역할을 합니다.
    • FileInputStream: 파일에서 바이트 데이터를 읽어옵니다.
  • 출력 스트림: OutputStream을 상속하는 클래스들이 있으며, 데이터를 파일로 출력하는 역할을 합니다.
    • FileOutputStream: 파일에 바이트 데이터를 씁니다.

스트림 종류입력 클래스출력 클래스데이터 유형
바이트 스트림FileInputStreamFileOutputStream바이트 데이터 (텍스트, 이미지, 비디오 등)
문자 스트림FileReaderFileWriter문자 데이터 (텍스트 파일)

줄바꿈 방식의 차이

  • Windows는 \r\n (캐리지 리턴 + 줄바꿈)으로 줄을 나눕니다.
  • macOS (및 대부분의 유닉스 계열 시스템)에서는 \n (줄바꿈)만 사용합니다.

주 스트림과 보조 스트림

1. 주 스트림 (Primary Stream)

주 스트림데이터 입출력 작업을 직접 처리하는 스트림입니다. 파일, 네트워크, 메모리 등에서 직접 데이터를 읽고 쓰는 스트림으로, 바이트 스트림문자 스트림을 포함합니다. 주 스트림은 입출력의 기본 역할을 하며, 데이터를 읽거나 쓰는 핵심 작업을 수행합니다.

바이트 스트림

  • InputStreamOutputStream을 상속하는 클래스들이 바이트 단위의 데이터를 처리합니다.
    • FileInputStream: 파일로부터 바이트 데이터를 읽음.
    • FileOutputStream: 파일로 바이트 데이터를 씀.

문자 스트림

  • ReaderWriter를 상속하는 클래스들이 문자 단위의 데이터를 처리합니다.

    • FileReader: 파일로부터 문자 데이터를 읽음.
    • FileWriter: 파일로 문자 데이터를 씀.

    이 두 클래스는 바이트 스트림(InputStream, OutputStream)과 달리 문자 스트림을 다루므로, 유니코드 기반의 다국어 데이터를 처리하는 데 적합합니다.


2. 보조 스트림 (Secondary Stream)

보조 스트림주 스트림을 감싸거나 연결하여 추가 기능을 제공하는 스트림입니다. 보조 스트림 자체는 데이터를 직접 입출력하지 않으며, 주 스트림에 성능 향상이나 데이터 변환 등의 부가적인 기능을 제공합니다. 예를 들어, 버퍼링, 데이터 변환(객체 직렬화), 필터링 등의 기능을 제공합니다.

보조 스트림의 주요 역할

  • 버퍼링: 입출력 성능을 개선하는 역할을 합니다.
    • BufferedInputStream, BufferedReader: 데이터를 버퍼링하여 성능을 향상시킵니다.
  • 데이터 변환: 기본 타입이나 객체를 스트림으로 변환하거나, 반대로 스트림에서 데이터를 변환해 처리합니다.
    • DataInputStream, DataOutputStream: 기본 데이터 타입(int, double 등)을 스트림에 쓰거나 읽을 수 있게 해줍니다.
    • ObjectInputStream, ObjectOutputStream: 객체를 직렬화해서 스트림으로 쓰거나, 역직렬화해서 객체로 복원할 수 있게 해줍니다.

버퍼링을 통한 성능 개선

파일 입출력 작업에서 버퍼링(Buffering)을 사용하면 성능을 크게 향상시킬 수 있습니다. 버퍼를 사용하면 데이터가 일정 크기만큼 모일 때 한 번에 처리되므로, 입출력 속도가 빨라집니다.

* 버퍼링 클래스:

  • BufferedInputStream, BufferedOutputStream: 바이트 스트림에서 사용.
  • BufferedReader, BufferedWriter: 문자 스트림에서 사용.

버퍼를 사용하는 이유

컴퓨터의 입출력 장치(디스크, 네트워크, 키보드 등)와 프로그램 간에는 속도 차이가 큽니다. 프로그램이 처리 속도가 빠른 반면, 입출력 장치의 속도는 상대적으로 느리기 때문에, 작은 데이터를 여러 번 주고받을 경우 성능 저하가 발생할 수 있습니다.

버퍼를 사용하면 데이터를 한 번에 모아서 처리하여 입출력 작업의 빈도를 줄이고, 전체적인 성능을 개선할 수 있습니다. 이는 자바의 파일 IO 작업에서 특히 중요합니다.

  • 버퍼를 사용하지 않는 입출력은 우편 배달부가 편지를 하나씩 배달하는 것과 같습니다. 매번 배달할 때마다 시간이 걸립니다.
  • 버퍼를 사용하는 입출력은 편지를 일정량 모아서 한 번에 배달하는 것과 비슷합니다. 더 적은 배달 횟수로 더 많은 편지를 처리할 수 있습니다.

FileInputStream - 파일 내용 읽어오기

  • 파일이 없으면 NullPointerException 발생
package io1;

import java.io.FileInputStream;
import java.io.IOException;

public class IOEx01 {
    public static void main(String[] args) {
        // FileInputString
		// 파일로부터 데이터를 읽기 위한 FileInputStream 변수 선언
        FileInputStream fls = null;   // (close하기 위해 위헤 따로 선언)
        
        try {
        // FileInputStram을 통해 특정 파일을 연다
            fls = new FileInputStream("/Users/leehayeon/Desktop/java/test.txt"); // 파일 경로 저장
            
            int data = fls.read();
            System.out.println(data);
        } catch (IOException e) {
            System.out.println("[에러] " + e.getMessage());
        } finally {
            **try { fls.close(); } catch (IOException e) {}**  // 주로 한 줄로 처리
        }
    }
}

// 49

int data = fls.read(); 한 자씩 읽음
System.out.println((char)data); (char)로 변형해 출력

  try {
            fls = new FileInputStream("/Users/leehayeon/Desktop/java/test.txt");
            **int data = fls.read();
            System.out.println((char)data);**
            data = fls.read();
            System.out.println((char)data);
            data = fls.read();
            System.out.println((char)data);

        }
// 한 자가 아닌 파일 내용 모두 읽고 싶을 때
 try {

            fls = new FileInputStream("/Users/leehayeon/Desktop/java/test.txt");
			
            
            int data = 0;   // 읽은 데이터를 저장할 수 초기화
            // 파일 끝에 도달할 때까지 내용 읽기. 읽은 데이터를 문자로 변환해 출력한다.
            // 다국어는 읽을 수 없음
            // 엔터키도 포함해서 읽어 들임
            while( (data = fls.read()) != -1 ) {
                System.out.print((char)data);
            }
        }

FileOuptputStream - 파일에 쓰기

  • 파일이 없으면 자동 생성
package io1;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class IOEx02 {
    public static void main(String[] args) {
        FileOutputStream fos = null;

        try {
        	// FileOutputStream을 통해 특정 파일을 생성 또는 열기
            // 파일이 없으면 파일 자동 생성
            fos = new FileOutputStream("/Users/leehayeon/Desktop/java/test2.txt");

            fos.write('a');  // 파일에 'a'문자 쓰기 (아스키 코드 값 97 저장됨)
            fos.write('b');  // 파일에 'b'문자 쓰기 (아스키 코드 값 98 저장됨)
            
            // 문자열을 직접 쓸 수 없음
            //fos.write("b")

            System.out.println("출력 완료");
        } catch (FileNotFoundException e) {
        	// 파일을 찾지 못했을 때 예외 처리
            System.out.println("[에러] " + e.getMessage());
        } catch (IOException e) {
        		// 파일 쓰는 도중 발생하는 입출력 오류 처리
                System.out.println("[에러] " + e.getMessage());
        } finally {
            try { fos.close();} catch (IOException e) { }
        }
    }
}

복사 - 읽는 대로 쓰기

package io1;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class IOEx03 {
    public static void main(String[] args) {
        // 파일 내용을 복사
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            fis = new FileInputStream("/Users/leehayeon/Desktop/java/test.txt");
            fos = new FileOutputStream("/Users/leehayeon/Desktop/java/newtest.txt");

            int data = 0;
            
            // 파일에서 데이터를 읽고, 읽은 값이 -1(파일의 끝)이 될 때까지 반복
            while ((data = fis.read()) != -1) {
                fos.write(data);
            }
        } catch (IOException e) {
            System.out.println("[애러] " + e.getMessage());
        } finally {
        		// 자원 해제: 입력 스트림과 출력 스트림이 null이 아닐 경우 닫기
                if (fis != null) { try { fis.close();} catch (IOException e) {}   // 스트림을 닫는 도중 발생하는 예외 처리
                if (fos != null) { try { fos.close();} catch (IOException e) {}
                }
                System.out.println("복사 완료");
            }
        }
    }
}

2차 스트림 : Buffer - 가속화

package io1;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class IOEx4 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        BufferedInputStream bis = null;

        try {
            fis = new FileInputStream("/Users/leehayeon/Desktop/java/test.txt");
            bis = new BufferedInputStream(fis);

            int data = 0;
            while((data = bis.read()) != -1) {
                System.out.print((char)data);
            }
        } catch (IOException e) {
            System.out.println("[에러] " + e.getMessage());
        } finally {
            if (fis != null) {try { fis.close(); } catch (IOException e) {e.printStackTrace();}}
            if (fis != null) {try { bis.close(); } catch (IOException e) {e.printStackTrace();}}
        }
    }
}
package io1;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class IOEx4 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        BufferedInputStream bis = null;

        try {
            //fis = new FileInputStream("/Users/leehayeon/Desktop/java/test.txt");
            //bis = new BufferedInputStream(fis);
            bis = new BufferedInputStream(new FileInputStream("/Users/leehayeon/Desktop/java/test.txt"));

            int data = 0;
            while((data = bis.read()) != -1) {
                System.out.print((char)data);
            }
        } catch (IOException e) {
            System.out.println("[에러] " + e.getMessage());
        } finally {
            //if (fis != null) {try { fis.close(); } catch (IOException e) {e.printStackTrace();}}
            if (bis != null) {try { bis.close(); } catch (IOException e) {e.printStackTrace();}}
        }
    }
}

buffer를 이용한 복사 - buffered를 이용해 가속화 장치를 만든 것

package io1;

import java.io.*;

public class IOEx05 {
    public static void main(String[] args) {
//        FileInputStream fis = null;
//        FileOutputStream fos = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
//            fis = new FileInputStream("/Users/leehayeon/Desktop/java/test.txt");
//            fos = new FileOutputStream("/Users/leehayeon/Desktop/java/test.txt");
            bis = new BufferedInputStream(new FileInputStream("/Users/leehayeon/Desktop/java/test.txt"));
            bos = new BufferedOutputStream(new FileOutputStream("/Users/leehayeon/Desktop/java/test.txt"));

            int data = 0;
            while ((data = bis.read()) != -1) {
                bos.write(data);
            }

        } catch (IOException e) {
            System.out.println("[애러] " + e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                }
                if (bos != null) {
                    try {
                        bos.close();
                    } catch (IOException e) {
                    }
                }
                System.out.println("복사 완료");
            }
        }
    }
}

파일 보다는 버퍼를 통해 관리하는 것이 훨 나을 것

FileReader - 다국어

package io1;

import java.io.FileReader;
import java.io.IOException;

public class IOEx06 {
    public static void main(String[] args) {
        FileReader fr = null;

        try {

            fr = new FileReader("/Users/leehayeon/Desktop/java/test.txt");

            int data = 0;
            while((data = fr.read()) != -1) {
                System.out.print((char)data);
            }
        } catch (IOException e) {
            System.out.println("[에러]" + e.getMessage());
        } finally {
            if (fr != null) {try {fr.close();} catch (IOException e) {} }
        }
    }
}

/*
1234567890
abcdefghijkl
가나다라마바
*/

FileWriter - 새로 파일 만들고 쓰기(기본 옵션)

package io1;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class IOEx07 {
    public static void main(String[] args) {
        FileWriter fw = null;

        try {
		        **// 새로 파일 만들고 쓰기**
            fw = new FileWriter("/Users/leehayeon/Desktop/java/newtest.txt");

            // 줄바꿈은 직접 추가해야
            fw.write("hello");

            fw.write("\n");
            fw.write(System.lineSeparator());

            fw.write("hello");

            System.out.println("입력 완료");
        } catch (IOException e) {
            System.out.println("[에러] " + e.getMessage());
        } finally {
            if (fw != null) {try {fw.close(); } catch (IOException e) {e.printStackTrace();}}
        }
    }
}

FileWrite도 가속화가 있나용 - BufferedReader ** 한 줄씩 읽을 수 있음 (String)

package io1;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class IOEx08 {
    public static void main(String[] args) {
        BufferedReader br = null;
        //FileReader fr = null;

        try {
//            fr = new FileReader("/Users/leehayeon/Desktop/java/test.txt");
            br = new BufferedReader(new FileReader("/Users/leehayeon/Desktop/java/test.txt"));

            int data = 0;
            while((data = br.read()) != -1) {
                System.out.print((char)data);
            }
            
            **String line = null;
            // 힌 줄씩 파일 끝까지 읽기
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }**
            
        } catch (IOException e) {
            System.out.println("[에러]" + e.getMessage());
        } finally {
            if (br != null) {try {br.close();} catch (IOException e) {} }
        }
    }
}

0개의 댓글

관련 채용 정보