[TIL] 2022년 10월 1일 토요일
6.2 표준입출력의 대상변경
- System.in, System.out, System.err의 입출력 대상은 콘솔화면 → setIn(), setOut(), setErr()를 사용하여 다른 입출력 대상으로 변경 가능 → JDK1.5부터 Scanner클래스를 제공하여 System.in으로 데이터를 입력받는 것이 편리해짐
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class StandardIOEx {
public static void main(String[] args) {
PrintStream ps = null;
FileOutputStream fos =null;
try {
fos = new FileOutputStream("test.txt");
ps = new PrintStream(fos);
System.setOut(ps);
}catch (IOException e){
System.err.println("File not found");
}
System.out.println("Hello by System.out");
System.err.println("Hello by System.err");
}
}
//자바의 정석 교재 예제
C:\jdk1.8\work\ch15>java StandardIOEx3
Hello by System.err
C:\jdk1.8\work\ch15>type test.txt
Hello by System.out
C:\jdk1.8\work\ch15>
//내 컴퓨터로 실행
Macui-iMac:src mac$ java StandardIOEx.java
Hello by System.err
Macui-iMac:src mac$ type test.txt
-bash: type: test.txt: not found
Macui-iMac:src mac$ cat test.txt
Hello by System.out
Macui-iMac:src mac$
- 내 컴퓨터로 예제를 실행했으나 type test.txt가 작동하지 않음 → terminal이라서 type 대신 cat으로 변경
Macui-iMac:src mac$ java StandardIOEx >> output.txt
Hello by System.err
Macui-iMac:src mac$ cat output.txt
Macui-iMac:src mac$ cat output.txt
Macui-iMac:src mac$ java StandardIOEx < output.txt
Hello by System.err
Macui-iMac:src mac$ cat output.txt
Macui-iMac:src mac$
- output.txt로 데이터를 받아 새로운 내용을 저장하는 것 같은데 terminal에서는 output.txt파일이 생성되기만하고 내용을 입력하지 못함 → 다른 방법을 찾아봐야 함
6.3 RandomAccessFile
- RandomAccessFile 클래스는 DataOutput 인터페이스와 DataInput 인터페이스를 구현 → random access file에 대하여 읽고 쓰는 것 모두 지원하는 클래스
- 파일 포인터를 사용하여 파일의 어느 위치에서나 읽고 쓰기가 가능함.
- 파일 포인터는 파일의 첫 부분에 위치. 파일을 읽고 쓸 때 순차적으로 읽고 쓴다면 별도의 작업이 필요 없고, 원하는 임의의 위치가 있다면 파일 포인터를 원하는 위치로 이동한 다음 작업함.
- 모든 입출력 클래스가 파일 포인터를 갖고있으나 RandomAccessFile처럼 사용자가 포인터의 위치를 변경할 수 없음
생성자 | 설명 |
RandomAccessFile(File file, String mode) | 매개변수 파일을 읽거나 읽고 쓸 RandomAccessFile 스트림 인스턴스를 생성 |
RandomAccessFile(String name, String mode) | 매개변수 이름의 파일을 읽거나 읽고 쓸 RandomAccessFile 스트림 인스턴스를 생성 |
* mode의 값 r : 파일로부터 읽기만을 수행할 때 rw : 파일에 읽기와 쓰기. 지정된 파일이 없으면 새로운 파일 생성 rws: rw와 동일하나 출력내용이 파일에 지연 없이 바로 쓰이게 함. rwd는 파일의 내용만, rws는 파일의 메타정보 포함 |
자료형 | 메소드 | 설명 |
FileChannel | getChannel() | Returns the unique FileChannel object associated with this file. 파일과 연관된 고유한 FileChannel 객체를 반환 |
FileDescriptor | getFD() | Returns the opaque file descriptor object associated with this stream. 이 스트림과 연관된 불분명한 파일 디스크립터 객체를 반환 |
long | getFilePointer() | Returns the current offset in this file. 이 파일의 현재 offset을 반환. 'ABCD'가 저장된 파일에서 파일 포인터가 현재 'C'에 있다면 시작점인 'A'와 차이가 2이므로 2를 반환 |
long | length() | Returns the length of this file. 파일의 길이를 반환 |
void | seek(long pos) | Sets the file-pointer offset, measured from the beginning of this file, at which the next read or write occurs. 이 파일의 시작점에서 다음으로 읽거나 쓸 오프셋을 설정. 'ABCD'가 저장된 파일에서 seek(2)를 선언한다면 시작점인 A에서 2가 떨어진 'C'부터 읽고 씀 |
void | setLength(long newLength) | Sets the length of this file. 파일의 길이를 설정 |
int | skipBytes(int n) | Attempts to skip over n bytes of input discarding the skipped bytes. 지정된 수만큼 byte를 건너뛰고 건너뛴 바이트는 버림 |
import java.io.EOFException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileEx {
public static void main(String[] args) {
int[] score = { 1, 100, 90, 90,
2, 70, 90, 100,
3, 100, 100, 100,
4, 70, 60, 80,
5, 70, 90, 100
};
try {
RandomAccessFile raf = new RandomAccessFile("score2.dat", "rw");
for(int i=0; i<score.length; i++){
//raf.write(score[i]);
raf.writeInt(score[i]);
}
while (true){
System.out.println(raf.readInt());
}
}catch (EOFException eof){
}catch (IOException e){
e.printStackTrace();
}
}
}
import java.io.EOFException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileEx2 {
public static void main(String[] args) {
int sum = 0;
try {
RandomAccessFile raf = new RandomAccessFile("score2.dat", "r");
int i=4;
while (true){
raf.seek(i);
sum += raf.readInt();
i += 16;
}
}catch (EOFException eof){
System.out.println("sum = " + sum);
}catch (IOException ioe){
ioe.printStackTrace();
}
}
}
- 더보기 속 예제를 푸는데 답이 sum = 38165092라고 나왔다. 환장할 노릇이었지만 내 실수인 걸 발견했다. readInt()인데 read()를 넣었다. read()는 바이트로 읽으니 주의하자.
import java.io.EOFException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileEx2 {
public static void main(String[] args) {
int sum = 0;
try {
RandomAccessFile raf = new RandomAccessFile("score2.dat", "r");
int i=4;
while (true){
raf.seek(i);
System.out.println(raf.readInt());
sum += raf.readInt();
i += 16;
}
}catch (EOFException eof){
System.out.println("sum = " + sum);
}catch (IOException ioe){
ioe.printStackTrace();
}
}
}
- 국어점수만 잘 읽어오는지 궁금해서 readInt()한 다음 sum에 더하게 해봤는데 결과값이 410에서 430으로 바뀌었다. readInt()를 한다음 또 readInt()를 해서 파일 포인터가 다음 과목값을 더해 계산한 것이다. 출력해보고싶을 땐 새로운 변수를 선언해 그 변수에 readInt()한 값을 넣고, 출력하고 더해야 값이 변하지 않을 것이다.
6.4 File
- File 클래스는 파일과 디렉터리 모두 다룰 수 있어 File 인스턴스는 파일을 가리킬수도, 디렉터리를 가리킬 수 도 있음
타입 | 필드 | 설명 |
static String | pathSeparator | The system-dependent path-separator character, represented as a string for convenience. 운영체제 의존적인 경로 구분 문자열 |
static char | pathSeparatorChar | The system-dependent path-separator character. 운영체제 의존적인 경로 구분 문자 |
static String | separator | The system-dependent default name-separator character, represented as a string for convenience. 운영체제 의존적인 기본 이름 구분 문자열 |
static char | separatorChar | The system-dependent default name-separator character. 운영체제 의존적인 기본 이름 구분 문자 |
- 운영체제 의존적인은 직역하다보니 나온 표현인데 Java 파일이 실행되는 운영체제에서 사용중인으로 생각하는게 좋다.
생성자 | 설명 |
File(File parent, String child) | 부모 추상경로명에 있는 파일과 자식 경로명으로부터 child이름의 새로운 File 인스턴스를 생성 |
File(String pathname) | 매개변수로 받은 경로명을 추상경로명으로 변환하여 새로운 File 인스턴스를 생성 |
File(String parent, String child) | 부모 경로명과 자식 경로병으로부터 새로운 File 인스턴스를 생성 |
File(URI uri) | URI를 추상경로명으로 바꿔 주어진 파일로 새로운 File인스턴스를 생성 |
타입 | 메소드 | 설명 |
String | getName() | 추상경로명이 나타내는 파일이나 디렉터리의 이름을 반환 |
String | getPath() | 추상경로명을 String 타입의 경로명으로 변환하여 반환 |
String File |
getAbsolutePath() getAbsoluteFile() |
추상경로명을 String 타입의 절대경로로 반환 추상경로명을 File 타입의 절대경로로 반환 |
String File |
getParent() getParentFile() |
파일의 상위 추상경로명을 String 타입의 절대경로로 반환 파일의 상위 추상경로명을 File 타입의 절대경로로 반환 상위 경로명이 없다면 null을 반환 |
String File |
getCanonicalPath() getCanonicalFile() |
파일의 추상경로명을 String 타입의 정규경로 반환 파일의 추상경로명을 File 타입의 정규경로 반환 |
- UI와 운영체제는 파일이나 디렉터리의 이름을 정할 때 시스템에 의존적인 경로명을 사용함 → 윈도우는 경로를 구분할 때 ";", 이름을 구분할 때 "\"를 사용하지만 유닉스는 경로를 구분할 때 ":", 이름을 구분할 때 "/"를 사용
- 절대경로는 파일시스템의 루트에서 시작하는 파일의 전체 경로, 정규경로는 기호나 링크 등을 포함하지 않은 유일한 경로
- 추상경로명은 절대경로일 수도 있고 상대경로명일 수도 있음
- 이로 인해 윈도우에서 만든 Java 코드를 유닉스에서 실행할 때, 반대의 경우일 때 오류를 일으킬 수 있음 → File 클래스는 경로명을 계층적인 관점에서 운영체제에 독립되도록 도와줌
- 시스템 속성 중 user.dir값을 확인하면 현재 실행중인 디렉터리의 상대경로를 알 수 있음
타입 | 메소드 | 설명 |
boolean | canRead() | 읽을 수 있는 파일인지 검사 |
boolean | canWrite() | 쓸 수 있는 파일인지 검사 |
boolean | canExecute() | 실행할 수 있는 파일인지 검사 |
int | compareTo(File pathname) | 주어진 파일 또는 디렉터리와 비교 Unix는 대소문자 구별, Windows는 구별하지 않음 |
boolean | exists() | 파일이 존재하는지 검사 |
boolean | isAbsolute() | 파일 또는 디렉터리가 절대경로명으로 지정되었는지 확인 |
boolean | isDirectory() | 디렉토리인지 확인 |
boolean | isFile() | 파일인지 확인 |
boolean | isHidden() | 파일의 속성이 숨김인지 확인. 파일이 없으면 false |
boolean | createNewFile() | 새로운 파일을 생성. 생성하려는 파일이 기존재하면 생성하지 않음. |
static File | createTempFile() | 임시파일을 시스템의 임시 디렉토리에 생성 |
static File | createTempFile(String prefix, String suffix) | 임시파일을 시스템의 지정된 디렉토리에 생성 |
boolean | delete() | 파일을 삭제 |
void | deleteOnExit() | 응용프로그램 종료시 파일을 삭제 |
boolean | equals(Object obj) | 주어진 객체가 같은 파일인지 비교 |
long | lastModified() | 파일이 마지막으로 수정된 시간을 지정된 시간으로 반환 |
long | length() | 파일의 크기를 반환 |
String[] | list() | 디렉토리의 파일 목록(디렉토리 포함)을 String배열로 반환 |
String[] File[] |
list(FilenameFilter filter) list(FilenameFilter filter) |
FilnameFilter인스턴스에 구현된 조건에 맞는 파일을 String배열(File배열)로 반환 |
File[] File[] File[] |
listFiles() listFiles(FileFilter filter) listFiles(FilenameFilter f) |
디렉토리의 파일목록(디렉토리 포함)을 File배열로 반환(filter가 지정된 경우에는 filter의 조건과 일치하는 파일만 반환) |
static File[] long long long |
listRoots() getFreeSpace() getTotalSpace() getUsableSpace() |
컴퓨터 파일시스템의 root의 목록(floppy, CD-ROM, HDD drive)을 반환. get으로 시작하는 메서드들은 File이 root일 때 비어있는 공간, 전체 공간, 사용가능한 공간을 바이트단위로 반환 |
boolean boolean |
mkdir() mkdirs() |
파일에 지정된 경로로 디렉토리(폴더)를 생성. 성공하면 true, mkdirs는 필요하면 부모 디렉토리까지 생성 |
boolean | renameTo(File dest) | 지정된 파일(dest)로 이름을 변경 |
boolean boolean boolean boolean boolean boolean boolean |
setExcecutable(boolean executable) setExecutable(boolean executable, boolean ownerOnly) setReadable(boolean readable) setReadable(boolean readable, boolean ownerOnly) setReadOnly() setWritable(boolean writable) setWritable(boolean, boolean) |
파일의 속성을 변경. OwnerOnly가 true면 파일의 소유자만 해당 속성을 변경할 수 있음. |
boolean | setLastModified(long t) | 파일을 마지막으로 수정한 시간을 지정된 시간(t)으로 변경 |
Path | toPath() | 파일을 Path로 변환해서 반환 |
URI | toURI() | 파일을 URI로 변환해서 반환 |