자바 프로그램에서 외부의 파일을 접근하는 방법은 다음의 과정을 거친다.
먼저 외부 파일을 참조하는 참조 객체(대리자, 위임자)를 생성한다. 그리고 참조하는 객체를 조작한다. 그 행동의 결과가 외부 파일이 적용되는 작동 방식이다.
본문에서 다룰 텍스트 파일 또한 자바 프로그램의 외부 파일이다. 텍스트 파일을 바로 자바로 가져오려고 하면 난이도가 많이 올라가고 코드도 복잡해진다. 그래서 자바와 외부 파일을 이어주는 중개인을 만들고 시작하는 방식으로 작성하였다.
여기서 사용하는 파일 참조 클래스는 java.io.File에 속한 클래스이다.
💡File 조작
파일 데이터 확인
File file = new File("C:\\Class\\code\\java\\file\\data.txt");
System.out.println(file.exists());
if(file.exists()) {
System.out.println("파일이 있습니다.");
// 업무
System.out.println(file.getName()); // data.txt
System.out.println(file.isFile()); // true
System.out.println(file.isDirectory()); // false
System.out.println(file.length()); // 32
System.out.println(file.getAbsolutePath()); // C:\Class\code\java\file\data.txt
System.out.println(file.lastModified()); // 1691379563506
System.out.println(file.isHidden()); // false
// tick > 년월일시분초
Calendar c1 = Calendar.getInstance();
System.out.println(c1.getTimeInMillis());
c1.setTimeInMillis(file.lastModified());
System.out.printf("%tF %tT\n", c1, c1); // 2023-08-07 12:39:23
} else {
System.out.println("파일이 없습니다.");
}
- getName: 파일의 이름 반환
- isFile: 이게 파일인지, 폴더인지를 나타냄. 파일일 경우 true, 아닐 경우 false 반환
- isDirectory: 이게 폴더인지, 파일인지를 나타냄. 폴더일 경우 true, 아닐 경우 false 반환
- length: 파일의 크기 (byte)
- getAbsolutePath: 파일의 경로
- lastModified: 수정한 날짜
- isHidden: 이 파일이 숨김파일인지, 아닌지를 나타냄. 숨긴 파일일 경우 true, 아닐 경우 false 반환
파일 생성하기
File file = new File("C:\\Class\\code\\java\\file\\hello.txt");
if (!file.exists()) {
// Unhandled exception type IOException
try {
System.out.println(file.createNewFile());
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println("이미 동일한 파일이 존재합니다.");
}
파일을 생성할 때, 확장자를 txt가 아닌 png, mp4를 지정해도 파일 자체는 만들어지긴 하지만, 비어있는 파일이 만들어지는 것이므로 의미가 없다.
!file.exists() 메소드로 파일이 있는지를 물어보고, 파일이 없을 경우 지정한 폴더에 파일을 생성한다. 그리고 파일이 있는 경우 "이미 동일한 파일이 존재합니다." 메시지를 출력한다.
이때 trycatch문으로 묶은 이유는 Unhandled exception type IOException 오류가 발생하기 때문이다.
파일명 바꾸기
File file = new File("C:\\Class\\code\\java\\file\\data.txt");
File file2 = new File("C:\\Class\\code\\java\\file\\데이터.txt");
if (file.exists()) {
System.out.println(file.renameTo(file2));
}
파일명을 바꿀 때에는 renameTo() 메소드를 사용한다.
file은 수정하기 전, file2는 수정한 후의 주소로, txt 파일의 이름을 'data'에서 '데이터'로 바꾸는 소스코드이다.
만약 폴더 내에 동일한 이름의 파일이 2개 있을 경우 false를 반환하고 이름이 바뀌지 않는다.
파일 이동하기
File file = new File("C:\\Class\\code\\java\\file\\data.txt");
File file2 = new File("C:\\Class\\code\\java\\move\\data.txt");
if (file.exists()) {
System.out.println(file.renameTo(file2));
}
앞서 파일명을 바꿀 때 renameTo() 메소드를 사용했다. 그런데 파일을 이동할 때에도 renameTo() 메소드를 사용한다.
이처럼 renameTo() 메소드는 경로와 이름을 한꺼번에 바꿀 수 있는 메소드이다.
파일 삭제하기
File file = new File("C:\\Class\\code\\java\\file\\data.txt");
if (file.exists()) {
System.out.println(file.delete());
}
파일을 삭제할 때에는 delete() 메소드를 사용하며, 삭제한 파일은 휴지통으로 가지 않으니 주의한다.
💡Directory 조작
폴더 데이터 확인
File dir = new File("C:\\Class\\code\\java\\file");
if (dir.exists()) {
System.out.println("폴더가 있습니다.");
// 업무
System.out.println(dir.getName()); // file
System.out.println(dir.isFile()); // false
System.out.println(dir.isDirectory()); // true
System.out.println(dir.length()); // 0 <- 폴더 본연의 크기를 나타내므로 항상 0이 나온다.
System.out.println(dir.getAbsolutePath()); // C:\Class\code\java\file
System.out.println(dir.lastModified()); // 1691379524913
System.out.println(dir.isHidden()); // false
} else {
System.out.println("폴더가 없습니다.");
}
- getName: 폴더의 이름 반환
- isFile: 이게 파일인지, 폴더인지를 나타냄. 파일일 경우 true, 아닐 경우 false 반환
- isDirectory: 이게 폴더인지, 파일인지를 나타냄. 폴더일 경우 true, 아닐 경우 false 반환
- length: 폴더의 크기 (byte)
- getAbsolutePath: 폴더의 경로
- lastModified: 수정한 날짜
- isHidden: 이 폴더가 숨김파일인지, 아닌지를 나타냄. 숨긴 폴더일 경우 true, 아닐 경우 false 반환
폴더는 물리적인 공간의 개념으로 존재하는 게 아니다.
폴더는 자신만의 데이터를 가지고 있지 않고, 식별자인 이름만 가지고 있으므로 크기가 존재하지 않는다.
폴더의 크기(length)가 항상 0으로 나오는 이유가 바로 이 때문이다.
폴더 만들기
File dir = new File("C:\\Class\\code\\java\\bbb\\ccc");
if (!dir.exists()) {
System.out.println(dir.mkdir());
System.out.println(dir.mkdirs());
}
mkdir() 메소드는 폴더를 1개만 만들고, mkdirs() 메소드는 연관된 폴더를 모두 만든다.
만약 mkdir() 메소드를 사용했는데 폴더를 2개 이상 만들려고 할 경우 false를 반환한다. mkdir() 메소드를 사용하려면 최종 대상을 만들 때 앞에 실존해야 한다.
폴더 만들기 소스코드
회원 폴더 내에 회원명으로 개인 폴더 생성
String[] member = {"홍길동", "아무개", "이순신", "권율", "유관순"};
for (int i = 0; i < member.length; i++) {
String path = String.format("C:\\class\\code\\java\\file\\회원\\[개인폴더]%s님", member[i]);
File dir = new File(path);
System.out.println(dir.mkdirs());
}
날짜별 폴더 생성 (2023-01-01 ~ 2023-12-31)
Calendar c = Calendar.getInstance();
c.set(2023, 0, 1);
System.out.println(c.getActualMaximum(Calendar.MONTH)); // 11
System.out.println(c.getActualMinimum(Calendar.MONTH)); // 0
System.out.println(c.getActualMaximum(Calendar.DATE)); // 31 (2023년 1월달 최대 날짜)
int max = c.getActualMaximum(Calendar.DAY_OF_YEAR);
for (int i = 0; i < max; i++) {
// "2023-01-01"
String name = String.format("%tF", c);
// System.out.println(name);
File dir = new File("C:\\Class\\code\\java\\file\\날짜\\" + name);
dir.mkdirs();
c.add(Calendar.DATE, 1);
}
폴더명 바꾸기
File dir = new File("C:\\Class\\code\\java\\file\\날짜");
File dir2 = new File("C:\\Class\\code\\java\\file\\할일");
if (dir.exists()) {
System.out.println(dir.renameTo(dir2));
}
폴더 이동하기
File dir = new File("C:\\Class\\code\\java\\file\\할일");
File dir2 = new File("C:\\Class\\code\\java\\move\\할일");
if (dir.exists()) {
System.out.println(dir.renameTo(dir2));
}
폴더 삭제하기
File dir = new File("C:\\class\\code\\java\\aaa");
if (dir.exists()) {
System.out.println(dir.delete());
}
폴더를 삭제할 때에는 빈 폴더일 때에만 가능하다.
폴더 내에 내용물(파일, 자식 폴더)이 하나라도 있을 경우 삭제가 불가능하다.
폴더의 내용 보기
String path = "C:\\eclipse";
File dir = new File(path);
if (dir.exists()) {
// list() 메소드
dir.list();
// listFiles() 메소드
dir.listFiles();
String[] list = dir.list();
for (String f : list) {
// 파일명, 폴더명
System.out.println(f);
File file = new File(path + "\\" + f);
System.out.println(f + " > " + (file.isFile() ? "파일" : "폴더"));
}
}
dir.listFiles();
File[] list = dir.listFiles();
for (File f : list) {
System.out.printf("%s - %s\n"
, f.getName()
, f.isDirectory());
}
// 탐색기 느낌
File[] list = dir.listFiles();
for (File d : list) {
if (d.isDirectory()) {
System.out.printf("[%s]\n", d.getName());
}
}
for (File f :list) {
if(f.isFile()) {
System.out.println(f.getName());
}
}
list() 메소드는 해당 폴더가 가지고 있는 자료를 문자열로 가져온다.
listFiles() 메소드는 디렉토리를 조작할 때 가장 많이 사용하는 메소드이니 잘 알아두도록 한다.
💡특정 폴더의 File/Directory 개수 세기
// 누적 변수
private static int count = 0; // 파일 개수
private static int dcount = 0; // 폴더 개수
private static long length = 0; // 폴더 크기
private static void eclipseCount() {
File dir = new File("C:\\eclipse");
if (dir.exists()) {
countFile(dir);
System.out.printf("총 파일 개수: %,d개\n", count); // 총 파일 개수: 12,020개
System.out.printf("총 폴더 개수: %,d개\n", dcount); // 총 폴더 개수: 2,632개
System.out.printf("폴더 크기: %,dbyte\n", length); // 폴더 크기: 756,135,133byte
}
}
private static void countFile(File dir) {
// 1. 목록 가져오기
File[] list = dir.listFiles();
// 2. 파일 개수
for (File subfile : list) {
if (subfile.isFile()) {
count++; // 파일 카운트
length += subfile.length(); // 파일 크기를 누적
}
}
// 3. 자식 폴더를 대상으로 1~2번을 반복
for (File subdir : list) {
if (subdir.isDirectory()) {
dcount++; // 폴더 카운트
// 1~2번 실행 > 3번 > 손자 폴더
countFile(subdir); // 자식 폴더 > 반복
}
}
}