본문 바로가기
JAVA

java.io 패키지

by 융디's 2024. 4. 27.
728x90
java.io 패키지

java.io 패키지

@2024.04.17

InputStream(들어오는 데이터) → 프로그램 → outputStream(나가는 데이터)

모든 데이터는 스트림이라는 형태로 추상화(냇가에 물이 흘러가는 형태) 되어 있다.
따라서 어떤 데이터가 들어오든
사용하는 방법은 똑같다.

들어오는 통로와 나가는 통로가 각각 있다(양방향성이 아닌 단방향)

파일에 무언가를 쓴다! → 자바가 아닌 운영체제가 하는 일이다.

주인공장식이 나뉘더라

주인공근원지와 목적지를 가지고 있는 클래스 → ex) FileInputStream

장식은 어디서 읽겠다는 것은 없고 버퍼를 제공하겠다 → ex) BufferRedaer

  • 해당 생성자를 바라봤을 때 생성자에 또 다른 IO를 받기를 원하는 생성자는 장식
  • 장식은 기능이 중요하다! (클래스를 끼우고 끼우고)

FileInputStream 생성자 (주인공)
BufferRedaer 생성자(장식)

Java IO

💡
프로그램이 데이터를 읽고 쓰는 것을 의미하며, 다양한 소스에서 데이터를 읽고 쓰는 데 사용되는 라이브러리와 API 집합이다.
  • 기능
    • 유연성
      • 자바 IO가 다양한 유형의 데이터 소스와 대상에 지원
      • 파일, 네트워크 연결, 메모리 내 데이터 등에서 데이터를 읽고 쓸 수 있다.
      • 프로그래머가 동일한 인터페이스를 사용하여, 다양한 유형의 데이터 처리가 가능
    • 확장성
      • 새로운 유형의 데이터 소스나 대상을 쉽게 통합할 수 있게 해주며, 사용자 정의 입출력 처리가 가능
    • 재사용 가능성
      • 입력과 출력에 관련된 클래스와 인터페이스들이 일관되게 설계되어 있어, 한번 작성한 코드를 다양한 상황에서 재사용 할 수 있다.
  • 사용 예시
    • 프로그램이 텍스트 문서를 읽기
    • 인터넷에서 데이터를 다운로드
    • 사용자의 키 입력을 받아 처리

Byte 단위 입출력 Stream

💡
데이터를 바이트 단위로 읽고 쓰는 기능 제공한다.
  • 바이트 : 컴퓨터 데이터의 가장 기본적인 단위
    • 모든 종류의 데이터를 바이트 형태로 표현 가능!
  • 주로 이진 데이터를 다룰 때 사용
    • 이진 데이터 : 텍스트가 아닌 파일이나 네트워크 데이터 같은 것
      • ex) 이미지, 오디오 파일, 비디오 파일 등
    • 텍스트 형태로 읽고 쓰는 것이 아닌 바이트 형태로 직접 처리해야 한다.

InputStream/OutputStream(입출력 스트림)

💡
InputStream데이터를 읽는데 사용하며, OutputStream데이터를 쓰는데 사용된다.
  • 이들은 추상 클래스로서, 실제 사용 시에는 이들을 상속받아 구현된 여러 하위 클래스를 사용
  • 특징
    • 데이터를 한 번에 한 바이트씩 처리
    • 대량의 데이터를 처리할 때 매우 유용하나 처리 속도가 느리다.
      • 버퍼링과 같은 기술을 사용하여 단점을 극복
  • 추상 클래스인 InputStream/OutputStream 상속받아 구현된 여러 하위 클래스
    • FileInputStream 클래스 🎇
      • 파일로부터 바이트 단위로 데이터를 읽는데 사용
      • 파일 시스템에 저장된 데이터를 읽을 때 주로 사용되는 클래스
    • FileOutputStream 클래스 🎇
      • 파일을 바이트 단위로 데이터를 쓰는데 사용
      • 파일 시스템에 데이터를 저장할 때 주로 사용되는 클래스
      // 파일 불러오기(읽기) => 입력 스트림
      FileInputStream in = new FileInputStream("a.txt");
      
      // b.txt 파일에 쓰기 ( 해당 파일이 없으면 자동 생성) => 출력 스트림
      FileOutputStream out = new FileOutputStream("b.txt");
      
      int n;
      byte[] bytes = new byte[1024];
      
      // 1024 바이트 만큼 읽어오기 
      // in.read(): 파일로부터 한 바이트씩 읽어오며, 끝에 도달하면 -1 반환
      // out.write(c) : 읽어온 바이트를 다른 파일에 쓴다.  
      while ((n = in.read(bytes)) != -1) {
      	String str = new String(bytes);
      	System.out.println(str);
      	out.write(bytes);
      }
      
      // 1바이트씩 읽어오기 
      while ((n = in.read()) != -1) {
          System.out.println((char) n);
          out.write(n); // 1바이트씩  b.txt 파일에 쓰기 
      }
      out.close();
      in.close();
    • ByteArrayInputStream 클래스 🎇
      • 바이트 배열로부터 데이터를 읽는다.
      • 메모리에 저장된 바이트 배열로부터 데이터를 읽을 때 사용된다.
    • ByteArrayOutputStream 클래스 🎇
      • 바이트 배열에 데이터를 쓴다.
      • 메모리 내에서 데이터를 바이트 배열로 만들어 내는데 사용된다.
      // 출력할 문자열
      String data = "Hello, ByteArray Streams!";
      
      // 문자열을 바이트 배열로 변환하여 ByteArrayOutputStream에 쓰기
      ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
      try {
          byteArrayOutputStream.write(data.getBytes());
      } catch (IOException e) {
          e.printStackTrace();
      }
      
      // ByteArrayOutputStream에 쓰인 데이터를 바이트 배열로 가져오기
      byte[] byteArray = byteArrayOutputStream.toByteArray();
      
      // ByteArrayInputStream으로부터 데이터 읽기
      ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
      
      // 바이트 배열에서 데이터를 읽어와 문자열로 변환하여 출력
      int byteData;
      StringBuilder result = new StringBuilder();
      try {
          while ((byteData = byteArrayInputStream.read()) != -1) {
              result.append((char) byteData);
          }
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          // ByteArrayInputStream, ByteArrayOutputStream 닫기
          try {
              byteArrayOutputStream.close();
              byteArrayInputStream.close();
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
    • BufferedInputStream 🎀
      • 버퍼링을 사용하여 입력 효율을 높인다.
      • 데이터의 일정량을 모아두었다가 한 번에 처리
      • 여러 번의 작은 읽기 연산보다 더 효율적으로 데이터를 읽을 수 있다.
    • BufferedOutputStream class 🎀
      • 버퍼링을 사용하여 출력 효율을 높인다.
      • 데이터를 일정량 모아두었다가 한 번에 쓰기 연산을 수행
      • 여러 번의 작은 쓰기 연산보다 더 효율적으로 데이터를 출력할 수 있다.
      // 입력 파일 경로와 출력 파일 경로
      String sourceFile = "source.txt";
      String destinationFile = "destination.txt";
      
      // 버퍼 크기 설정
      int bufferSize = 1024;
      
      // 입력 스트림과 출력 스트림 선언
      BufferedInputStream bufferedInputStream = null;
      BufferedOutputStream bufferedOutputStream = null;
      
      try {
          // 입력 파일에 대한 입력 스트림 생성
          bufferedInputStream = new BufferedInputStream(new FileInputStream(sourceFile));
      
          // 출력 파일에 대한 출력 스트림 생성
          bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destinationFile));
      
          // 파일 복사
          byte[] buffer = new byte[bufferSize];
          int bytesRead;
          while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
              bufferedOutputStream.write(buffer, 0, bytesRead);
          }
          System.out.println("File copied successfully!");
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          // 입력 스트림과 출력 스트림 닫기
          try {
              if (bufferedInputStream != null) {
                  bufferedInputStream.close();
              }
              if (bufferedOutputStream != null) {
                  bufferedOutputStream.close();
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
    • DataInputStream 🎀
      • 기본 데이터 타입을 바이트 스트림으로부터 직접 읽을 수 있게 한다.
      • int, long, float 등 타입을 읽을 때 유용하다.
    • DataOutputSteam class 🎀
      • 기본 데이터 타입을 바이트 스트림으로 쓸 수 있다.
      • int, long, float 등의 데이터 타입을 바이트 스트림에 쉽게 쓸 수 있게 해준다.
      // 파일에 데이터 쓰기
      try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(filePath))) {
          // 데이터 쓰기
          dataOutputStream.writeUTF("Hello, DataOutputStream!");
          dataOutputStream.writeInt(123);
          dataOutputStream.writeDouble(3.14);
      } catch (IOException e) {
          e.printStackTrace();
      }
      
      // 파일에서 데이터 읽기
      try (DataInputStream dataInputStream = new DataInputStream(new FileInputStream(filePath))) {
          // 데이터 읽기
          String message = dataInputStream.readUTF();
          int intValue = dataInputStream.readInt();
          double doubleValue = dataInputStream.readDouble();
      
          // 읽은 데이터 출력
          System.out.println("Message: " + message);
          System.out.println("Int value: " + intValue);
          System.out.println("Double value: " + doubleValue);
      } catch (IOException e) {
          e.printStackTrace();
      }

Char 단위 입출력 Stream

💡
자바에서 텍스트를 처리할 때 사용되는 입출력 방식으로,
문자 데이터를 읽고 쓰는데 최적화되어있으며 주로
텍스트 파일이나 문자열 데이터를 다룰 때 사용
  • 특징
    • 문자 단위 데이터 처리
      • 문자가 몇 바이트로 구성되었든 간에 문자 하나를 독립적인 단위로 취급
    • 인코딩 호환성
      • 문자 기반 스트림은 다양한 문자 인코딩을 지원
    • 텍스트 중심
      • 텍스트 파일/문자열 데이터 처리에 적합
      • HTML, XML. JSON 파일 등의 처리에 주로 사용

Reader/Writer(문자 스트림)

💡
추상 클래스로, 문자 데이터의 입력과 출력을 다루며, 여러 하위 클래스를 통해 구체화된다.
  • 추상 클래스인 Reader/Writer 상속받아 구현된 여러 하위 클래스
    • FileReader 클래스 🎇
      • 텍스트 파일로부터 데이터를 읽기 위해 사용
      • 파일의 텍스트 내용을 한 문자씩 읽거나, 문자 배열을 통해 한 번에 읽을 수 있다.
    • FileWriter 클래스 🎇
      • 텍스트 파일에 데이터를 쓰기 위해 사용
      • 문자 데이터를 파일에 쓸 수 있으며, 여러 쓰기 메서드를 제공
      // 파일에 텍스트 쓰기
      try (FileWriter fileWriter = new FileWriter(filePath)) {
          fileWriter.write("Hello, FileWriter!");
      } catch (IOException e) {
          e.printStackTrace();
      }
      // 파일에서 텍스트 읽기
      try (FileReader fileReader = new FileReader(filePath)) {
          int character;
          StringBuilder content = new StringBuilder();
          while ((character = fileReader.read()) != -1) {
              content.append((char) character);
          }
          System.out.println("File content: " + content);
      } catch (IOException e) {
          e.printStackTrace();
      }
    • StringReader 클래스 🎇
      • 문자열로 데이터를 읽는다.
      • 문자열 내의 데이터를 순차적으로 읽어 처리하는 데 사용
    • StringReader 클래스 🎇
      • 문자열로 데이터를 쓴다.
      • 내부적으로 문자열 버퍼를 관리하며, 데이터를 문자열 형태로 쉽게 작성 가능
      // 문자열
      String text = "Hello, StringWriter and StringReader!";
      
      // StringWriter를 사용하여 문자열 쓰기
      StringWriter stringWriter = new StringWriter();
      try {
          stringWriter.write(text);
      } catch (IOException e) {
          e.printStackTrace();
      }
      
      // StringWriter로부터 문자열 읽기
      StringReader stringReader = new StringReader(stringWriter.toString());
      StringBuilder result = new StringBuilder();
      try {
          int character;
          while ((character = stringReader.read()) != -1) {
              result.append((char) character);
          }
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          // StringReader 닫기
          stringReader.close();
      }
      
    • BufferedReader 클래스 🎀
      • 입력 데이터를 버퍼에 저장하여 효율적으로 읽을 수 있게 한다.
      • readLine() 메서드를 통해 한 줄씩 읽는 기능이 자주 사용된다.
    • BufferedWriter 클래스 🎀
      • 데이터를 내부 버퍼에 저장한 후 한 번에 쓰기를 수행
      • 여러 번 작은 쓰기 연산보다 효율적이며, 파일 쓰기 작업에 유용
      // 입력 파일 경로와 출력 파일 경로
      String sourceFile = "source.txt";
      String destinationFile = "destination.txt";
      
      // 파일 읽기와 쓰기를 위한 BufferedReader와 BufferedWriter 선언
      BufferedReader bufferedReader = null;
      BufferedWriter bufferedWriter = null;
      
      try {
          // 입력 파일에 대한 BufferedReader 생성
          bufferedReader = new BufferedReader(new FileReader(sourceFile));
      
          // 출력 파일에 대한 BufferedWriter 생성
          bufferedWriter = new BufferedWriter(new FileWriter(destinationFile));
      
          // 파일에서 한 줄씩 읽어서 출력 파일에 쓰기
          String line;
          while ((line = bufferedReader.readLine()) != null) {
              bufferedWriter.write(line);
              bufferedWriter.newLine(); // 새 줄 추가
          }
          System.out.println("File copied successfully!");
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          // BufferedReader와 BufferedWriter 닫기
          try {
              if (bufferedReader != null) {
                  bufferedReader.close();
              }
              if (bufferedWriter != null) {
                  bufferedWriter.close();
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
    • InputStreamReader 클래스 🎀
      • Byte 스트림을 문자 스트림으로 변환하는 데 사용
      • 바이트 기반 스트림을 문자 기반 스트림으로 연결하는 다리 역할
    • OutputStreamWriter 클래스 🎀
      • 문자 스트림을 바이트 스트림으로 변환하는 데 사용
      • 문자 기반 데이터를 바이트 기반 스트림으로 쓸 때 필요
      // 바이트 스트림과 문자 스트림을 연결할 바이트 입력 스트림과 출력 스트림 생성
      InputStream inputStream = null;
      OutputStream outputStream = null;
      
      try {
          // 바이트 입력 스트림 생성
          inputStream = new FileInputStream("input.txt");
      
          // 바이트 입력 스트림을 문자 입력 스트림으로 변환하는 InputStreamReader 생성
          InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
      
          // 문자 출력 스트림 생성
          outputStream = new FileOutputStream("output.txt");
      
          // 문자 출력 스트림을 바이트 출력 스트림으로 변환하는 OutputStreamWriter 생성
          OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
      
          // 문자를 읽어서 쓰기
          int character;
          while ((character = inputStreamReader.read()) != -1) {
              outputStreamWriter.write(character);
          }
          System.out.println("File copied successfully!");
      } catch (IOException e) {
          e.printStackTrace();
      } finally {
          // 스트림 닫기
          try {
              if (inputStream != null) {
                  inputStream.close();
              }
              if (outputStream != null) {
                  outputStream.close();
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      }

특수한 IO - System 클래스

💡
표준 입출력, 시스템 속성, 환경 변수 등과 같은 시스템 관련 작업을 수행하는 데 사용되는 클래스
  • 표준 입출력 및 오류 출력에 관련된 정적 메서드
    • System.in : 표준 입력 스트림
      • 주로 콘솔로부터 사용자의 입력을 받는데 사용
      • 이 스트림은 InputStream 형태로 제공된다 ⇒ 바이트 단위 입출력 스트림
    • System.out : 표준 출력 스트림 🎀
      • 콘솔에 데이터를 출력할 수 있다.
      • 주로 텍스트 메시지를 사용자에게 표시하는 데 사용
    • System.error : 표준 오류 출력 스트림
      • 오류 메시지나 경고를 출력하는 데 사용
      • PrintStream 클래스의 인스턴스지만 주로 오류 메시지를 다루는데 쓰인다.
      • System.err로 출력된 메시지는 System.out으로 출력된 메시지와 별도로 관리되거나,
        다른 색상으로 표시되어 오류를 더 쉽게 식별할 수 있다.
      try {
      reader.close();
      } catch (IOException e) {
      System.err.println("리더를 닫는 중 오류가 발생했습니다: " + e.getMessage());
      }

파일 입출력 ( File I/O )

💡
디스크에 저장된 파일에서 데이터를 읽고, 파일에 데이터를 쓸 수 있다.
  • 프로그램과 외부 환경 간의 데이터 교환을 가능하게 한다.
  • 주의할 점
    • 예외 처리
      • IOException을 포함한 여러 예외 발생 가능성
      • 입출력 작업은 항상 try-catch 블록 내에서 수행
    • 리소스 관리
      • 파일과의 연결은 시스템 리소스를 사용
      • 사용이 끝난 후에는 반드시 리소스를 해제
    • 버퍼링
      • 데이터를 처리할 때는 버퍼링을 사용하는 게 좋다
      • BufferedReader나 BufferedWriter와 같은 클래스를 사용하면 입출력 효율이 높다.
  • 파일 쓰는 과정
    1. 파일과의 연결 생성
      • FileOutputStream, FileWriter등의 쓰기 클래스를 사용하여 쓸 파일과 연결을 생성
    1. 데이터 쓰기
      • 파일에 데이터를 쓰기 위한 메서드 호출
      • 바이트 데이터 또는 문자 데이터를 파일에 쓸 수 있다.
    1. 리소스 해제
      • 파일 쓰기 작업이 완료되면, 파일과의 연결을 닫고 리소스를 해제
    • Byte 단위로 파일 입출력하기
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.IOException;
      
      public class ByteFileIOExample {
          public static void main(String[] args) {
              FileInputStream in = null;
              FileOutputStream out = null;
              try {
                  in = new FileInputStream("source.jpg");
                  out = new FileOutputStream("destination.jpg");
                  int byteData;
                  while ((byteData = in.read()) != -1) {
                      out.write(byteData);
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  if (in != null) {
                      try {
                          in.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  if (out != null) {
                      try {
                          out.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
      
    • Char 단위로 파일 입출력하기
      import java.io.FileReader;
      import java.io.FileWriter;
      import java.io.IOException;
      
      public class CharFileIOExample {
          public static void main(String[] args) {
              FileReader reader = null;
              FileWriter writer = null;
              try {
                  reader = new FileReader("inputText.txt");
                  writer = new FileWriter("outputText.txt");
                  int character;
                  while ((character = reader.read()) != -1) {
                      writer.write(character);
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  if (reader != null) {
                      try {
                          reader.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
                  if (writer != null) {
                      try {
                          writer.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
      

보조 스트림(Decorative Streams)

💡
데코레이터 패턴의 한 예로, Java IO에서 기본 스트림에 추가적인 기능을 제공하는 스트림
  • 기본 스트림 ⇒ 주인공 🎇
    • 파일이나 네트워크 소켓과 같은 데이터 소스나 대상과 직접적으로 연결된다.
  • 보조 스트림 ⇒ 장식 🎀
    • 기본 스트림 위에 덧붙여져서 추가적인 기능을 수행한다.
    • 데이터를 필터링하거나, 버퍼링, 문자와 바이트 간의 변환, 객체 직렬화 등 다양한 기능 수행
  • 주요 보조 스트림의 종류
    • Bufferd Streams (버퍼링 스트림)
      • BufferedReader / BufferedWriter
        • 텍스트 데이터를 처리할 때 사용
        • 내부적으로 버퍼를 사용해 입출력 효율 향상
      • BufferedInputStream / BufferedOutputSteam
        • 바이트 데이터를 처리할 때 사용
        • 버퍼링을 통해 데이터 읽기 및 쓰기 성능 향상
    • Data Streams (데이터 스트림)
      • DataInputStream / DataOutputStream
      • 바이너리 데이터를 처리할 때 사용
      • 기본 자료형의 데이터를 쉽게 읽고 쓸 수 있게 해준다.
    • Object Streams (객체 스트림)
      • ObjectInputStream / ObjectOutputStream
      • 객체의 직렬화와 역 직렬화를 위해 사용
      • 객체를 바이트 형태로 변환하거나, 바이트에서 객체로 복원할 수 있다.
    • Print Steram (프린트 스트림)
      • PrintWriter / PrintStream
      • 형식화된 데이터를 출력할 때 사용
      • System.out → PrintSteam의 한 예시
    • Character Streams to Byte Streams ( 문자 스트림과 바이트 스트림 변환)
      • InputStreamReader / OutputStreamWrite
      • 바이트 스트림과 문자 스트림 간의 변환을 위해 사

728x90

'JAVA' 카테고리의 다른 글

네트워크의 기본  (0) 2024.04.27
멀티 스레드  (2) 2024.04.27
데코레이터 패턴  (1) 2024.04.27
컬렉션 프레임워크  (1) 2024.04.27
제네릭  (1) 2024.04.26