5. 파일입출력(I/O)
📌 InputStream / OutputStream
자바에서 제공하는 입출력 스트림으로, 입력과 출력을 동시에 처리하기 위한 스트림이다.
입출력 스트림은 어떤 대상을 다루느냐에 따라 종류가 나뉜다. 예를 들면, File을 다룰 때에는 FileInputStream / FileOutputStream을 사용하고, 프로세스를 다룰 때는 PipedInputStream / PipedOutputStream을 사용한다.
※ Stream이란?
개별 바이트나 문자열인 데이터의 원천
파일을 읽거나 쓸 때, 네트워크 소켓을 거쳐 통신할 때 쓰이는 추상적인 개념
✔️ InputStream 메서드 종류
메서드명 | 리턴 타입 | 기능 |
available() | int | 현재 읽을 수 있는 바이트의 수를 반환한다. |
close() | void | 입력 스트림을 닫는다. |
mark(int readlimit) | void | 입력 스트림에서 현재의 위치를 표시해준다. |
markSupported() | boolean | 해당 입력 스트림에서 mark()로 지정된 지점이 있는지에 대한 여부를 확인한다. |
read() | abstract int | 입력스트림에서 1Byte를 읽어 int 값으로 반환(실제로 읽어들인 값을 반환)하며 더이상 읽어드릴 값이 없을 경우 -1을 반환한다. |
read(byte[] b) | int | 입력 스트림에서 buf[] 크기만큼 읽어 buf에 저장하고, 읽은 바이트 수를 반환한다. |
read(byte[] b, int off, int len) | int | b[off]에서 len개까지의 데이터를 읽고 읽은 바이트 수를 반환한다. |
reset() | void | mark()를 마지막으로 호출한 위치로 이동한다. |
skip(long n) | long | 입력 스트림에서 지정된 바이트만큼 무시하고, 무시된 바이트 수를 반환한다. |
✔️ OutputStream 메서드 종류
메서드명 | 리턴 타입 | 기능 |
close() | void | 출력 스트림을 닫는다. |
flush() | void | 버퍼에 남아있는 데이터를 모두 출력시키고 버퍼를 비우는 역할을 한다. |
write(byte[] b) | void | 바이트 배열을 출력 스트림에 넣는다. |
write(byte[] b, int off, int len) | void | b[off]에서 len개까지의 바이트 배열의 바이트를 출력 스트림에 넣는다. |
write(int b) | abstract void | 매개변수로 주어진 int 값에서 끝에 있는 1Byte만을 출력 스트림으로 보낸다. |
✔️ FileInputStream
자바에서 많이 사용되는 FileInputStream은 대표적인 바이트 기반 스트림으로, 다음과 같이 스트림을 생성할 수 있다.
FileInputStream 변수명 = new FileInputStream(파일경로);
파일을 읽어오는 기본 구조는 아래 예제 코드와 같다.
import java.io.FileInputStream;
public class FileInputStreamExample {
public static void main(String args[])
{
try {
// 입력 : 파일 경로
FileInputStream fileInput = new FileInputStream("hi.txt");
int i = 0;
//fileInput.read()의 리턴값을 i에 저장한 후, 값이 -1인지 확인한다.
while ((i = fileInput.read()) != -1) {
System.out.print((char)i);
}
fileInput.close();
}
catch (Exception e) {
System.out.println(e);
}
}
}
❗️BufferedInputStream
성능 향상을 위한 보조 스트림
성능이 향상되기 때문에 파일을 불러올 때 같이 많이 사용된다. 여기서 BufferedInputStream은 바이트 배열로서, 여러 바이트를 저장하여 한번에 많은 양의 데이터를 입출력 할 수 있도록 도와주는 임시 저장 공간 역할을 한다.
import java.io.FileInputStream;
import java.io.BufferedInputStream;
public class FileInputStreamExample {
public static void main(String args[])
{
try {
FileInputStream fileInput = new FileInputStream("hi.txt");
BufferedInputStream bufferedInput = new BufferedInputStream(fileInput);
int i = 0;
while ((i = bufferedInput.read()) != -1) {
System.out.print((char)i);
}
fileInput.close();
}
catch (Exception e) {
System.out.println(e);
}
}
}
✔️ FileOutputStream
자바에서 많이 사용되는 FileOutputStream은 대표적인 바이트 기반 스트림으로, 다음과 같이 스트림을 생성할 수 있다.
FileOutputStream fileOutput = new FileOutputStream(파일 경로);
import java.io.FileOutputStream;
public class FileOutputStreamExample {
public static void main(String args[]) {
try {
FileOutputStream fileOutput = new FileOutputStream("hi.txt");
String word = "code";
byte b[] = word.getBytes();
fileOutput.write(b);
fileOutput.close();
}
catch (Exception e) {
System.out.println(e);
}
}
}
위 코드를 실행하면, 같은 디렉토리 내에 code라는 문자열이 입력된 hi.txt 파일이 생성됨을 확인할 수 있다.
📌 FileReader / FileWriter
자바에서 제공하는 대표적인 문자 기반 스트림
앞서 살펴본 File 입출력 스트림은, 바이트 기반 스트림이다. 바이트 기반은 입출력 단위가 1byte라는 뜻이다. 하지만 Java에서 char 타입은 2byte(자바 기본 유닛 참고)이다. 이 두 차이를 해소하기 위해 자바에서는 문자 기반 스트림을 제공한다. 문자 기반 스트림에는 FileReader와 FileWriter가 있다.
FileReader는 인코딩을 유니코드로 변환하고, FileWriter는 유니코드를 인코딩으로 변환한다.
✔️ FileReader
public class FileReaderExample {
public static void main(String args[]) {
try {
String fileName = "hi.txt";
FileReader file = new FileReader(fileName);
int data = 0;
while((data=file.read()) != -1) {
System.out.print((char)data);
}
file.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
hi.txt에 한글을 입력하고 저장한 뒤 FileReader를 통해 값을 읽어올 수 있다. 또한 InputStream과 동일한 메서드를 사용할 수 있다.
❗️BufferedReader
성능 향상을 위한 보조 리더 버퍼
바이트 기반 스트림과 마찬가지로 Reader에도 성능을 개선할 수 있는 BufferedReader가 있다.
FileReader file = new FileReader(fileName);
BufferedReader buffered = new BufferedReader(file);
✔️ FileWriter
public class FileWriterExample {
public static void main(String args[]) {
try {
String fileName = "hi.txt";
FileWriter writer = new FileWriter(fileName);
String str = "written!";
writer.write(str);
writer.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
앞서 만든 hi.txt 파일에 “written!”이라는 문자열을 입력하는 예제이다. OutputStream과 동일한 메서드를 사용할 수 있다.
📌 File
자바에서 파일과 디렉토리에 접근하고 제어하기 위해 사용하는 클래스
✔️ File의 생성자
생성자 | 설명 |
File(String pathname) | 입력한 pathname(파일명 포함) 경로 파일의 객체를 생성한다. |
File(String parent, String child) | parent 디렉토리 경로의 child 파일에 대한 객체를 생성한다. |
File(File parent, String child) | 파일 객체 parent의 child 파일에 대한 객체를 생성한다. |
File(URI uri) | uri 경로에 대한 파일 객체를 생성한다. |
✔️ File의 메서드
메소드 | 설명 |
File getAbsoluteFile() | 파일의 절대 경로를 반환한다. |
String getAbsolutePath() | 파일의 절대 경로를 문자열로 반환한다. |
File getCanonicalFile() | 파일의 정규 경로를 반환한다. |
String getCanonicalPath() | 파일의 정규 경로를 문자열로 반환한다. |
String getName() | 파일이나 폴더의 이름을 넘겨준다. |
String getParent() | 부모 경로에 대한 경로명을 문자열로 반환한다. |
File getParentFile() | 부모 폴더를 File의 형태로 반환한다. |
String getPath() | 파일의 경로를 문자열의 형태로 반환한다. |
long getTotalSpace() | 하드디스크의 총 용량을 반환한다. |
long getUsableSpace() | 하드디스크의 사용 가능한 용량을 반환한다. |
long getFreeSpace() | 하드디스크의 남은 공간을 반환한다. |
int hashCode() | hash code를 반환한다. |
long lastModified() | 해당 경로 파일의 최종 수정 일자를 반환한다. |
long length() | 해당 경로 파일의 길이를 반환한다. |
Path toPath() | java.nio.file.Path 객체로 반환한다. |
URI toURI() | URI 형태로 파일 경로를 반환한다. |
File[] listRoots() | 하드디스크의 루트 경로를 반환한다. |
String[] list() | 경로의 파일들과 폴더를 문자열 배열로 반환한다. |
String[] list(FilenameFilter filter) | filter에 만족되는 파일들과 폴더 이름을 문자열 배열로 반환한다. |
File[] listFiles() | 해당 경로의 파일들과 폴더의 파일을 배열로 반환한다. |
File[] listFiles(FileFilter filter) | filter에 만족되는 파일들과 폴더를 File 배열로 반환한다. |
File[] listFiles(FilenameFilter filter) | filter에 만족되는 파일들과 폴더를 File 배열로 반환한다. |
✔️ 파일 체크 관련 메서드
메소드 | 설명 |
boolean exists() | 파일의 존재 여부를 반환한다. |
boolean isAbsolute() | 해당 경로가 절대 경로인지 여부를 반환한다. |
boolean isDirectory() | 해당 경로가 디렉토리인지 여부를 반환한다. |
boolean isFile() | 해당 경로가 file 인지 여부를 반환한다. |
boolean isHidden() | 해당 경로가 숨김 파일인지 여부를 반환한다. |
✔️ 파일 권한 관련 메서드
메소드 | 설명 |
boolean canExecute() | 파일 실행 권한이 있는지 여부를 반환한다. |
boolean canRead() | 파일을 읽기 권한이 있는지 여부를 반환한다. |
boolean canWrite() | 파일을 씨기 권한이 있는지 여부를 반환한다. |
boolean setExecutable(boolean executable) | 파일 소유자의 실행 권한을 설정한다. |
boolean setExecutable(boolean executable, boolean ownerOnly) | 파일의 실행 권한을 소유자 또는 모두에 대해 설정한다. |
boolean setReadable(boolean readable) | 파일의 소유자의 읽기 권한을 설정한다. |
boolean setReadable(boolean readable, boolean ownerOnly) | 파일의 읽기 권한을 소유자 또는 모두에 대해 설정한다. |
boolean setReadOnly() | 파일을 읽기 전용으로 변경한다. |
boolean setWritable(boolean writable) | 파일의 소유자의 쓰기 권한을 설정한다. |
boolean setWritable(boolean writable boolean ownerOnly) | 파일의 쓰기 권한을 소유자 또는 모두에 대해 설정한다. |
✔️ 예제
import java.io.*;
public class FileExample {
public static void main(String args[]) throws IOException {
File file = new File("../hi.txt");
System.out.println(file.getPath());
System.out.println(file.getParent());
System.out.println(file.getCanonicalPath());
System.out.println(file.canWrite());
}
}
파일 인스턴스를 생성하는 것이 곧 파일을 생성하는 것은 아니다. 파일을 생성하기 위해서는 파일 인스턴스를 생성할 때 다음과 같이 첫 번째 인자에 경로를, 두 번째 인자에 파일명을 작성하고, createNewFile()메서드를 호출해주어야 한다.
File file = new File("./", "newHi.txt");
file.createNewFile();
다음은 현재 디렉토리(.)에서 확장자가 .txt인 파일만을 대상으로, 파일명 앞에 “code”라는 문자열을 붙여주는 예제이다.
import java.io.File;
public class FileClassExample {
public static void main(String[] args) {
File parentDir = new File("./");
File[] list = parentDir.listFiles();
String prefix = "code";
for(int i =0; i <list.length; i++) {
String fileName = list[i].getName();
if(fileName.endsWith("txt") && !fileName.startsWith("code")) {
list[i].renameTo(new File(parentDir, prefix + fileName));
}
}
}
}