티스토리 뷰
1. 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
Stream
- 데이터를 운반하는데 사용되는 연결 통로
- 단방향 통신만 가능, 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없음
- 바이트 기반 스트림 (InputStream, OutputStream)
- 다른 read, write 함수들에서 abstract 함수를 사용하고 있기 때문에 read(), write(int b)가 반드시 구현되어 있어야 사용 가능
inputStream | outputStream |
abstract int read () | abstract void write (int b) |
int read (byte[] b) | void write (byte[] b) |
int read (byte[] b, int off, int len) | void write (byte[] b, int off, int len) |
입력스트림 | 출력스트림 | 입출력 대상의 종류 |
FileInputStream | FileOutputStream | 파일 |
ByteArrayInputStream | ByteArrayOutputStream | 메모리(byte 배열) |
PipedInputStream | PipedOutputStream | 프로세스(프로세스간의 통신) |
AudioInputStream | AudioOutputStream | 오디오장치 |
Buffer
- 보조 스트림, 입력성능응 향상 시키거나 새로운 기능을 추가할 수 있음
//기반 스트림을 생성
FileInputStream fis = new FileInputStream("test.txt");
//기반 스트림을 이용, 보조 스트림을 생성
BufferedInputStream bis = new BufferedInputStream(fis);
//보조스트림인 BufferedInputStream 으로부터 데이터를 읽음
bis.read();
- 보조 스트림의 종류
- InputStream과 OutputStream의 자손들이므로 입출력 방법이 같음
입력 | 출력 | 설명 |
FilterInputStream | FilterOutputStream | 필터를 이용한 입출력처리 |
BufferedInputStream | BufferedOutputStream | 버퍼를 이용한 입출력 성능 향상 |
DataInputStream | DataOutputStream | int, float와 같은 기본형 단위(primitive type)로 데이터를 처리 |
SequenceInputStream | 두개의 스트림을 하나로 연결 | |
LineNumberInputStream | 읽어온 데이터의 라인 번호를 카운트 | |
ObjectInputStream | ObjectOutputStream | 데이터를 객체단위로 읽고 쓰는데 사용, 주로 파일을 이용하며 객체 직렬화와 관계있음 |
PrintStream | 버퍼를 이용하며, 추가적인 print 관련 기능(print, printf, println 메서드) | |
PushBackInputStream | 버퍼를 이용해서 읽어온 데이터를 다시 되돌리는 기능(unread, push back to buffer) |
Channel
- channel은 stream과 달리 양방향 입출력이 가능
- java.nio.channels.FileChannel
- 동기화 처리가 되어있어, 멀티스레드 환경에서 안전
FileChannel fileChannel = FileChannel.open(
Paths.get("C:/Temp/file.txt"),
StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE
);
FileChannel fileChannel = FileChannel.open(
Paths.get("C:/Temp/file.txt"),
StandardOpenOption.READ,
StandardOpenOption.WRITE
);
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class App {
public static void main(String[] args) {
System.out.println("hi");
Path path = Paths.get("D:/dev/workspace/java-study/src/com/ssonsh/study/filechannel/test.txt");
try(FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)){
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
Charset charset = Charset.defaultCharset();
StringBuilder data = new StringBuilder();
int byteCount;
while(true){
byteCount = fileChannel.read(byteBuffer);
if(byteCount == -1) break;
byteBuffer.flip();
data.append(charset.decode(byteBuffer).toString());
byteBuffer.clear();
}
System.out.println("file.txt : " + data);
}catch(Exception e){
e.printStackTrace();
}
}
}
2. InputStream과 OutputStream
- 모든 바이트 기반 스트림의 조상
InputSteam
메서드명 | 설명 |
int available() | 스트림으로부터 읽어올 수 있는 데이터의 크기 반환 |
void close() | 스트림 닫음, 자원 반환 |
void mark (int readlimit) | 현재 위치 표시 reset() 으로 표시한 위치로 다시 돌아갈 수 있음 readlimit : 되돌아 갈 수 있는 byte의 수 |
boolean markSupported | mark(), reset()을 지원하는지 알려줌 |
abstract int read() | 1 byte를 읽어옴 읽어올 데이터가 없으면 -1 반환 abstract 라서 상황에 맞게 구현 필요 |
int read (byte[] b) | 배열 b의 크기 만큼 읽어서 배열을 채우고 읽어온 데이터의 수를 반환 |
int read (byte[] b, int off, int len) | 최대 len 개의 byte를 읽어서 배열 b의 off 위치 부터 저장함 |
void reset() | 스트림에서 위치를 마지막으로 mark() 가 호출되었던 위치로 되돌림 |
long skip (long n) | 스트림에서 주어진 길이 n 만큼 건너뜀 |
OutputStream
메서드명 | 설명 |
void close() | 입력 소스를 닫음, 자원 반환 |
void flush() | 스트림 버퍼에 있는 모든 내용을 출력 소스에 씀, 버퍼가 있는 출력 스트림에만 의미가 있음 |
abstract void write(int b) | 주어진 값을 출력 소스에 씀 |
void write (byte[] b) | 주어진 배열 b에 저장된 모든 내용을 출력 소스에 씀 |
void write (byte[] b, int off, int len) | 주어진 배열 b에 저장된 내용 중에서 off 번째 부터 len개 만큼 읽어서 출력 소스에 씀 |
3. Byte와 Character 스트림
- Java의 한문자 char 형은 2byte
- 바이트 기반의 스트림으로 2byte 문자 처리하는데에 어려움이 있음
- InputStream -> Reader , OutputStream -> Writer
바이트 기반 스트림 | 문자 기반 스트림 |
FileInputStream FileOutputStream |
FileReader FileWriter |
ByteArrayInputStream ByteArrayOutputStream |
CharArrayReader CharArrayWriter |
PipedInputStream PipedOutputStream |
PipedReader PipedWriter |
StringBufferInputStream StringBufferOutputStream |
StringReader StringWriter |
InputStream | Reader |
abstract int read() int read(byte[] b) int read(byte[] b, int off, int len) |
int read() int read(char[] cbuf) abstract int read(char[] cbuf, int off, int len) |
OutputStream | Writer |
abstract void write (int b) void write (byte[] b) void write (byte[] b, int off, int len) |
void write (int c) void write (char[] cbuf) abstract void write (char[] cbuf, int off, int len) void write(String str) void write(String str, int off, int len) |
바이트 기반 보조 스츠림 | 문자 기반 보조 스트림 |
BufferedInputStream BufferedOutputStream |
BufferedReader BufferedWriter |
FilterInputStream FilterOutputStream |
FilterReader FilterWriter |
LineNumberInputStream (deprecated) | LineNumberReader |
PrintStream | PrintWriter |
PushbackInputStream | PushbackReader |
4. 표준 스트림 (System.in, System.out, System.err)
- 콘솔(console)을 통한 데이터 입력과 출력
- 자바 어플리케이션의 실행과 동시에 자동으로 사용 생성되어서 스트림 작성 없이 사용 가능
- System.in : 콘솔로부터 데이터를 입력 받음 InputStream
- System.out : 콘솔로 데이터를 출력함 PrintStream
- System.err : 콘솔로 데이터를 출력 PrintStream
- static void setOut(PrintStream out) : System.out의 출력을 지정된 PrintStream으로 변경
- static void setErr(PrintStream err) : System.err의 출력을 지정된 PrintStream으로 변경
- static void setIn(InputStream in) : System.in의 출력을 지정된 InputStream으로 변경
import java.io.*;
class StandardIOEx3 {
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); // System.out의 출력대상을 test.txt파일로 변경
} catch(FileNotFoundException e) {
System.err.println("File not found.");
}
System.out.println("Hello by System.out");
System.err.println("Hello by System.err");
}
}
5. 파일 읽고 쓰기
FileInputStream, FileOutputStream
- read() 의 반환 값이 int 형이지만 -1(더이상 입력값이 없음)을 제외하고는 0 ~ 255(1byte) 범위의 정수형이기 때문에 char형(2byte)로 변환되어도 손실되는 값은 없음
import java.io.*;
class FileViewer {
public static void main(String args[]) throws IOException{
FileInputStream fis = new FileInputStream(args[0]);
int data = 0;
while((data=fis.read())!=-1) {
char c = (char)data;
System.out.print(c);
}
}
}
FileReader, FileWriter
- byte기반 스트림은 한글이 깨져서 출력된다
import java.io.*;
class FileReaderEx1 {
public static void main(String args[]) {
try {
String fileName = "test.txt";
FileInputStream fis = new FileInputStream(fileName);
FileReader fr = new FileReader(fileName);
int data =0;
// FileInputStream을 이용해서 파일내용을 읽어 화면에 출력한다.
while((data=fis.read())!=-1) {
System.out.print((char)data);
}
System.out.println();
fis.close();
// FileReader를 이용해서 파일내용을 읽어 화면에 출력한다.
while((data=fr.read())!=-1) {
System.out.print((char)data);
}
System.out.println();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
} // main
}
File
- File (String fileName) : 주어진 문자열을 이름으로 갖는 파일을 위한 File 인스턴스를 생성, fileName에 경로 포함
- File (String pathName, String fileName) : 파일의 이름과 경로를 분리해서 관리
- File (File pathName, String fileName) : 문자열이 아닌 File 인스턴스가 경로인 경우
- File (URI uri) : 지정된 uri로 파일을 생성
import java.io.*;
class FileEx1 {
public static void main(String[] args) throws IOException
{
File f = new File("c:\\jdk1.8\\work\\ch15\\FileEx1.java");
String fileName = f.getName();
int pos = fileName.lastIndexOf(".");
System.out.println("경로를 제외한 파일이름 - " + f.getName());
System.out.println("확장자를 제외한 파일이름 - " + fileName.substring(0,pos));
System.out.println("확장자 - " + fileName.substring(pos+1));
System.out.println("경로를 포함한 파일이름 - " + f.getPath());
System.out.println("파일의 절대경로 - " + f.getAbsolutePath());
System.out.println("파일의 정규경로 - " + f.getCanonicalPath());
System.out.println("파일이 속해 있는 디렉토리 - " + f.getParent());
System.out.println();
System.out.println("File.pathSeparator - " + File.pathSeparator);
System.out.println("File.pathSeparatorChar - " + File.pathSeparatorChar);
System.out.println("File.separator - " + File.separator);
System.out.println("File.separatorChar - " + File.separatorChar);
System.out.println();
System.out.println("user.dir=" + System.getProperty("user.dir"));
System.out.println("sun.boot.class.path=" + System.getProperty("sun.boot.class.path"));
}
}
출처
자바의 정석, 남궁 성 지음
'개발 > Java Study' 카테고리의 다른 글
15주차: 람다식 (0) | 2021.03.21 |
---|---|
14주차 : 제네릭 (0) | 2021.03.15 |
12주차 : 애노테이션 (0) | 2021.02.24 |
11주차 : Enum (0) | 2021.02.21 |
10주차 : 멀티쓰레드 프로그래밍 (0) | 2021.02.20 |