Java 입출력 패키지

김정훈·2024년 5월 10일

Java

목록 보기
35/48

입출력(I/O)

java.io 패키지

1. 입출력

  • Input/Output 입력 / 출력
  • 컴퓨터 내부 또는 외부와 프로그램간의 데이터를 주고받는 것

2. 스트림(stream)

데이터가 이동하는 통로

  • 입력 통로(입력 스트림)
  • 출력 통로(출력 스트림)

1) 바이트기반 스트림

데이터 크기가 바이트 단위
1바이트씩 읽어오는 스트림

[입력 스트림]

InputStream : 추상 클래스

1. 기반 스트림

직접 데이터에 접근해서 읽어오는 스트림
1바이트씩 읽어 오는 형태int read()

  • FileInputStream
  • ByteArrayInputStream

참고)

  • Unsigned : 양의 정수
  • Unsined Byte : 0 ~ 255

입력 스트림의 끝에 도달한 경우 반환값이 -1 / 바이트 범위에서 부족 👉 더 큰 자료형 int를 반환

int read()

public class Ex01 {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("test1.txt")){
            int ch = fis.read(); //1byte씩 읽어옴 A
            System.out.println((char)ch);

            ch = fis.read();//B를 읽어옴
            System.out.println((char)ch);

            ch = fis.read(); //C를 읽어옴
            System.out.println((char)ch);

            ch = fis.read(); //D를 읽어옴
            System.out.println((char)ch);

            ch = fis.read(); //E를 읽어옴
            System.out.println((char)ch);

            ch = fis.read(); // 다읽고나면 -1을 읽어옴
            System.out.println(ch);
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

while문을 사용해서 반복하고 파일의 끝 -1을 반환받으면 종료한다.

public class Ex02 {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("test1.txt")){
            int ch = 0;
            while((ch = fis.read()) != -1){
                System.out.println((char)ch);
            }

        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

available

public class Ex03 {
    public static void main(String[] args) {
        try(FileInputStream fis = new FileInputStream("test1.txt")){
            while(fis.available()>0){
                System.out.print((char)fis.read());
            }
        } catch(IOException e){
            e.printStackTrace();
        }
    }
}

버퍼
위와 같이 1byte씩 읽어온다면 비효율적이다.
👉 버퍼를 사용하여 더 큰 크기로 읽어온다. read(byte[] b)
버퍼는 기존값을 삭제하고 담지 않고 삭제는 생략하고 덮어씌운다.
버퍼는 성능을 위해 사용하기 때문에 삭제를 생략하여 성능을 증가시킨다.
그렇기 때문에 마지막은 중복이 될 수 있다.

public class E {
    public static void main(String[] args) {
        try(FileInputStream fis = new FileInputStream("test1.txt")){
            byte[] buffer = new byte[5];
            while(fis.available() > 0){
                int ch = fis.read(buffer);  //ch -> 읽어온 바이트수
                //버퍼는 기존값을 삭제하고 담지 않고 삭제는 생략하고 덮어씌운다.
                //버퍼는 성능을 위해 사용하기 때문에 삭제를 생략하여 성능을 증가시킨다.
                //그렇기 때문에 마지막은 중복이 될 수 있다.
                for(int i = 0 ; i< ch; i++){
                    System.out.print((char)buffer[i]);
                }
                System.out.println();
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

2. 보조 스트림 : 다른 스트림에 추가적인 기능을 부여하는 스트림

생성자 매개변수 InputStream

  • FilterInputStram : 보조스트림의 체계를 정리하기 위한 클래스
    • BufferedInputStream : 버퍼 기능 추가
    • DataInputStream : 기본 자료형으로 데이터를 읽을 수 있는 기능 추가
      • 한 가지 자료형으로 사용하는 것
      • 끝까지 다읽은 후에 읽으면 EOFException 발생
public class Ex04 {
    public static void main(String[] args) {
        try(FileInputStream fis = new FileInputStream("score.txt");
            DataInputStream dis = new DataInputStream(fis)){

            while (true) {
                int score = dis.readInt();
                System.out.println(score);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
  • ObjectInputStream : 객체 형태로 변환하여 읽어 오는 기능 추가
  • InputStreamReader : 바이트 단위 스트림 👉 문자 단위 스트림으로 변환 가능

[출력 스트림]

OutputStream : void write(int..) 추상 클래스

1. 기반 스트림 : 직접 데이터에 접근해서 출력하느 스트림

  • FileOutputStream :
public class Ex01 {
    public static void main(String[] args) {
        try(FileOutputStream fos = new FileOutputStream("text1.txt")){
            for(char ch = 'A'; ch <= 'Z'; ch++){
                fos.write(ch);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
-------------------------------------------------------------------------
//FileOutputStream의 두번째 매개변수 boolean append에 false값을 주면
//파일 커서를 맨뒤로 해서 데이터를 끝에 추가한다.
public class Ex01 {
    public static void main(String[] args) {
        try(FileOutputStream fos = new FileOutputStream("text1.txt", true)){
            for(char ch = 'A'; ch <= 'Z'; ch++){
                fos.write(ch);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
  • ByteArrayOutputStream :

2. 보조 스트림 : 다른 스트림에 추가적인 기능을 제공 - 생성자 매개변수 OutStream

  • FilterOutputStream : 보조스트림의 체계를 정의하기 위한 클래스
    • BufferedOutputStream : 출력 스트림 + 버퍼기능
    • DataOutputStream : 기본형으로 데이터를 출력할 수 있는 기능.
  • ObjectOutputStram : 객체 형태로 데이터를 출력하는 기능 추가
public class Ex01 {
    public static void main(String[] args) {
        try(FileOutputStream fos = new FileOutputStream("test1.txt");
            DataOutputStream dos = new DataOutputStream(fos)){
            dos.writeByte(100);
            dos.writeChar('A');
            dos.writeUTF("안녕하세요");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

public class Ex02 {
    public static void main(String[] args){
        try(FileInputStream fis = new FileInputStream("test1.txt");
            DataInputStream dis = new DataInputStream(fis)){
            byte num = dis.readByte(); //순서가 변경되면 오류가발생
            char ch = dis.readChar(); 
            String str = dis.readUTF();

            System.out.printf("num=%d, ch=%c, str=%s%n",num, ch, str);
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

참고

데코레이터 패턴

2) 문자기반 스트림

데이터 크기가 문자 단위
유니코드 - 2, 3 바이트

[입력 스트림]

Reader : 추상 클래스

1. 기반 스트림

데이터에 직접 접근하는 스트림
FileReader :

public class Ex03 {
    public static void main(String[] args) {
        try(FileReader fr = new FileReader("test2.txt")){
            int ch = 0;
            while((fr.read()) != -1){
                System.out.print((char)ch);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

CharArrayReader :
StringReader :

2. 보조 스트림

입력스트림 + 추가 기능
생성자 매개변수 Reader

  • FilterReader
    • BufferedReader : 버퍼 기능
  • InputStreamReader : 바이트 단위 스트림 👉 문자 단위 스트림으로 변환 기능
    • Reader로 사용이 불가한 InpusStream인 경우 변환
    • 생성자 매개변수 String charSetName, Charset cs : 변환하려고 하는 문자표(유니코드)
    • 2바이트 유니코드 : ISO8859_1 / EUC-KR, CPC949
    • 3바이트 유니코드 : UTF-8
    • String getEncoding(): 문자표의 종류

참고)

InputStream System.in : 표준 입력(1바이트 단위)
System.in은 바이트 단위 스트림이기 때문에
읽기위해서는 InputStreamReader를 사용해서 바이트 단위 스트림을 문자 단위 스트림으로 변환하여 사용한다.

public class Ex04 {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in; //바이트 단위 스트림
        InputStreamReader isr = new InputStreamReader(in);
        //InputStreamReader를 사용하여 바이트 단위스트림을 문자 단위 스트림으로 변환d
        char ch = (char)isr.read();
        System.out.println(ch);
    }
}

[출력 스트림]

Writer : 추상 클래스

1. 기반 스트림

데이터에 직접 접근하는 스트림

  • FileWriter
  • CharArrayWriter
  • StringWriter

2. 보조 스트림

생성자 매개변수 Writer
출력 스트림 + 추가 기능

  • FilterWriter
    • BufferedWriter : 버퍼기능

데코레이터 패턴

 class BufferedInputStream extends InputStream{
 	private InputStream inl
    public BufferedInputStream(InputStream in){
    this.in = in;
    }
    //read 메서드의 기능은 추가적인 기능과 함께 다른 스트림의 기능을 대신 수행
    public int read(){
    	//버퍼 기능에 대한 코드 ... //추가기능
    	int byte = in.read(); // 다른 스트림의 읽기 기능을 대신 수행
        //버퍼 가능에 대한 코드 ... //추가기능
        return byte
	
    }
}
public interface Calculator {
    long factorial(long num);
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class ImplCalculator implements Calculator {
    @Override
    public long factorial(long num) {

        long total = 1L;
        for(long i = 1; i<=num;i++){
            total *= i;
        }
        return total;
    }
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class RecCalculator implements Calculator{
    @Override
    public long factorial(long num) {
        if(num<1L){
            return 1L;
        }
        return num * factorial(num - 1);
    }
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class Decorate implements Calculator {

    private Calculator calculator;
    public Decorate(Calculator calculator){
        this.calculator = calculator;
    }

    public long factorial(long num){

        long stime = System.nanoTime(); // 공통 추가 기능
        try {
            long result = calculator.factorial(num); // 핵심 기능을 대신 수행

            return  result;
        }finally {
            long etime = System.nanoTime(); // 공통 추가 기능
            System.out.println(etime - stime);
        }
    }
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class Ex02 {
    public static void main(String[] args) {
        Calculator cal1 = new Decorate(new ImplCalculator());
        long result1 = cal1.factorial(10L);
        System.out.println(result1);

        Calculator cal2 = new Decorate(new RecCalculator());
        long result2 = cal1.factorial(10L);
        System.out.println(result2);

    }
}

AOP(Aspect Oriented Programming) : 관점 지향 프로그래밍
관점 : 공통 관심사

3. 표준입출력 : 콘솔에 입력, 출력

JVM이 생성해 주는 객체

1) System.in : InputStream

터미널에서 입력, 바이트 단위 스트림
InPutStreamReader : 문자 단위 스트림으로 변경

2) System.out : PrintStream

문자 단위 출력 스트림
print(), printf(), println() 편의 메서드 포함. + 버퍼(8kb)

3) 참고 : PrintWriter

문자 단위 출력 스트림
print(), printf(), println() 편의 메서드 포함. + 버퍼(8kb)

4) System.err : PrintStream

표준 에러 스트림, 글자 색이 빨간색

public class Ex01 {
    public static void main(String[] args) {
        System.err.println("에러");
    }
}

4. File

  • 파일, 디렉토리를 파일 객체로 생성해서 관리
  • 파일, 디렉토리에 유용한 기능..

1) 파일경로

Windows : D:₩경로명₩파일명.확장자
리눅스 : /home/project/파일명
👉 File.separator

2) 환경변수

(OS내에서 사용가능한 변수) 구분문자
Windows : ;
리눅스 : :
👉 File.pathSeparator

3) 쓰기, 읽기, 실행 권한

boolean canRead() : 일기 권한 여부
boolean canWrite() : 쓰기 권한 - false이면 수정, 삭제 ❌
boolean canExecute() :

void setReadable(..) :
void setWritable(..) :
void setExecutable(..) :

void setReadOnly() : 읽기 전용

String getAbsolutePath() : 파일 전체 경로
String getCanonicalPath() : 정규화된 파일 경로(상대경로 👉 전체 경로 변경)

public class Ex07 {
    public static void main(String[] args) throws IOException {
        File file = new File("/Users/oreo/Desktop/fstudy/sub1/sub2/sub3/test1.txt");
        String absolutePath = file.getAbsolutePath();
        System.out.println(absolutePath);

        ///Users/oreo/Desktop/fstudy/sub1/test1.txt
        File file2 = new File("/Users/oreo/Desktop/fstudy/sub1/sub2/sub3/../../../test1.txt");
        String aabsolutePath2 = file2.getAbsolutePath();
        System.out.println(aabsolutePath2);

        ///Users/oreo/Desktop/fstudy/test1.txt
        String canonicalPath = file2.getCanonicalPath();
        System.out.println(canonicalPath);
    }
}

getName(), getPath()

public class Ex07 {
    public static void main(String[] args) throws IOException {
        ...
        System.out.println("getName() : " + file.getName());
        System.out.println("getPath() : " + file.getPath());
        //getName() : test1.txt
		//getPath() : /Users/oreo/Desktop/fstudy/sub1/sub2/sub3/test1.txt

    }
}

mkdir()

public class Ex04 {
    public static void main(String[] args) throws IOException {
        //File file = new File("/Users/oreo/Desktop/test1.txt");
        //file.createNewFile();
        File dir = new File("/Users/oreo/Desktop/fstudy");
        File file = new File(dir,"test1.txt");
        //exists() : 파일 또는 디렉토리 존재 유무 체크
        if(!dir.exists()) { //디렉토리가 없는 경우
            dir.mkdir(); //디렉토리생성
            System.out.println("디렉토리생성");
        }
        file.createNewFile();
    }
}

mkdirs()

public class Ex05 {
    public static void main(String[] args) throws IOException {
        File dir = new File("/Users/oreo/Desktop/fstudy/sub1/sub2/sub3");
        File file = new File(dir,"test1.txt");

        if(!dir.exists()){
            dir.mkdirs(); //하위 폴더도 재귀적으로 모두 생성
        }
        file.createNewFile();
        
        System.out.println(dir.isDirectory()); //디렉터리인지 판별
        System.out.println(dir.isFile()); //파일인지 판별
    }
}

createTempFile()

public class Ex06 {
    public static void main(String[] args) throws IOException {
        File tmpFile = File.createTempFile("tmp",".log", new File("/Users/oreo/Desktop/fstudy")); // tmp(난수).log
    }
}

delete(), deleteOnExit()

public class Ex06 {
    public static void main(String[] args) throws IOException, InterruptedException {
        File tmpFile = File.createTempFile("tmp",".log", new File("/Users/oreo/Desktop/fstudy"));
        //tmpFile.delete(); //바로삭제
        tmpFile.deleteOnExit(); //애플리케션이 종료되면 삭제

        Thread.sleep(5000);
        System.out.println("종료!");
    }
}

5. 직렬화(Serialization)

  • 객체에 저장된 데이터를 스트림에 쓰기(write)위해 연속적인(serial) 데이터로 변환하는 것을 말한다.
  • 직렬화 👉 데이터 노출 👉 위험한 작업 👉 의사 표현(Serialable 인터페이스 상속 👉 진행하겠음을 표현)
  • Serialization 인터페이스(구현 내용 ❌ - 마커인터페이스)
    👉 변환 값 : 다시 객채로 복구할 때 필요한 항목 직렬화
    👉 객체마다 변경될 수 있는 값(인스턴스 변수)만 직렬화, 메서드, 상수는 직렬화되지 않는다.
  • 직렬화를 하지 않으면 데이터를 쓰기할수가 없다.

Serialization 인터페이스 구현

public class Book implements Serializable { //인터페이스를 상속받아야한다.
    private int isbn; //도서번호
    private String title; //도서명
    private String author; //저자

    public Book(int isbn, String title, String author) {
        this.isbn = isbn;
        this.title = title;
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "isbn=" + isbn +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

1) ObjectInputStream

객체 형태로 읽기.

  • 객체로 복구(새로 생성 👈 객체마다 다른데이터(인수턴스 변수 값)를 주입)
public class Ex02 {
    public static void main(String[] args) {
        try(FileInputStream fis = new FileInputStream("book.txt");
            ObjectInputStream ois = new ObjectInputStream(fis)){
            /*
            Book book = new Book(..., ..., ...);
            복구시에 필요한 데이터가 저장 -> 다시 객체 생성, 값 대입
             */
            Book book1 = (Book)ois.readObject();
            System.out.println(book1);
        }catch (IOException | ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}
  • 저장한 순서대로 객체를 복구 가능 👉 불편함 발생
  • 불편함 해소를 위해 객체 저장시 컬렉션 프레임워크의 List,Set,Map을 활용

2) ObjectOutputStream

객체 형태로 저장.
👉 객체를 복구할 때 필요한 항목 저장
(복구가 필요한 데이터 - 객체마다 다른 데이터(인스턴스 변수 : 직렬화)

public class Ex01 {
    public static void main(String[] args) {
        try(FileOutputStream fos = new FileOutputStream("book.txt");
            ObjectOutputStream oos = new ObjectOutputStream(fos)){

            Book book1 = new Book(1000,"책1","저자1");
            oos.writeObject(book1);
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

3) map

public class Book implements Serializable {
    private int isbn; //도서번호
    private String title; //도서명
    private String author; //저자 

    public Book(int isbn, String title, String author) {
        this.isbn = isbn;
        this.title = title;
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "isbn=" + isbn +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

public class Ex03 {
    public static void main(String[] args) {
        try(FileOutputStream fos = new FileOutputStream("data.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos)){
            HashMap<String, Object> data = new HashMap<>();
            Book book1 = new Book(1000,"책1","저자1");
            Book book2 = new Book(1001,"책2","저자2");
            List<Book> books = Arrays.asList(
              new Book(1002,"책3","저자3"),
              new Book(1003,"책4","저자4")
            );
            data.put("book1",book1);
            data.put("book2",book2);
            data.put("books",books);
            data.put("str","안녕하세요.");

            oos.writeObject(data);
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

public class Ex04 {
    public static void main(String[] args) {
        try(FileInputStream fis = new FileInputStream("data.obj");
            ObjectInputStream ois = new ObjectInputStream(fis)){

            HashMap<String, Object> data = (HashMap<String, Object>)ois.readObject();
            List<Book> books = (List<Book>)data.get("books");
            System.out.println(books);
            String str = (String)data.get("str");
            books.forEach(System.out::println);
            System.out.println(str);

        }catch(IOException | ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}

4) transient

직렬화를 배제할수있는 기능

public class Book implements Serializable {
    private  transient String author; //직렬화 배제
profile
안녕하세요!

0개의 댓글