File
파일은 기본적이면서도 가장 많이 사용되는 입출력 대상이기 때문에 중요하다
자바에서는 File 클래스를 통해서 파일과 디렉토리를 다룰 수 있도록 하고 있다
-> File 인스턴스는 파일일 수도 있고 디렉토리일 수도 있다
File의 생성자와 경로에 관련된 메서드
생성자/메서드 | 설명 |
File(String fileName) | 주어진 문자열을 이름으로 갖는 파일을 위한 File 인스턴스를 생성한다. 파일뿐만 아니라 디렉토리도 같은 방법으로 다룬다 fileName은 주로 경로를 포함해서 지정해주지만, 파일 이름만 사용해도 되는데, 이 경우 프로그램이 실행되는 위치가 경로(path)로 간주된다. |
File(String pathName, String fileName) File(File pathName, string fileName) |
파일의 경로와 이름을 따로 분리해서 지정할 수 있도록 한 생성자. 이 중 두 번째 것은 경로를 문자열이 아닌 File인스턴스인 경우를 위해서 제공된 것이다. |
File(URI uri) | 지정된 uri로 파일을 생성 |
String getName() | 파일이름을 String으로 변환 |
String getPath() | 파일의 경로(path)를 String으로 반환 |
String getAbsoulutePath() File getAbsoluteFile() |
파일의 절대경로를 String으로 반환 파일의 절대경로를 File로 반환 |
String getParent() File getParentFile() |
파일의 조상 디렉토리를 String으로 반환 파일의 조상 디렉토리를 File로 반환 |
String getCanonicalPath() File getCanonicalFile() |
파일의 정규경로를 String으로 반환 파일의 정규경로를 File로 반환 |
경로와 관련된 File의 멤버변수
멤버변수 | 설명 |
static String pathSeparator | OS에서 사용하는 경로 구분자. 윈도우 “;”, 유닉스“:” |
static char pathSeparatorChar | OS에서 사용하는 경로 구분자 윈도우 ‘;’, 유닉스 ‘:’ |
static String separator | OS에서 사용하는 이름 구분자 윈도우 “\”, 유닉스 “/” |
static char separatorChar | OS에서 사용하는 이름 구분자 윈도우 ‘\’, 유닉스 ‘/’ |
->파일의 경로와 디렉토리나 파일의 이름을 구분하는데 사용되는 구분자가 OS마다 다를 수 있기 때문에 OS 독립적으로 프로그램을 작성하기 위해서는 위의 멤버변수들을 이용해야 한다
절대경로(absolute path)는 파일시스템의 루트(root)0로부터 시작하는 파일의 전체 경로를 의미한다
하나의 파일에 대해 둘 이상의 절대경로가 존재할 수 있다 //OS마다 다르다
-> 현재 디렉토리를 의미하는 ‘.’와 같은 기호나 링크를 포함하는 경우가 이에 해당한다
정규경로(canonical path) 기호나 링크 등을 포함하지 않는 유일한 경로를 의미한다
File인스턴스를 생성했다고 해서 파일이나 디렉토리가 생성되는 것은 아니다
새로운 파일을 생성하기 위해서는 File인스턴스를 생성한 다음 출력 스트림을 생성하거나
createNewFile()을 호출해야 한다
1. 이미 존재하는 파일을 참조할 때 : File f = new File(“파일경로”, “FileEx1.java”); 2. 기존에 없는 파일을 새로 생성할 때 : File f = new FIle(“파일경로”, “NewFile.java”); f.createNewFile(); //새로운 파일이 생성된다 |
printFileList(File dir)는 디렉토리에 포함된 파일과 디렉토리의 목록을 출력하는 메서드이다
파일을 목록을 출력하고 디렉토리인 경우 ArrayList에 담았다가 printFileList(File dir)을 재귀호출한다 //재귀호출만으로도 처리가 가능함
FilenameFilter는 accept메서드 하나만 선언되어 있으며 메서드만 구현해주면 된다
public interface FilenameFilter {
boolean accept(File dir, String name); }
직렬화(serialization)
객체를 데이터 스트림으로 만드는 것을 의미한다
객체에 저장된 데이터를 스트림에 쓰기위해 연속적인 데이터로 변환한다
역직렬화(deserialization) : 스트림으로부터 데이터를 읽어서 객체를 만드는 것
직렬화는 객체가 컴퓨터에 저장되었다가 다시 꺼내 쓸 수 있도록 하며 네트웍을 통해 컴퓨터간에 서로 객체를 주고받을 수 있게한다
**간단하게 되짚어보는 객체지향
객체는 클래스에 정의된 인스턴스 변수의 집합이다
사실 객체에는 메서드가 포함되지 않는다
->객체를 저장한다는 것은 객체의 모든 인스턴스 변수의 값을 저장한다는 것과 같은 의미이다
ObjectInputStream, ObjectOutputStream
직렬화(스트림에 객체를 출력)에는 ObjectInputStream을 사용하고
역직렬화(스트림으로부터 객체를 입력)에는 ObjectOutputStream을 사용한다
각각 InputStream/OutputStream을 상속받지만 기반스트림을 필요로하는 보조스트림이다
객체 생성시 입출력 스트림 지정
ObjectInputStream(InputStream in)
ObjectOutputStream(OutputStream out)
파일에 객체를 저장(직렬화)
FileOutputStream fos = new FileOutputStream(“objectfile.ser”);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(new UserInfo());
->위 코드는 objectfile.ser이라는 파일에 UserInfo객체를 직렬화하여 저장한다
->역직렬화는 입력스트림을 사용하고 writeObject() 대신 readObject()를 사용한다
//readObject()의 반환타입이 Object이기 때문에 객체 원래의 타입으로 형변환 해야한다
defaultReadObject() defaultWriteObject() : 자동 직렬화 수행
직렬화가 가능한 클래스 Serializable, transient
직렬화하고자 하는 클래스가 java.io.Serializable 인터페이스를 구현하도록 하면 된다
public class UserInfo implements java.io.Serializable { String name; String password; int age; } |
Serializable는 빈 인터페이스지만 직렬화를 고려하여 작성한 클래스인지 판단하는 기준이 된다
public interface Serializable { }
조상클래스가 Serializable을 구현하면 자손도 직렬화가 가능하다
->구현하지 않을시 조상클래스에 정의된 인스턴스 변수가 직렬화 대상에서 제외된다
->인스턴스 변수의 타입이 아닌 실제로 연결된 객체의 종류에 의해 결정된다
transient
제어자 transient를 붙여서 직렬화 대상에서 제외되도록 할 수 있으며
password와 같이 보안상 직렬화되면 안 되는 값에 대해 transient를 사용할 수 있다
ArrayList와 같은 객체를 직렬화하면 ArrayList에 저장된 모든 객체들과 각 객체의 인스턴스 변수가 참조하고 있는 객체들까지 모두 직렬화된다
->직렬화 할 객체가 많을때는 각 객체를 개별적으로 직렬화하는 것보다 ArrayList와 같은 컬렉션에 저장해서 직렬화하는 것이 좋다
*보통은 확장자를 직렬화의 약자인 ser로 한다
직렬화가 가능한 클래스의 버전관리
직렬화된 객체를 역직렬화 할 때는 직렬화 했을 때와 같은 클래스를 사용해야한다
-> 클래스의 내용이 변경된 경우 역직렬화에 실패하며 예외가 발생한다
java.io.InvalidClassException : local class incompatible //클래스의 버전이 다른경우
static상수나 transient가 붙은 인스턴스변수가 추가되는 경우에는 직렬화에 영향을 미치지 않기 때문에 클래스의 버전을 다르게 인식하도록 할 필요는 없다
네트웍으로 객체를 직렬화하여 전송하는 경우 클래스가 조금만 변경되어도 해당 클래스를 재배포하는 것은 프로그램을 관리하기 어렵게 만든다
->클래스를 수동으로 관리해야한다
class MyData implements java.io.Serializable { int value1; } |
클래스 내에 serialVersionUID를 정의하면 클래스의 내용이 바뀌어도 자동생성된 값으로 변경되지 않는다