자바에서 입출력을 사용할 때 스트림을 사용한다.
스트림에는 입력과 출력으로 나누어지는데 스트림이 이루어질 때 사용되는 기본자료형은 _바이트 단위_이다.

입력스트림 사용하기

package stream;

import java.io.IOException;

public class SystemInTest1 {

    public static void main(String[] args) {
        System.out.println("알파벳 하나를 쓰고 [Enter]를 누르세요");

        int i;

        try {
            i = System.in.read();
            System.out.println((char)i);
        }catch(IOException e) {
            e.printStackTrace();
        }
    }

}

  • 스트림은 반드시 예외처리를 해야한다.
  • 입력스트림을 바이트 단위로 받아 "문자형"으로 형변환 후 출력하였다.

 

여러개 입력 받기

package stream;

import java.io.IOException;

public class SystemInTest2 {

    public static void main(String[] args) {
        System.out.println("알파벳 여러개를 쓰고 [Enter]를 누르세요");

        int i;

        try {
            while((i = System.in.read()) != -1) {
                System.out.print((char)i);                
            }

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

    }

}

  • 사용자가 엔터를 누르기전까지 계속해서 문자열을 저장해뒀다가 엔터를 누르면 출력한다.

 

스캐너로 입력받기.

System.in.read 와 달리 Scanner클래스를 이용하면 다양한 자료형의 입력스트림을 받을 수 있다.

package stream;

import java.util.Scanner;

public class ScannerTest {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("이름:");
        String name = scanner.nextLine();
        System.out.println("직업:");
        String job = scanner.nextLine();
        System.out.println("사번:");
        int num = scanner.nextInt();

        System.out.println("------- 사원 정보 --------");

        System.out.println(name);
        System.out.println(job);
        System.out.println(num);

    }

}

 

파일 읽기, 쓰기

텍스트 파일 읽기1

package stream;

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

public class FileInputStreamTest1 {

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

        try {
            fis = new FileInputStream("input.txt");
            System.out.println((char)fis.read());
            System.out.println((char)fis.read());
            System.out.println((char)fis.read());
        } catch (IOException e) {
            System.out.println(e);
        }finally {
            try {
                fis.close();
            } catch (IOException e) {
                System.out.println(e);
            } catch (NullPointerException e) {
                System.out.println(e);
            }
        }
        System.out.println("end");
    }
}

  • input.txt 라는 파일을 읽어온다.
  • 한줄씩 일어와 형변환 후 출력한다 (텍스트 파일에 3줄이 되있으므로 3번 써주었다)

 

텍스트 파일 읽기1

package stream;

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

public class FileInputStreamTest2 {

    public static void main(String[] args) {

        try(FileInputStream fis = new FileInputStream("input.txt")) {
            int i;
            while((i = fis.read()) != -1) { // 파일을 한줄 씩 끝까지 반복함
                System.out.println((char)i);
            }
            System.out.println("end");            
        } catch (FileNotFoundException e) {
            System.out.println(e);
        } catch (IOException e) {
            System.out.println(e);
        } 
    }
}
  • 위에서 세줄을 읽어오기 위해 read() 메서드를 세번 써주었지만 파일의 라인수가 많은 경우나 계속 변경되는 경우에는 라인수를 할 수 없으므로 반복문을 통해 텍스트를 읽어온다.

 

배열로 파일 읽어오기

package stream;

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

public class FileInputStreamTest3 {

    public static void main(String[] args) {

        try(FileInputStream fis = new FileInputStream("input2.txt")) {
            byte[] bs = new byte[10];

            int i;
            while((i = fis.read(bs)) != -1) { // 파일을 한줄 씩 끝까지 반복함
                for(byte b : bs) {
                    System.out.print((char)b);
                }
                System.out.print(": " + i + "바이트 읽음");
            }
        } catch (FileNotFoundException e) {
            System.out.println(e);
        } catch (IOException e) {
            System.out.println(e);
        } 
        System.out.println("end");
    }
}

  • 파일을 읽을 때 문자를 10개씩 배열로 저장해 반복해서 출력하였다.
  • 결과값 3번째 줄을 보면 Z뒤에 "QRST" 가 출력되었다. 이것은 기존 2번째 라인을 저장할 때 byte 배열에 이미 저장된 요소들이 그대로 출력된 것이다.
  • 이를 방지하기 위해서는 읽어들인 바이트 수 만큼만 출력하도록 출력부분을 바꾸면 해결된다.
                for(int k=0; k < i; k++) {
                    System.out.print((char)bs[k]);
                }

 

텍스트 파일에 쓰기

package stream;

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

public class FileOutStreamTest {

    public static void main(String[] args) {
        //try(FileOutputStream fos = new FileOutputStream("output.txt")) {
        try(FileOutputStream fos = new FileOutputStream("output.txt", true)) {
            fos.write(65);
            fos.write(66);
            fos.write(67);
        }catch(IOException e) {
            e.printStackTrace();
        }

        System.out.println("출력이 완료되었습니다.");

    }

}

  • 파일아웃풋스트림으로 텍스트파일을 생성해 그 안에 아스키코드로 알파벳 ABC를 출력한다.
  • 만약 파일을 이어서 작성하고 싶다면 FileOutStream 생성자 두번째 인자에 true를 넘겨준다.
    FileOutputStream fos = new FileOutputStream("output.txt", true)

 

배열로 저장해 파일에 쓰기

package stream;

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

public class FileOutStreamTest2 {

    public static void main(String[] args) {

        try(FileOutputStream fos = new FileOutputStream("output2.txt")) {
            byte[] bs = new byte[26];
            byte data = 65;

            for(int i=0; i < bs.length; i++) {
                bs[i] = data;
                data++;
            }

            fos.write(bs);            

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

        System.out.println("출력이 완료되었습니다.");

    }

}

  • InputStream과 마찬가지로 byte 배열을 사용해 자료를 한꺼번에 출력할 수 있다.
  • 만약 읽어드린 데이터에서 일부만 출력하고 싶다면 write() 메서드의 인자를 아래와 같이 넘기면 원하는 부분만 출력할 수 있다.
    fos.write(bs, 2, 10);

 

문자 단위 스트림

앞서 파일스트림은 바이트 단위로 문자를 읽고/쓰기 때문에 한글처리에 문제를 가진다.

한글텍스트 파일 읽기 문제점.

앞에 실습했던 FileInputStreamTest2 예제해서 한글로 된 파일을 읽어서 출력해보자.

package stream;

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

public class FileInputStreamTest2 {

    public static void main(String[] args) {

        try(FileInputStream fis = new FileInputStream("reader.txt")) {
            int i;
            while((i = fis.read()) != -1) { // 파일을 한줄 씩 끝까지 반복함
                System.out.println((char)i);
            }
            System.out.println("end");            
        } catch (FileNotFoundException e) {
            System.out.println(e);
        } catch (IOException e) {
            System.out.println(e);
        } 
    }
}

  • 바이트단위로 읽어오지만 한글은 한글자당 기본 2바이트의 크기를 가지고 있으므로, 알아볼 수 없는 문자가 출력되었다.

 

FileReader로 한글파일 읽기.

package stream;

import java.io.FileReader;

public class FileReaderTest {
    public static void main(String[] args) {
        // 파일리더로 "안녕하세요"가 적혀있는 텍스트 파일을 읽어옴.
        try(FileReader fr = new FileReader("reader.txt")) {
            int i;
            while((i = fr.read()) != -1) {
                System.out.print((char)i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  • 사용방법은 FileInputStream 이랑 똑같다.
  • 문자를 다룰 때는 FileReader 클래스로 처리하는게 좋다.

 

FileReader로 쓰기

package stream;

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

public class FileWriterTest {

    public static void main(String[] args) {
        try(FileWriter fw = new FileWriter("writer.txt")) {
            fw.write('A');
            char buf[] = {'B', 'C', 'D', 'E', 'F', 'G'};

            fw.write(buf);
            fw.write("안녕하세요. 잘써지나요?");
            fw.write(buf, 1, 2);
            fw.write(65);            
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("출력이 완료되었습니다.");
    }

}

 

보조스트림

보조스트림은 기반스트림처럼 파일이나 네트워크에 읽기/쓰기 권한은 없다.
하지만 기반스트림이 못하는 기능을 옆에서 도와줘서 기반스트림이 할 수 없는 스트림 기능을 구현할 수 있다.

보조스트림을 활용해 한글텍스트 읽어오기

package stream;

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

public class InputStreamReaderTest {

    public static void main(String[] args) {
        try(InputStreamReader isr = new InputStreamReader(new FileInputStream("reader.txt"))) {
            int i;
            while((i = isr.read()) != -1) {
                System.out.print((char)i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

  • 원래 FileInputStream 클래스는 바이트단위로 문자를 처리하기에 한글을 읽을 수 없다.
  • 하지만 InputStreamReader의 생성자로 넘겨주었기에 바이트단위로 파일을 읽어오더라도 문자로 변환을 시켜주기에 정상적으로 한글을 읽어올수 있게 되었다.

 

Buffered 스트림

Buffered 스트림을 활용하면 한 바이트씩 입/출력을 수행하는 것보다 더 빠르게 프로그램을 수행할 수 있다.

FileInputStream 을 이용하여 파일 복사하기.

package stream;

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

public class FileCopyTest {

    public static void main(String[] args) {
        long millisecond = 0;

        try(FileInputStream fis = new FileInputStream("a.zip");
            FileOutputStream fos = new FileOutputStream("copy.zip")) {

            millisecond = System.currentTimeMillis();

            int i;

            while((i = fis.read()) != -1) {
                fos.write(i);
            }

            millisecond = System.currentTimeMillis() - millisecond;

        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("파일 복사하는데" + millisecond + " 초 소요되었습니다.");
    }

}

 

보조스트림 Buffered 활용하여 파일 복사하기

package stream;

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

public class BufferedStreamTest {

    public static void main(String[] args) {
        long millisecond = 0;

        try(FileInputStream fis = new FileInputStream("a.zip");
            FileOutputStream fos = new FileOutputStream("copy.zip");
            BufferedInputStream bis = new BufferedInputStream(fis);
            BufferedOutputStream bos = new BufferedOutputStream(fos)) {

            millisecond = System.currentTimeMillis();

            int i;

            while((i = bis.read()) != -1) {
                bos.write(i);
            }

            millisecond = System.currentTimeMillis() - millisecond;

        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("파일 복사하는데" + millisecond + " 초 소요되었습니다.");
    }
}  

  • 기반스트림과 보조스트림을 활용하여 파일을 복사했다.
  • 파일을 읽고 쓰는 속도가 굉장히 빨라졌다.
  • Buffered 스트림은 한번에 8192 바이트의 배열을 저장할 수 있으므로 이러한 속도가 가능한 것이다.

 

DataInputStream, DataOutputStream

(생략)

 

직렬화

직렬화란 인스턴스 자체를 외부에 전달할 수 있도록 값 형태로 저장하는 것을 의미한다.
즉, 인스턴스 변수 값을 스트림으로 만드는 것이다.

Person 클래스 직렬화/역직렬화 구현하기.

package stream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Person implements Serializable {

    /**
     * 직렬화 버전 생성 고유아이디
     */
    private static final long serialVersionUID = -2384750752214662238L;

    String name;
    String job;


    public Person() {}

    public Person(String name, String job) {
        this.name = name;
        this.job = job;
    }

    public String toString() {
        return name + "," + job;
    }

}

public class SerializationTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Person personAhn = new Person("안대용", "과장");
        Person personYang = new Person("양기모", "사원");

        // 직렬화
        try(FileOutputStream fos = new FileOutputStream("serial.out"); 
            ObjectOutputStream oos = new ObjectOutputStream(fos)) {

            oos.writeObject(personAhn);
            oos.writeObject(personYang);

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


        // 역직렬화
        try(FileInputStream fis = new FileInputStream("serial.out");
            ObjectInputStream ois = new ObjectInputStream(fis)) {

            Person p1 = (Person)ois.readObject();
            Person p2 = (Person)ois.readObject();

            System.out.println(p1);
            System.out.println(p2);

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

    }
}

  • Person객체의 변수 값들을 직렬화로 한 후 다시 읽어서 콘솔에 출력하였다(역직렬화)
  • 직렬화를 한다는 것은 객체정보를 외부에 노출 시킨다는 의미이기에 이 객체는 직렬화 할 것이라는 정보를 기재해야한다.
  • 그러므로 Person 객체는 Serializable 인터페이스를 상속받았다.
  • 객체의 직렬화 대상에서 제외하고자 한다면 변수 앞에 transient 예약어를 추가한다.
    • 예) transient String job;

 

File 클래스

파일을 직접 입/출력할 수 없지만, 파일 정보나 생성을 할 수 있다.

package stream;

import java.io.File;
import java.io.IOException;

public class FileTest {
	public static void main(String[] args) throws IOException {
		File file = new File("C:\\fileTest\\newFile.txt");
		file.createNewFile();
		
		System.out.println(file.isFile());
		System.out.println(file.isDirectory());
		System.out.println(file.getName());
		System.out.println(file.getAbsolutePath());
		System.out.println(file.getPath());
		System.out.println(file.canRead());
		System.out.println(file.canWrite());
		
		file.delete();
		
	}
}

파일 생성 후 delete() 메서드로 다시 지워짐.

 

출처: do it 자바프로그래밍

'프로그래밍 > Java' 카테고리의 다른 글

Iterator를 사용 list의 객체 삭제하기  (0) 2021.11.02
쓰레드  (0) 2020.05.10
예외처리  (0) 2019.12.29
스트림  (0) 2019.12.27
람다식  (0) 2019.12.25
블로그 이미지

파니동

,