자바의 입출력(Input/Output)은 꽤 복잡합니다.
우리가 사는 세상에서는 문제를 대할 때 복잡하면 그 자체로 좋지 않은 것이 대부분인데,
왜 자바의 입출력이 복잡해졌냐고 곰곰히 생각해 보면 자바의 입출력 시스템 설계자들은
파일이나, 콘솔, 네트워크 연결등 자바에서 읽고 써야 할 미디어 종류뿐만 아니라
미디어로부터 읽고,써야할 정보를 가장 적합한 형태로 읽고 쓸수 있는 다양한 방법들을
제공하려고 했기 때문입니다.
이렇게 설계한 덕분에 자바의 입출력 기능은 기타 어떤 언어와도 비교해도 손색이
없을 정도로 다양하고 풍부한 기능을 갖게 되었습니다만 자바의 입출력 관련된 클래스가
상당히 많아지고 사뭇 복잡하게 되었습니다.
자바에서 제공하는 풍부한 입출력 기능을 이용해 좀더 쉽게 좀더 효율적으로 프로그램
할 수 있습니다. 대신 좀 똑똑해 져야 하겠습니다.
파일(File) 클래스
데이터소스
정보를 저장하거나 저장된 정보를 얻기 위해서 사용되는 가장 널리 쓰이는 데이터소스
(Data Source)는 파일입니다.
데이터 소스는 정보를 저장하고 있는 그 물리적 형태를 두고 의미한 것은 아닙니다.
데이터 소스는 물리적인 디스크에 존재하는 데이터베이스가 될 수도 있고, 단순한 파일
일 수도 있고, 메모리에 있는 XML 문서일 수도 있습니다. 여기서 데이터 소스라고 했을 때
그 데이타소스는 정보를 읽고 쓸 수 있는 모든 논리적인 공간을 의미한다고 이해하겠습니다.
File 클래스의 성격
파일은 윈도우 파일시스템이나 유닉스 파일시스템을 경험해 본 분들은 직관적으로 느끼실
수 있을 것입니다. 이런 직관적인 생각은 자바에서도 다르지 않습니다.
자바에서 File 클래스는 파일 시스템의 실제 파일 자체는 아닙니다.
File클래스가 의미하는 것은 파일시스템의 실제 파일의 껍데기 부분이라고 여기시면 오히려
적합하지 않을까 합니다. 자바의 File클래스는 물리적인 File의 내용알맹이와는 직접적인
관련은 없다는 것입니다. File클래스가 파일의 내용알맹이와 관계가 없다보니 파일의 내용을
읽어 본다던가 파일에 정보을 저장한다던가하는 이런 행동들은 File 클래스를 통해서는
할 수 없습니다. File클래스로는 읽고,쓰기를 할 수 없다는 뜻입니다.
자바에서의 File 클래스는 실제 파일시스템의 파일이나 디렉토리에 대한 의미를 모아
놓은 것입니다. 파일시스템의 실제 파일이나 디렉토리에 대한 정보를 구하고자 할 때는
File 클래스를 통하면 아주 효과적입니다. 파일이나 디렉토리자체를 읽고,쓰지는 못하지만
파일이나 디렉토리에 대한 정보를 구하고자 할때는 아주 유용하게 사용됩니다.
이런 성격 때문에 File클래스는 유틸리티(Utility) 클래스라고 불립니다.
File클래스의 기능
File클래스를 이용하면 File클래스가 가리키는 파일에 대한 정보를 얻을 수 있습니다.
즉 File클래스가 가리키는 파일이 읽기 권한이 주어졌는지, 쓰기 권한 이 주어졌는지 알아
볼 수도 있습니다. 파일을 파일시스템에서 지울 때나, 파일시스템에 새로운 디렉토리를
만들 때 File클래스를 사용합니다. 파일이 실제로 존재하는지 여부와 실제 파일의 절대 경로
도 알아 볼수 도 있고, 파일인지 디렉토리인지 구별할 수 있고 디렉토리에 어떤 내용이
있는지 목록을 볼수 도 있으며, 파일의 크기도 알아 볼수 있습니다.
그 외에도 많은 다양한 기능이 있는데 실제로 File클래스에서 제공하고 있는 메소드들은
실제 프로그램에서 많이 사용되고 있고 그 빈도도 상당히 높습니다.
File클래스 예제
언급했듯이 File클래스는 실제의 파일에 대해서 읽고,쓰는 메소드는 전혀 포함하고 있지
않고 파일에 대한 종합적인 정보를 얻을 수 있는 방법을 제공해 주는 클래스입니다.
파일에 대한 껍데기 부분이라고 표현한 이유는 단지 이 이유 때문입니다.
import java.io.*;
import java.util.*;
/**
* File클래스의 기능을 보여줍니다.
*/
public class FileDemo {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("java -classpath CLASSPATH FileDemo file명");
System.exit(1); // 자바 버추얼머신을 끝냅니다.
}
String name = args[0]; // 관심의 대상되는 파일
// 파일이름 name에 대한 File 인스턴스를 만듭니다.
File f = new File(name);
if (f.exists())
System.out.println(name + "은 존재합니다.");
else {
System.out.println(name + "이 없습니다.");
System.exit(1);
}
if (f.canRead())
System.out.println(name + "은 읽기 가능합니다.");
if (f.canWrite())
System.out.println(name + "은 쓰기 가능합니다.");
System.out.println(name + "의 파일명은 " + f.getName() + "입니다.");
System.out.println(name + "의 절대경로는 " + f.getAbsolutePath() + "입니다.");
if (f.isFile())
System.out.println(name +"의 크기는 " + f.length() + " 바이트입니다.");
// f가 디렉토리인지 확인합니다.
if (f.isDirectory()) {
String[] fileNames = f.list(); // 디렉토리 f의 목록을 구합니다.
System.out.println(name + "은 Directory입니다.");
System.out.println(name + " Directory 아래의 파일입니다.");
for(int i = 0; i < fileNames.length; i++ ) {
System.out.println(fileNames[i]);
}
}
System.out.println(name + "의 마지막 변경시각은 " + new Date(f.lastModified()) +
" 입니다.");
}
}
예제 6 - 1 FileDemo.java
예제 6 - 1에서는 File클래스의 가장 기본적인 메소드에 대해서 살펴보았습니다.
그림 6 - 1 [ run FileDemo]
예제 6 - 1에서 File클래스를 이용해서 파일이 존재하는지 여부와 파일이 읽기,쓰기가
가능한지, 파일시스템에서의 절대경로는 언제인지, 파일이 마지막으로 변경된 시간이
언제인지등을 알아보았습니다.
프로그램을 하다보면 때로는 파일시스템에 없는 디렉토리를 만들어야 하는 경우도 있고
존재하는 디렉토리의 목록을 보아야 하는 경우가 있을 수 있습니다.
특히 디렉토리에 특정한 조건에 맞는 파일 목록을 보아야 하는 경우도 있습니다.
즉, 디렉토리 아래에 ".java"로 끝나는 파일의 목록만 구하는 경우 말입니다.
디렉토리에 관련된 정보를 구할때도 자바에서는 아이러니칼하게 File클래스를 이용합니다.
자바에는 Directory클래스는 없습니다. 조금 이상하게 들릴지도 모르겠지만 우리가
디렉토리라고 부르는 것 또한 파일시스템에 존재하는 파일인 것을 생각해보면 Directory
클래스가 없고, File클래스에서 디렉토리 관련 메소드를 제공하는 것이 어색한 것은
아닐 것입니다.
import java.io.*;
import java.util.*;
/**
* File클래스의 디록토리관련 기능을 보여줍니다.
*/
public class DirectoryDemo {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("java -classpath CLASSPATH DirectoryDemo file명");
System.exit(1); // 자바 버추얼머신을 끝냅니다.
}
String directoryName = args[0];
File f = new File(directoryName);
if (f.exists()) {
System.out.println(directoryName + "이 존재합니다.");
}
else {
f.mkdirs(); // 하위 디렉토리를 계속해서 만듭니다.
System.out.println(directoryName + "을 만들었습니다.");
}
if (f.isDirectory()) {
System.out.println(directoryName + "의 내용을 표시합니다.");
// f 디렉토리 아래에 이름이 ".class"로 끝나는 파일의 목록만 구합니다.
String[] fileNames = f.list(new FilenameFilter() {
public boolean accept(File d, String name) {
if (name.indexOf(".class") != -1)
return true;
else
return false;
}
});
for(int i = 0; i < fileNames.length; i++) {
System.out.println(fileNames[i]);
}
}
else {
System.out.println(directoryName + "은 디렉토리가 아닙니다.");
}
}
}
예제 6 - 2 DirectoryDemo.java
예제 6 - 2 DirectoryDemo 클래스에서는 입력으로 받은 파일이 디렉토리라면 디렉토리
아래의 있는 파일의 이름에 “.class”이 포함되어 있는 파일만 보여주고 있습니다.
mkdir() 메소드를 이용해서 하나의 디렉토리를 만들수 있고, mkdirs() 메소드를 이용해서
한꺼번에 여러 깊이의 하위 디렉토리를 만들 수 있습니다.
예제 6 - 2에서 디렉토리의 내용을 볼 때 DirectoryDemo는 “.class”가 포함되어 있는
파일이름만 표시하라고 했는데 이를 필터링이라고 합니다.
File클래스의 list() 메소드는 FileNameFilter라는 인터페이스등을 인자로 받을 수 있는데
list()메소드가 이런 필터를 인자로 받게 되면 필터를 참으로하는 조건의 내용만
보여주게 됩니다. 즉, FileNameFilter에서 accept되는 내용만 보여주게 되지요.
예제 6 -2 DirectoryDemo에서 사용한 FileNameFilter클래스는 Anonymous Inner 클래스
라고 부릅니다. 클래스의 이름이 없고, 클래스 내부에서 정의된 클래스이기 때문에 그렇게
불립니다. Anonymous Inner 클래스는 프로그램에서 단 한번만 사용하고자 할 때
유용합니다. 간편하게 만들수 있고, 클래스 이름을 지어야 하는 그 골치아픈 일에서 벗어
날수 있기 때문입니다.
그림 6 - 2 [ run DirectoryDemo ]
'자바 Basic > 입출력(I/O)' 카테고리의 다른 글
자바공부-7.메모리에서 읽고쓰기 (0) | 2007.12.11 |
---|---|
자바공부-6.기다리는 읽기와 기다리지않는 읽기 (0) | 2007.12.11 |
자바공부-5.캐릭터 스트림(Reader/Writer) (1) | 2007.12.07 |
자바공부-3.바이트 스트림(ByteStream) (1) | 2007.12.07 |
자바공부-2.입출력에 관한 자바의 관점 (0) | 2007.12.07 |