[Java] 46. 자바 IO 기본(1)

2025. 7. 1. 16:50·Java/IO, Network
IO 기본 (1)

IO 기본 (1)

#Java/adv2



/스트림 시작1: 자바 프로세스의 데이터를 외부로 입출력 입력/출력 스트림(단방향)을 사용. byte 단위 입출력

  • /스트림 시작 - 예제1
    • new FileOutputStream(파일경로): 파일에 데이터를 출력하는 스트림
      • 파일 없으면 자동 생성. 폴더는 자동 생성X
      • fos.write(int): byte 단위로 값 출력
      • new FileOutputStream(파일경로, appned 유무):
        • append 옵션이 true이면 기존 파일의 끝에 이어서, false(기본값)이면 지우고 처음부터 다시 작성
    • new FileInputStream(파일경로): 파일에서 데이터 읽어오는 스트림
      • fis.read(): byte 단위로 읽어온다.
        • 파일의 끝(EOF)에 도달해서 읽을 내용 없으면 -1 반환
        • byte가 아니라 int를 반환한다.
          • byte는 (-128 ~ 127)
            • 256개에 추가적으로 EOF를 위한 특별한 값 할당이 어려움. (8bit 한계)
          • int를 사용하면 256 종류의 값 + EOF를 나타낼 수 있다.
    • fis.close(), fos.close()
      • 외부 자원을 사용하는 것이므로 GC 대상이 아님. 반드시 직접 닫아주자.
    • 텍스트 편집기의 인코딩 방식에 따라 byte 값이 디코딩되어 보인다.
  • /스트림 시작 - 예제2: 파일 읽을 때 while문을 통해 EOF 도달시점까지 읽을 수 있다.

/스트림 시작2: byte 하나씩이 아니라, byte 배열로 데이터를 다뤄보자.

  • /스트림 시작 - 예제3
    • 출력 스트림
      • fos.write(byte[]): byte 배열의 데이터를 한 번에 출력
    • 입력 스트림
      • read(byte[], offset, lentgh) : byte[]을 미리 만들어두고, 만들어둔 byte[]에 한 번에 데이터를 읽어올 수 있다.
        • 여기서 byte[]는 버퍼가 된다.
        • offset: 데이터가 기록되는 byte[] 오프셋(시작 위치). 디폴트는 0
        • length: 읽어올 byte 최대 길이. 디폴트는 byte[].length
        • 반환 값: 버퍼에 읽은 총 바이트 수. 끝에 도달하면 -1
  • /스트림 시작 - 예제4
    • 입력 스트림
      • byte[] readBytes = fis.readAllBytes();
        • 스트림이 끝날 때 까지 모든 데이터를 한 번에 읽어온다.
  • /부분으로 나누어 읽기 vs 전체 읽기
    • read(byte[], offset, lentgh)
      • 스트림 내용을 부분적으로 읽거나, 읽으면서 같이 무언가 처리해야 하는 경우 적합.
        • ex. 메모리 사용량 제어. 100MB 1MB씩 100번
    • readAllBytes()
      • 작은 파일이나 메모리에 모든 내용을 올려서 처리해야 하는 경우
      • 편리하나, 메모리 사용량 제어가 불가능. OutOfMemoryError 발생 가능

/InputStream, OutputStream

  • 자바는 파일, 네트워크, 콘솔 각각 데이터를 주고 받는 방식을 InputStream, OutputStream에 추상화해둠(추상 클래스)
    • 일관된 방식으로 데이터를 주고받을 수 있다.
    • 유연하고, 확장가능하고, 재사용가능하고, 예외 처리도 표준화된다.
  • InputStream
    • FileInputStream, ByteArrayInputStream, SocketInputStream
    • read(), read(byte[]), readAllBytes()
  • OutputStream
    • FileOutputStream, ByteArrayOutputStream, SocketOutputStream
    • write(int), write(byte[])
  • /메모리 스트림
    • new ByteArrayOutputStream()
      • write() 제공
    • new ByteArrayInputStream(baos.toByteArray());
      • readAllBytes() 제공
  • /콘솔 스트림
    • PrintStream printStream = System.out;
      • write() 제공
      • println(String), print(String)등 제공
        • Sout이 사실은 printStream의 메서드
        • println 내부에서 문자열을 byte로 바꿔서 처리해준다.
      • 이 스트림은 자바가 시작될 때 자동으로 만들어져서, 직접 생성하지 않는다.

/파일 입출력과 성능 최적화1 - 하나씩 쓰기

  • /예제1 - 쓰기: 1바이트씩 fos.write()로 쓰기
  • /예제1 - 읽기: 1바이트씩 fis.read()로 읽기
  • write()나 read()를 사용하면 시스템 콜을 명령이 전달되어 무거운 작업이 수행되는데, 이걸 수없이 반복하니 오래 걸린다.
    • OS와 HW 수준에서 어느정도 최적화가 되긴 하지만, read(), write() 호출 횟수부터 줄여야 시스템 콜 횟수도 줄어든다.

/파일 입출력과 성능 최적화2 - 버퍼 활용: 시스템 콜 한 번에 많은 데이터를 버퍼에 실어서 보내자.

  • byte[]를 통해 전달
  • /예제2 - 쓰기
    • fos.write(buffer);
    • 버퍼가 가득차면 write()로 작성한다. (예제는 버퍼 크기: 8KB)
    • 끝 부분에 오면 버퍼가 가득차지 않고 남아있을 수 있으므로, 남은부분을 write()한다.
    • 1바이트씩 write()하는 것 보다 훠~얼씬 빠르다.
  • /버퍼의 크기에 따른 쓰기 성능
    • 버퍼의 크기를 늘리면, 시스템 콜도 줄어들어 실행 시간이 줄어든다.
    • 버퍼의 크기가 8KB를 넘으면 크게 빨라지지 않는다.
      • 디스트에서 데이터를 읽고 쓰는 단위가 보통 4KB 또는 8KB이기 때문이다.
      • 버퍼 크기는 4KB나 8KB로 잡자
  • /예제2 - 읽기
    • while ((size = fis.read(buffer)) != -1)
    • fis.read(): 읽은 사이즈를 반환해줌, buffer.legnth가 8192면, 8192씩 읽어온다.
  • byte[] 버퍼 방식의 단점: 직접 버퍼를 만들고 관리해야 함.

/파일 입출력과 성능 최적화3 - Buffered 스트림 쓰기

  • BufferedOutputStream를 통해 버퍼 기능을 내부에서 처리해준다.
  • new BufferedOutputStream(대상 OutputStream, BUFFER_SIZE);
    • 단순히 버퍼 기능만 제공한다. 따라서 반드시 대상 OutputStream이 있어야 한다.
      • ex) fos
    • 생성자에 사용할 버퍼의 크기도 함께 전달할 수 있다.
    • bos.write()를 하면 시스템 콜이 나가는게 아니라, 먼저 버퍼에 쌓이도록 구현되어 있다.
    • byte[]을 직접 다루지 않아도 된다. for문에 1바이트씩 써도, 내부적으로 버퍼가 가득차야 대상 OutputStream에 write() 시스템 콜이 나간다.
    • OutputStream을 상속받기 때문에 같은 기능을 사용할 수 있다.
    • flush(): 버퍼가 다 차지 않아도 버퍼에 남아있는 데이터를 전달해준다.
    • close(): 내부에서 먼저 flush()를 호출하여 내부에 남아있는 데이터를 비우고 대상 OutptStream의 자원을 정리하고, BufferedOutputStream도 닫힌다.
      • 대상 OutputStream을 직접 닫으면 안 된다. flush()가 호출되지 않고, 자원도 정리되지 않는다.
    • 버퍼의 크기만큼 데이터를 모아서 전달하기 때문에 빠르다.
  • /기본 스트림, 보조 스트림
    • 기본 스트림: FileOutputStream과 같이 단독으로 사용할 수 있는 스트림
    • 보조 스트림: BufferedOutputStream과 같이 단독으로 사용할 수 없고, 보조 기능을 제공하는 스트림

/파일 입출력과 성능 최적화4 - Buffered 스트림 읽기

  • BufferedInputStream를 통해 버퍼 기능을 내부에서 처리해준다.
  • new BufferedInputStream(대상 InputStream, BUFFER_SIZE)
  • InputStream 을 상속받기 때문에 같은 기능을 사용할 수 있다.
  • bis.read()
    • 조회하면 버퍼에서 값을 읽어온다.
    • 버퍼에 읽을 데이터가 부족하면 버퍼 크기만큼 대상 InputStream에서 값을 읽어온다.
    • 1바이트씩 데이터를 조회해도 실제로는 버퍼 크기만큼 퍼오기 때문에, 성능이 최적화 된다.

/버퍼를 직접 다루는 것 보다 BufferedXxx의 성능이 떨어지는 이유

  • BufferedXxx 클래스는 모두 동기화 처리가 되어 있기 때문이다.
  • BufferedXxx의 read(), write()를 n번 호출하면 락을 걸고 푸는 것도 n번 호출된다.
  • 자바 초창기에 만들이진 클래스라, 멀티 스레드를 고려해서 만들어졌다.
    • 스레드 safe 하지만, 성능이 약간 저하된다.
    • 일반적인 상황이라면 이 정도 성능은 크게 문제가 되지는 않는다.
  • 매우 큰 데이터를 다루고 성능 최적화가 중요하면 버퍼를 직접 다루는 방법을 고려해야 한다.
  • 동기화 락이 없는 BufferedXxx 클래스는 없다.

/파일 입출력과 성능 최적화5 - 한 번에 쓰기

  • 파일의 크기가 크지 않다면 간단하게 한 번에 쓰고 읽는 방법도 좋은 방법이다.
    • ex) fos.write(buffer);
    • ex) byte[] bytes = fis.readAllBytes();
    • 예제에서는 10MB로 지정했지만, 8KB랑 성능 차이가 거의 나지 않는다.

Ref) 김영한의 실전 자바 - 고급 2편, I/O, 네트워크, 리플렉션 강의 | 김영한 - 인프런

'Java > IO, Network' 카테고리의 다른 글

[Java] 51. 네트워크 - 프로그램(2)  (0) 2025.07.01
[Java] 50. 네트워크 - 프로그램(1)  (0) 2025.07.01
[Java] 49. File, Files  (0) 2025.07.01
[Java] 48. 자바 I/O 활용  (0) 2025.07.01
[Java] 47. 자바 IO 기본(2)  (0) 2025.07.01
'Java/IO, Network' 카테고리의 다른 글
  • [Java] 50. 네트워크 - 프로그램(1)
  • [Java] 49. File, Files
  • [Java] 48. 자바 I/O 활용
  • [Java] 47. 자바 IO 기본(2)
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (456)
      • Software Development (27)
        • Performance (0)
        • TroubleShooting (1)
        • Refactoring (0)
        • Test (8)
        • Code Style, Convetion (0)
        • DDD (0)
        • Software Engineering (18)
      • Java (71)
        • Basic (5)
        • Core (21)
        • Collection (7)
        • 멀티스레드&동시성 (13)
        • IO, Network (8)
        • Reflection, Annotation (3)
        • Modern Java(8~) (12)
        • JVM (2)
      • Spring (53)
        • Framework (12)
        • MVC (23)
        • Transaction (3)
        • AOP (11)
        • Boot (0)
        • AI (0)
      • DB Access (1)
        • Jdbc (1)
        • JdbcTemplate (0)
        • JPA (14)
        • Spring Data JPA (0)
        • QueryDSL (0)
      • Computer Science (129)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (5)
        • 시스템 프로그래밍 (23)
        • Algorithm (29)
      • HTTP (8)
      • Infra (1)
        • Docker (1)
      • 프로그래밍언어론 (15)
      • Programming Language(Sub) (77)
        • Kotlin (1)
        • Python (25)
        • C++ (51)
        • JavaScript (0)
      • FE (11)
        • HTML (1)
        • CSS (9)
        • React (0)
        • Application (1)
      • Unix_Linux (0)
        • Common (0)
      • PS (13)
        • BOJ (7)
        • Tip (3)
        • 프로그래머스 (0)
        • CodeForce (0)
      • Book Review (4)
        • Clean Code (4)
      • Math (3)
        • Linear Algebra (3)
      • AI (7)
        • DL (0)
        • ML (0)
        • DA (0)
        • Concepts (7)
      • 프리코스 (4)
      • Project Review (6)
      • LegacyPosts (11)
      • 모니터 (0)
      • Diary (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
lumana
[Java] 46. 자바 IO 기본(1)
상단으로

티스토리툴바