과제 2. Java I/O

1. Java I/O 입출력 클래스의 종류

  • Stream으로 끝나는 클래스 : byte 단위로 입출력을 수행하는 클래스
  • Reader / Writer로 끝나는 클래스 : character 단위로 입출력을 수행하는 클래스
  • File로 시작하는 클래스 : 하드디스크의 파일을 사용하는 클래스
  • Data로 시작하는 클래스 : Java의 원시 자료형을 출력하기 위한 클래스
  • Buffered로 시작하는 클래스 : 시스템의 버퍼를 사용하는 클래스

a. InputStream / OutputStream

  • InputStream

  • OutputStream

b. Reader / Writer

  • Reader
  • Writer

c. 기타


출처: https://hyeonstorage.tistory.com/250

2. Java I/O 입출력 클래스 활용법

  1. 클래스명을 구성하는 단어들의 의미를 잘 파악해야 한다.
  2. 클래스 생성자의 의미를 잘 파악하여야 한다.
    • 생성자란? 객체를 생성하고 클래스를 보다 용이하게 활용하기 위해 클래스명에 파라미터를 추가하여 클래스 내부에 선언하는 구문.
      - 참고 : https://opentutorials.org/module/516/5519
    • API 문서를 통해 클래스의 생성자를 확인할 수 있음.
    • 생성자가 중요한 이유 : 생성자에 전달한 인자가 무엇이냐에 따라서 읽어 들여야할 대상과 써야 할 대상이 달라진다.
    • 생성자의 특징 : 반환값이 없다, 메소드명이 클래스명과 동일하다.
    • 추상클래스를 파라미터로 받는 경우도 있는데, 이 경우에는 추상클래스를 상속받는 하위 클래스를 파라미터로 입력하면 됨.
      - 추상클래스란? 비슷한 필드와 메소드를 공통적으로 추출해 만들어진 클래스(객체를 생성할 수 없음, 참고 : https://limkydev.tistory.com/188)
      - 파라미터에 있는 클래스 뿐만 아니라 클래스의 자손도 입력될 수 있음.
    • 출처 : https://www.holaxprogramming.com/2012/03/28/java-basic-io/
      ex) "키보드로부터 한 줄을 입력받아 화면에 출력 하시오"
public static void main(String[] args) throws IOException {
    InputStreamReader inputStreamReader = new InputStreamReader(System.in);
    BufferedReader br = new BufferedReader(inputStreamReader);	
    String line;
    while ((line = br.readLine()) != null) {
    	System.out.println(line);
    }
}

3. 예제로 보는 I/O 클래스 활용법

a. FileInputStream

1) file의 내용을 읽어 화면에 출력하는 프로그램

import java.io.FileInputStream;
import java.io.IOException;
 
//file의 내용을 읽어 화면에 출력하는 프로그램
public class FileView {
    public static void main(String[] args) {
        if(args.length != 1) {
            System.out.println("사용법 : java FileView 파일명");
        }
        //항상 null로 먼저 정의하고
        FileInputStream fis = null;
        try {
            //try구문에서 입출력스트림 생성
            fis = new FileInputStream(args[0]);
            int i = 0;
            while((i = fis.read()) != -1) {
                System.out.write(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                //finally구문에서 스트림 close하기
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. Stream클래스를 null로 선언
  2. try블럭에서 객체를 생성하고 사용
  3. fianlly블럭에서 io스트림을 닫음
  • FileInputStream은 InputStream의 자식 클래스다.(InputStream은 추상클래스)
  • 위 프로그램에서는 바이트 하나씩 읽어들이고 있지만 실제로 운영체제는 512 또는 1024바이트씩 읽어온다. 따라서 실제로는 굉장히 많은 입출력이 일어나고 있어 효율적이지 않다. 이 문제를 해결하기 위해서는 버퍼를 두어 한번에 읽는 것이 적절하다.(ByteArray[Input/Output]Stream, Data[Input/Output]Stream, Piped[Input/Output]Stream)
  • Try Catch문 : Try 블록에서 예외가 발생하면 catch 블록의 코드가 실행되고, 발생하지 않으면 catch 블록의 코드는 실행되지 않는다. (예외 클래스는 catch 조건으로 설정)
    - 데이터베이스와 데이터를 주고받을 경우에 예외가 많이 발생하기 때문에 데이터를 주고 받을 때 try catch문은 필수적으로 사용된다.
    - 참고 : https://coding-factory.tistory.com/280

2) 문자 단위로 파일 내용을 읽어 들여 화면에 출력하고 싶을 때

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
 
public class StreamReaderTeste {
    public static void main(String[] args) {
        if(args.length != 1) {
            System.out.println("사용법 : java StreamReaderTest 파일명");
            System.exit(0);
        }
        FileInputStream fis = null;
        InputStreamReader isr = null;
        OutputStreamWriter osw = null;
        try {
            fis = new FileInputStream(args[0]);
            isr = new InputStreamReader(fis);
            osw = new OutputStreamWriter(System.out);
            char[] buffer = new char[512];
            int readcount = 0;
            while((readcount = isr.read(buffer)) != -1) {
                osw.write(buffer,0,readcount);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                fis.close();
                isr.close();
                osw.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}
import java.io.FileReader;
import java.io.FileWriter;

public class Test2 {     
	public static void main(String[] args) throws Exception { 
		int n = 0; 
        FileReader fr = new FileReader("C:/samdata/테스트.txt"); 
        FileWriter fw = new FileWriter("C:/samdata/테스트카피.txt", false); 
        while ((n = fr.read()) != -1) {     
        	fw.write(n); 
        } 
        fr.close(); 
        fw.close();     
     } 
 }

b. FileOutputStream

1) .dat파일에 객체를 보내는 코드

package nio;
 
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
 
public class BookObjectOutputTest {
    public static void main(String[] args) {
        FileOutputStream fout = null;
        ObjectOutputStream oos = null;
        ArrayList<Book> list = new ArrayList<>();
        Book b1 = new Book("a0001","자바완성","정프로",10000);
        Book b2 = new Book("a0002","IO완성","정아마추어",20000);
        Book b3 = new Book("a0003","NIO완성","정코딩",30000);
        list.add(b1);
        list.add(b2);
        list.add(b3);
        
        try {
            fout = new FileOutputStream("booklist.dat");
            oos = new ObjectOutputStream(fout);
            
            oos.writeObject(list);
            oos.reset();
            System.out.println("저장완료");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                oos.close();
                fout.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}
  1. 객체로서 통신할 클래스를 직렬화 해야한다.(Serializable 인터페이스를 implements 한다.)
  2. 다수의 객체를 한번에 보내기 위해 ArrayList를 활용하여 객체를 묶음.
  3. 묶은 객체들을 writeObject을 활용하여 FileOutputStream객체로 전달하고, booklist.dat파일에 저장함.

4. Java 소켓 I/O 프로그래밍

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class Test02_2 {
  public static void main(String[] args) throws Exception {
    // 키보드에서 데이터를 읽는 스캐너 객체 준비
    Scanner keyScanner = new Scanner(System.in);
   
    // 1) 접속할 서버 주소 입력 받기
    System.out.print("서버 주소: ");
    String serverAddress = keyScanner.nextLine();
   
    // 2) 접속할 서버의 포트 번호 입력 받기
    System.out.print("포트 번호: ");
    int port = Integer.parseInt(keyScanner.nextLine());
   
    // 3) 사용자로부터 입력 받은 값을 가지고 서버에 접속한다.
    Socket socket = new Socket(serverAddress, port);
    System.out.println("=> 소켓 객체 생성 완료!");
   
    // 4) 입출력할 스트림 객체 준비
    InputStream in0 = socket.getInputStream();
    OutputStream out0 = socket.getOutputStream();
   
    // 5) 스트림 객체에 입출력 보조 객체를 연결한다.
    Scanner in = new Scanner(in0);
    PrintStream out = new PrintStream(out0);
    System.out.println("=> 입출력 스트림 준비 완료!");
   
    // 6) 키보드에서 서버에 보낼 메시지를 입력 받는다.
    System.out.print("서버에 보낼 메시지: ");
    String message = keyScanner.nextLine();
   
    // 7) 키보드에서 입력 받은 메시지를 서버에 보낸다.
    out.println(message);
    System.out.println("=> 서버에 메시지 전송 완료!");
   
    // 8) 서버가 보낸 메시지를 읽는다.
    String response = in.nextLine();
    System.out.println("=> 서버로부터 메시지 수신 완료!");
   
    // 9) 서버가 보낸 메시지를 화면에 출력한다.
    System.out.println(response);
   
    in.close();
    in0.close();
    out.close();
    out0.close();
    socket.close();
    keyScanner.close();
  }
}

좋은 웹페이지 즐겨찾기