반응형
File I/O Handling
- JAVA에서 파일을 읽고 쓰는 작업을 수행하는 방법
- 데이터의 영속성(시스템이 종료되거나 프로그램이 종료된 후에도 데이터를 유지하는 것) 제공
- 다양한 형식의 데이터를 다룰 수 있도록 함
기본 개념
- 입력(읽기) : 파일의 내용을 프로그램으로 가져오는 작업
- 출력(쓰기) : 프로그램에서 데이터를 파일에 저장하는 작업
java.io.File Class
- 파일이나 디렉토리를 나타내는 객체 생성(파일 및 디렉토리 경로를 추상적으로 표현하는 클래스)
- 파일의 속성(읽기, 쓰기 권한 등)을 확인하거나 파일을 생성, 삭제 할 수 있음
package day2;
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FileCheckExample {
private static final Logger logger = LoggerFactory.getLogger(FileCheckExample.class);
public static void main(String[] args) {
File file = new File("example.txt"); // 경로에 해당하는 파일 객체 생성. 실제 파일 생성이 아님
if (file.exists()) {
logger.info("파일이 존재함");
} else {
logger.info("파일이 존재하지 않음");
}
}
}
- 절대 경로 : 파일을 찾기 위해 추가 정보가 필요 없는 완전한 경로
- UNIX 플랫폼 : 접두사 "/"
- Windows 플랫폼 : "\"
- 상대 경로 : 다른 경로에 대한 정보가 필요
- 부모 경로 : getParent() 메소드를 사용하여 추상 경로의 부모를 얻을 수 있음
- 파일 시스템 객체 : file클래스의 인스턴스는 실제 파일 시스템 객체(파일 또는 디렉토리)를 나타낼 수도 있고, 아닐 수도 있음(경로를 지정할 수 있지만, 그 경로가 실제로 존재하는지의 여부는 별개의 문제임)
- exists() 메소드로 파일이 존재하는지 확인할 수 있음
- 접근 권한 : 읽기, 쓰기, 실행 등의 작업에 대한 제한. 파일에 대한 접근 권한은 객체의 소유자와 다른 사용자에게 다를 수 있음
- 불변성 : file 클래스의 인스턴스는 불변. 한 번 생성된 후에는 경로가 변경되지 않음(경로는 객체가 생성되는 순간에 정해지며, 경로를 변경하고 싶다면 새로운 file 객체를 생성해야 함)
FileReader
public class FileReader
extends InputStreamReader
implements Closeable, AutoCloseable, Readable
- 문자 파일을 읽기 위한 클래스
- 주로 텍스트 파일을 읽을 때 사용됨
- 문자열 데이터를 처리하는 데 유용함
- FileReader의 생성자는 기본 문자 인코딩과 기본 바이트 버퍼 크기 사용 -> 별도로 지정하지 않아도 기본값으로 파일을 읽을 수 있음
- FileReader는 문자 스트림을 읽기 위해 설계되었으므로 원시 바이트 스트림을 읽으려면 FileInputStream을 사용하는 것이 적합
package day3;
import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import day2.LoggerExample;
public class FileReaderExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
try(FileReader fr = new FileReader("src/main/resources/example.txt");
BufferedReader br = new BufferedReader(fr)){
String line;
while((line = br.readLine())!=null) {
logger.info(line);
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
FileWriter
public class FileWriter
extends OutputStreamWriter
implements Closeable, Flushable, Appendable, AutoCloseable
- 문자 파일을 작성하기 위한 클래스
- 문자 스트림을 통해 데이터를 파일에 쓸 수 있도록 설계
- FileWriter의 생성자는 기본 문자 인코딩과 기본 바이트 버퍼 크기를 가정(별도로 지정하지 않으면 시스템의 기본 설정 사용)
- 일부 플랫폼에서는 동시에 하나의 FileWriter만 파일에 쓸 수 있도록 제한(이미 열려 있는 파일에 대해 FileWriter를 생성하려고 하면 예외 발생)
package day3;
import java.io.FileWriter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import day2.LoggerExample;
public class FileWriterExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
try (FileWriter fw = new FileWriter("src/main/resources/example.txt")) {
fw.write("파일 수정");
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedReader
public class BufferedReader
extends Reader
implements Closeable, AutoCloseable, Readable
- 문자 입력 스트림에서 텍스트 읽기 : 문자를 버퍼링하여 효율적으로 읽을 수 있음
- 버퍼 크기 : 버퍼의 크기를 사용자가 지정할 수 있음. 하지만 기본 크기도 충분히 큼
- read() 메소드를 호출할 때마다 실제로 파일이나 스트림에서 데이터를 읽어야 함
- BufferedReader를 사용하여 FileReader나 InputStreamReader와 같은 Reader를 wrapping하는 것이 좋음
- wrapping : 어떤 객체를 다른 객체로 감싸는 것(원래 객체의 기능을 확장하거나 추가적인 기능 제공)
- 기본적으로 다른 Reader의 기능을 감싸고 그 위에 버퍼링 기능을 추가하여 효율성 향상
- BufferedReader를 사용하지 않으면 매번 read(), readLine()을 호출할 때마다 파일에서 바이트를 읽고, 이를 문자로 변환하여 반환해야 하는데 이는 매우 비효율적임
- 텍스트 입력을 더 효율적으로 처리하기 위해 DataInputStream 대신 BufferedReader를 사용할 수 있음
package day3;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import day2.LoggerExample;
public class BufferedReaderExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("src/main/resources/example.txt"))) {
String line;
while ((line = br.readLine()) != null) {
logger.info(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedWriter
public class BufferedWriter
extends Writer
implements Closeable, Flushable, Appendable, AutoCloseable
- 문자 출력 스트림에 텍스트를 쓰기 위한 클래스
- 문자를 버퍼링하여 효율적으로 단일 문자, 배열, 문자열을 쓸 수 있도록 도와줌
- 버퍼 크기 : 버퍼의 크기를 사용자가 지정할 수 있음. 하지만 기본 크기도 충분히 큼
- newLine() 메소드를 제공함(line.separator에 의해 정의된 줄 구분자)
- 모든 플랫폼이 줄 끝을 나타내는 데 같은 문자를 사용하지 않기 때문에 직접 줄 바꿈 문자를 쓰기보다 newLine() 메소드를 사용하는 것이 좋음
- 출력 내용을 즉시 기본 문자 또는 바이트 스트림으로 전송
- 출력이 필요하지 않은 경우, BufferedWriter로 감싸는 것이 좋음
- FileWriter와 같이 비용이 많이 드는 write() 작업을 수행하는 Writer를 사용할 때 BufferedWriter로 래핑하면 성능이 향상됨
- 출력이 필요하지 않은 경우, BufferedWriter로 감싸는 것이 좋음
package day3;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import day2.LoggerExample;
public class BufferedWriterExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("src/main/resources/example.txt"))) {
bw.write("또 다시 파일 수정");
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileInputStream
public class FileInputStream
extends InpuutStream
implements Closeable, AutoCloseable
- 파일 시스템에서 파일로부터 입력 바이트를 읽어 오는 클래스
- 원시 바이트 스트림을 읽는 데 사용(바이트 단위로 데이터를 읽기 때문)
- 어떤 파일에 접근할 수 있는지는 호스트 환경에 따라 다름
package day3;
import java.io.FileInputStream;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import day2.LoggerExample;
public class FileInputStreamExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("src/main/resources/example.txt")) {
int data; //read() 메소드가 int타입의 값을 반환
while ((data = fis.read()) != -1) { //파일의 끝에 도달하면 -1 반환
char character = (char) data; //바이트를 문자로 변환
logger.info(String.valueOf(character)); //문자를 문자열로 변환
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream
public class FileOutputStream
extends OutputStream
implements Closeable, Flushable, AutoCloseable
- 데이터를 파일 또는 FileDescriptor에 쓰기 위한 출력 스트림
- 파일에 바이트 데이터를 직접 쓸 수 있음
- 주로 이미지, 오디오 파일 등 이진 데이터에 사용됨
- 어떤 운영체제에서는 파일을 동시에 여러 개의 FileOutputStream 객체로 열 수 없음(이미 열려 있는 파일에 대해 FileOutputStream을 생성하려고 하면 오류 발생)
- 원시 바이트 스트림을 쓰는 데 적합
package day3;
import java.io.FileOutputStream;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import day2.LoggerExample;
public class FileOutputStreamExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
String data = "문자열";
byte[] byteArray = data.getBytes(); // 문자열을 바이트 배열로 반환
try (FileOutputStream fos = new FileOutputStream("src/main/resources/example.txt")) {
fos.write(byteArray); // 바이트 배열을 파일에 씀
} catch (IOException e) {
e.printStackTrace();
}
}
}
java.nio.file 패키지
- NIO(New Input/Output) API이며, JAVA 7에서 도입됨
- 파일 I/O를 더 효율적이고 직관적으로 처리할 수 있도록 도와줌
- 파일 입출력, 파일 시스템 탐색 및 파일 속성 관리와 같은 다양한 기능 제공
- Paths, Files 등의 클래스를 사용하여 파일을 쉽게 읽고 쓸 수 있음
- java.nio.file.attribute 패키지에서는 파일 속성에 대한 API를 정의
- 파일 및 파일 시스템 접근 : 파일의 생성, 삭제, 복사, 이동, 속성 조회 등의 작업 수행
- 심볼릭 링크 : 다른 파일을 참조하는 특수 파일
- 상호 운용성 : toPath 메소드를 통해 java.io.File 객체로 표현된 추상 경로를 Path 객체로 변환할 수 있음(생성된 Path는 동일한 파일에 대해 File 객체와 함께 사용할 수 있음)
- 가시성 : 패키지의 클래스들이 제공하는 파일 및 파일 시스템 뷰는 같은 JAVA 가상 머신 내의 다른 인스턴스와 일관성을 보장
- 동기화 I/O 파일 무결성 : SYNC / DSYNC 옵션을 통해 파일을 열 때 업데이트가 기본 저장 장치에 동기적으로 기록되도록 요구
- 일반 예외 : 생성자 또는 메서드에 null 인수를 전달하면 NullPointerException 발생. 닫힌 파일 시스템과 관련된 객체에서 파일 시스템 접근을 시도하면 ClosedFileSystemException 발생
- 선택적 특정 예외 : 일반적으로 IOException을 던짐
package day3;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import day2.LoggerExample;
public class NIOExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
Path path = Paths.get("src/main/resources/example.txt"); // 파일 경로를 정의하여 파일 객체 생성
// 파일 쓰기
try {
String data = "파일에 작성할 데이터";
Files.write(path, data.getBytes()); // 바이트 배열로 변환하여 파일에 작성
logger.info("파일에 데이터가 성공적으로 작성됨 : {}", path);
} catch (IOException e) {
e.printStackTrace();
}
// 파일 읽기
try {
String content = Files.readString(path);
logger.info("파일 내용 : {}", content);
} catch (IOException e) {
e.printStackTrace();
}
// 디렉토리 탐색
FileSystem fs = FileSystems.getDefault(); // 기본 파일 시스템
try {
// 지정된 디렉토리에서 파일 트리 탐색 시작
Files.walkFileTree(fs.getPath("src/main/resources"), new SimpleFileVisitor<Path>() {
//walkFileTree : 주어진 경로를 시작으로 파일 시스템의 트리를 탐색하는 메소드
//fs.getPath : 탐색할 시작 경로, SimpleFileVisitor<Path>는 파일 방문자 객체
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
logger.info("파일 : {}", file.toString()); // 방문한 파일 로그 출력
return FileVisitResult.CONTINUE; // 탐색을 계속 함
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
logger.info("디렉토리 : {}", dir.toString()); // 방문한 디렉토리 로그 출력
return FileVisitResult.CONTINUE; // 탐색 계속
}
});
} catch (IOException e) {
logger.error("디렉토리 탐색 중 오류 발생 : {}", e.getMessage());
}
}
}
walkFileTree
public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)
//Path 타입과 Object 타입 모두를 받을 수 있음
//FileVisitor는 Path와 그 부모 타입만 받을 수 있는 것 -> FileVisitor를 구현할 때 사용할 수 있는 타입이 Path이거나 부모타입 이어야 한다는 것
throws IOException
{
return walkFileTree(start,
EnumSet.noneOf(FileVisitOption.class),
Integer.MAX_VALUE,
visitor);
}
예외 처리
- 파일 입출력 작업은 다양한 이유로 실패할 수 있으므로 항상 예외 처리를 해야 함IOException
- 일반적인 I/O 오류를 나타내는 예외
- 파일 읽기, 쓰기, 파일 시스템 접근 등에서 문제가 발생할 때 발생
- 파일이 존재하지 않거나 접근 권한이 없을 때 발생
FileNotFoundException
- 지정된 파일을 찾을 수 없을 때 발생(경로가 잘못 지정되었거나 파일이 삭제된 경우)
- FileReader, FileInputStream 등을 사용할 때 주로 발생
EOFException
- 파일의 끝(EOF)에 도달했을 때 발생하는 예외
- 주로 DataInputStream에서 데이터를 읽을 때 발생
- 읽을 데이터가 없는데 계속해서 읽으려고 할 때 발생
SecurityException
- 보안 관리자에 의해 파일에 대한 접근이 거부될 때 발생하는 예외
- 특정 파일에 대한 읽기/쓰기 권한이 없는 경우 발생
try-catch
- try 블록 내에서 파일을 읽는 작업을 수행
- catch 블록에서 발생할 수 있는 예외를 처리
try-catch-finally
- 자원 해제 작업에 유용
try-with-resources
- JAVA 7 이상에서 자원을 자동으로 해제할 수 있음
- finally 블록을 따로 작성하지 않아도 됨
- with : 자원을 사용하는 컨텍스트를 나타내는 단어. try 블록 내에서 특정 자원을 사용하겠다는 의미
- resources : 프로그램에서 사용하는 자원을 의미. 자원은 파일, 네트워크 연결, 데이터베이스 연결 등과 같이 사용 후 반드시 해제해야 하는 것들
- try-with-resources문에서는 AutoCloseable 인터페이스를 구현한 객체들만 자동으로 사용할 수 있음
AutoCloseable 인터페이스를 구현하는 클래스
- FileInputStream
- FIleOutputStrema
- FileReader
- FileWriter
- BufferedReader
- BufferedWriter
ByteArrayInputStream
- 바이트배열에 데이터를 입출력하는데 사용되는 스트림(메모리)
- 주로 다른 곳에 입출력하기 전 데이터를 임시로 바이트 배열에 담아 변환하는 작업에 사용됨
- 바이트 배열을 차례대로 읽어 들이기 위한 클래스
- 생성자에 바이트 배열을 전달하면 해당 배열의 내용을 읽을 수 있음
- 스트림이 닫히면 더 이상 데이터를 읽을 수 없음
ByteArrayOutputStream
- 바이트 배열에 데이터를 출력할 수 있게 해줌
- 데이터를 쓰면 자동으로 내부 버퍼에 저장되며, 필요할 때 바이트 배열로 변환할 수 있음
- 스트림이 닫힐 필요 없이 언제든지 데이터를 읽을 수 있음
반응형
'첫 개발 경력, 바른개발연구소 > OJT' 카테고리의 다른 글
Variable (1) | 2025.01.21 |
---|---|
LGEricsson JAVA Standard (3) | 2025.01.20 |
Windows-based Development Environment Settings (1) | 2025.01.20 |