- 입출력을 다루기 위한 클래스
- 스트림은 단방향으로만 데이터를 전송할 수 있다
- 입력과 출력을 동시에 처리하기 위해서는 각각의 스트림이 필요하다!
- 입출력 스트림은 어떤 대상을 다루느냐에 따라 종류가 나뉘어진다
- Ex. File을 다룰 때는 FileInputStream / FileOutputStream을 사용한다
- Ex. process를 다룰 때는 PipedInputStream / PipedOutputStream을 사용한다
public class FileInputStreamExample {
public static void main(String[] args) {
try {
FileInputStream fileInputStream = new FileInputStream("파일 경로");
int idx = 0;
while((idx = fileInputStream.read()) != -1) {
System.out.print((char)idx);
}
fileInputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
- FileInputStream은 위와 같이 사용할 수 있다
- BufferedInputStream이라는 보조 스트림을 사용하면 성능이 향상되므로, 대부분의 경우 이를 사용한다
- 버퍼(Buffer)
- 바이트 배열
- 여러 바이트들을 저장하여 한 번에 많은 양의 데이터를 입출력할 수 있도록 도와주는 임시 저장 공간
public BufferedInputStreamExample {
public static void main(String[] args) {
try {
FileInputStream fileInputStream = new FileInputStream("파일 경로");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int idx = 0;
while((idx = bufferedInputStream.read()) != -1) {
System.out.print((char)idx);
}
fileInputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
- BufferedInputStream 보조 스트림도 FileInputStream과 같이 스트림의 하위 클래스이기 때문에 입출력 방법은 같다
FileOutputStream
public class FileOutputStreamExample {
public static void main(String[] args) {
try {
FileOutputStream fileOutputStream = new FileOutputStream("파일 경로");
String word = "Hello Java!";
byte[] bytes = word.getBytes();
fileOutputStream.write(bytes);
fileOutputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
- 위 코드를 통해 "Hello Java!"라는 문자열이 입력된 파일이 해당 경로에 생성된다
- 만약 해당 파일이 이미 존재한다면, 내용이 "Hello Java!"로 덮어씌워진다
FileReader / FileWriter
- File 입출력 스트림(FileInputStream / FileOutputStream)은 바이트 기반 스트림
- 그런데 자바에서 char 타입은 2 byte
- File 입출력 스트림에서 입출력하는 단위와 다르다
- 이를 해소하기 위해 문자 기반 스트림을 제공한다
- FileReader / FileWriter
- 문자 기반 스트림 -> 문자를 다룰 때 사용한다
- 문자 기반 스트림과 그 하위 클래스는 여러 종류의 인코딩과 자바에서 사용하는 유니코드 간의 변환을 자동으로 처리해준다
- 문자 기반 스트림에는 일반적으로 바이트 기반 스트림의 InputStream이 Reader로, OutputStream이 Writer로 대응된다
- FileInputStream이 문자 기반에서는 FileReader, FileOutputStream은 FileWriter에 해당하는 것과 같다
- 문자 기반 스트림 및 그 하위 클래스는 여러 종류의 인코딩과 자바에서 사용하는 유니코드 간의 변환을 자동으로 처리해주므로, FileReader는 인코딩을 유니코드로, FileWriter는 유니코드를 인코딩으로 변환해준다
FileReader
public class FileReaderExample {
public static void main(String[] args) {
String file = "파일 경로";
try {
FileReader fileReader = new FileReader(file);
int character = 0;
while((character = fileReader.read()) != -1) {
System.out.println((char)character);
}
fileReader.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
- 파일에 한글이 존재하더라도 자동으로 해당 인코딩을 유니코드로 변경해주기 때문에 잘 출력된다
- 성능을 개선할 수 있는 BufferedReader가 존재한다
public class BufferedReaderExample {
public static void main(String[] args) {
String file = "파일 경로";
try {
FileReader fileReader = new FileReader(file);BufferedReader bufferedReader = new BufferedReader(fileReader);
int character = 0;
while((character = bufferedReader.read()) != -1) {
System.out.println((char)character);
}
fileReader.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
FileWriter
public class FileWriterExample {
public static void main(String[] args) {
String file = "파일 경로";
try {
FileWriterExample fileWriter = new FileWriterExample(file);
String str = "Hello Java!";
fileWriter.write(str);
fileWriter.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
close() vs flush()
- close() : 스트림을 우선 플러쉬한 후에 스트림을 닫는다
- flush() : 스트림을 플러쉬한다
- 어차피 close()를 하면 플러쉬가 되는데 flush()를 왜 사용하는가?
- close()는 스트림을 닫는데, flush()는 스트림을 닫지 않는다
- 즉, 스트림을 닫지 않은 상태로 바이트를 보내고 싶은 경우에 flush()를 사용한다!
- Ex. 버퍼의 크기가 10000인데 버퍼 안에 10000만큼의 바이트가 존재한다
- 그런데 이후에 더 바이트가 들어온다면, 스트림을 닫아서는 안된다
- 이러한 경우에 flush()를 통해 버퍼링되어있는 바이트들을 쓰고 이후에 들어오는 바이트들을 버퍼에 넣는다
File
public class FileExample {
public static void main(String[] args) {
File file = new File("파일 경로");
System.out.println(file.getPath());
System.out.println(file.getParent());
System.out.println(file.getCanonicalPath());
System.out.println(file.canWrite());
}
}
- File의 path를 가져오는 API들
- getPath()
- File에 입력한 경로를 그대로 반환한다
- 만약 인자로 전달한 경로가 상대 경로라면 getPath()도 상대 경로를 반환한다
- getAbsolutePath()
- 현재 실행 중인 Working directory에 File에 전달한 경로를 조합하여 절대 경로를 반환한다
- getCanonicalPath()
- 절대 경로를 반환한다
- ./, ../와 같은 경로들을 정리하고 반환해준다
- Symbolic link 파일이라면 그것과 연결된 파일의 경로를 반환한다
File file = new File("../example/path/../path/file");
System.out.println(file.getAbsolutePath());
System.out.println(file.getCanonicalPath());
/home/IdeaProjects/example/../example/path/../path/file
/home/IdeaProjects/example/path/file
- File 인스턴스를 생성하는 것이 파일을 생성하는 것은 아니다
- 파일 생성을 위해서는 File 인스턴스를 생성할 때 첫 번째 인자에 경로를, 두 번째 인자에 파일명을 작성하고, createNewFile() 메서드를 호출해준다
File file = new File("../", "fileInstance.txt");
file.createNewFile();
- 파일명을 변경하고 싶을 때는 renameTo() 메서드를 사용한다
public class FileExample {
public static void main(String[] args) {
File parent = new File("./");
File[] fileList = parent.listFiles();
String prefix = "renameFile";
for(int idx = 0; idx < fileList.length; idx++) {
String fileName = fileList[idx].getName();
if(fileName.endWith("txt"))
list[idx].renameTo(new File(parent, prefix + fileName));
}
}
}