input, output의 약자로 컴퓨터 내부 또는 외부 장치와 프로그램 간의 데이터를 주고 받는 것을 말한다. RAM을 기준으로 파일을 입력 받으면 input, 출력하면 output이다. 파일을 입출력할 수 있게 되면 프로그램을 종료해도 데이터를 다시 불러와서 사용할 수 있는 영속성이라는 장점이 있다. 파일 입출력을 위해서 공통적인 방법으로 Stream을 사용한다.
파일이 이동하는 길인 스트림은 모두 단방향이기 때문에 입력 스트림과 출력 스트림은 따로 열린다. 하나의 스트림으로 입출력을 동시에 수행할 수 없기 때문에 동시에 입출력을 수행하려면 2개의 스트림이 필요하다. 스트림은 바이트 단위로 처리하는 바이트 기반 스트림과 문자 단위를 처리하는 문자 기반 스트림으로 나뉜다.
데이터를 바이트 단위로 처리하는 스트림에는 InputStream, OutputStream이 있다. InputStream, OutputStream이 최상위 클래스이며 추상 클래스로 해당 클래스의 하위 클래스를 이용해서 사용할 수 있다.
데이터를 문자열 단위로 처리하는 스트림으로 Reader, Writer가 있다. Reader, Writer 클래스가 최상위 클래스이자 추상 클래스로 하위 클래스를 이용해서 기능을 사용할 수 있다.
파일 시스템의 파일을 표현하는 클래스로 파일의 크기, 속성, 이름 등의 정보와 파일 생성 및 삭제 기능을 제공한다. File 변수명=new File(”파일경로”); 형태로 사용할 수 있다.
파일 경로는 절대 경로와 상대 경로로 작성할 수 있다. 절대 경로는 파일의 위치를 정확하게 지정해서 사용하는 것으로 보통 절대 경로로 작성한다. 상대 경로는 파일의 이름만 작성했을 때 현재 사용중인 폴더에 생성되는 것인데 이를 사용했을 경우 파일 위치가 변경되면 폴더 생성 위치가 달라지기 때문에 불안정하다.
//절대 경로
File f=new File("c:/Users/GDJ/file.txt");
//상대 경로
File f1=new File("test.txt");
try {
f.createNewFile(); //->예외처리가 필수인 메소드
System.out.println("파일 생성 완료"); //file 생성이 완료되면 메시지가 뜬다.
}catch(IOException e) {
e.printStackTrace(); //에러 이력 출력
System.out.println("파일 생성 실패");
}
원하는 파일을 생성하는 메소드로 mkdir()
은 하나의 파일만 생성하고 mkdirs()
는 여러 개의 파일을 생성할 수 있다.
File dir=new File("./t"); //file생성 하고 folder생성해야된다.
boolean result=dir.mkdir();
boolean result=dir.mkdirs();
System.out.println(result);
💡 ./
: 현재 경로에 저장한다. c:/Users/GDJ 경로에서 메소드를 실행 중 이었다고 하면 GDJ에 파일이 저장된다.
../
: 바로 위인 상위 경로에 저장한다. GDJ랑 같은 위치인 Users안에 저장된다.
File 클래스에서 제공하는 메소드로 파일을 삭제할 때 사용한다.
File delFile=new File("testfolder/file.txt");
delFile.delete();
File delDir=new File("testfolder"); //폴더도 삭제 가능
delDir.delete();
File info=new File("./myfolder2/a/b/test.txt");
//1.파일명 확인
System.out.println("파일명 : "+info.getName());
//2. 부모파일 확인
System.out.println("부모 경로 : "+info.getParent());
//2-1. 부모 파일을 File로 가져오기
File parent=info.getParentFile();
System.out.println("부모 파일명 : "+parent.getName());
//3. 경로 가져오기
System.out.println("경로 : "+info.getPath()); //상대경로를 가져온다.
//4. 불러온 파일이 폴더인지 파일인지 확인
System.out.println("info 폴더 : "+info.isDirectory());
System.out.println("파일 : "+info.isFile());
System.out.println("parent 폴더 : "+parent.isDirectory());
System.out.println("파일 : "+parent.isFile());
읽기 전용 파일만 구분해서 찾아주는 메소드.
스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해서 사용한다. 실제로 데이터를 주고 받는 스트림이 아니기 때문에 입출력에 대한 처리가 불가능함으로 기반 스트림을 먼저 생성한 후에 보조 스트림을 생성해서 사용할 수 있다.
보조 스트림도 하나의 클래스로 문자 변환, 입출력 성능, 기본 데이터 타입 출력, 객체 입출력하는 기능읠 제공하는 클래스들이 있다.
InputStreamReader, OutputStreamWriter 클래스를 사용한다. 바이트 기반 스트림이지만 데이터가 문자일 경우 문자 단위로 입출력을 하기 위해서 바이트 기반 스트림보다 편리하게 사용할 수 있다.
try(FileInputStream fis=new FileInputStream("strdata");
InputStreamReader isr=new InputStreamReader(fis);){
int data=0;
while((data=isr.read())!=-1) { //reader 쓴 걸로 가져와서 data에 대입
System.out.println((char)data);
//바이트 기반으로 가져왔기 때문에 char형으로 형변환하면 문자가 깨져서 나온다.
}
}catch(IOException e) {
e.printStackTrace();
}
BufferedInputStream, BufferedOutputStream 클래스를 이용한다. 느린 속도로 인해 입출력 성능에 영향을 미치는 입출력 소스를 이용해야될 때 함께 사용한다.
입출력 소스와 직접 작업하진 않지만 버퍼에 데이터를 모아서 한 번에 작업을 해서 입출력 횟수를 줄임으로 실행 성능을 향상시킨다.
지금은 컴퓨터 기능이 많이 좋아졌기 때문에 간단한 작업을 했을 때는 큰 차이를 느낄 수 없다.
try(FileOutputStream fos=new FileOutputStream("myfile");
BufferedOutputStream bos=new BufferedOutputStream(fos);){
String data="출력할 예시 문작을 작성.";
bos.write(data.getBytes());
}catch(IOException e) {
e.printStackTrace();
}
ObjectInputStream, ObjectOutputStream 클래스를 이용한다. 객체 자체를 입출력해서 다양한 자료형을 편하게 저장, 출력해서 사용할 수 있다. 단 객체는 문자가 아니므로 바이트 기반 스트림으로 데이터를 변경해주는 직렬화가 꼭 필요하다.
Serializable 인터페이스를 사용해서 객체를 직렬화 할 수 있다. 객체 직렬화를 하면 private 필드를 포함함 모든 필드를 바이르토 변환한다. 단, transient 키워드를 사용한 필드는 직렬화에서 제외된다.
직렬화, 역직렬화 기준은 JVM이 알아서 처리해준다.
바이트로 변환하는 것을 직렬화, 바이트에서 다시 객체로 변환 하는 것을 역직렬화라고 한다.
//persons를 매개변수로 전달 받고 persons.dat에 저장하는 기능을 구현
public void personsSave(Person[] persons) {
try(ObjectOutputStream oos=new ObjectOutputStream
(new FileOutputStream("persons.dat"));){
oos.writeObject(persons); //클래스 배열 자체를 받는다.
}catch(IOException e) {
e.printStackTrace();
}
}
//persons.dat에 저장된 데이터를 불러와서 반환하는 기능 구현
public Person[] personsLoad() {
Person[] result=new Person[10];
try(ObjectInputStream ois=new ObjectInputStream
(new FileInputStream("persons.dat"));){
result=(Person[])ois.readObject(); //클래스 배열 자체를 불러와서 result에 대입.
}catch(ClassNotFoundException|IOException e) {
e.printStackTrace();
}
return result;
}