티스토리 뷰

개발/Java Study

13주차 : I/O

박비버 2021. 3. 3. 23:40

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"));
	}
}

 

출처

자바의 정석, 남궁 성 지음

www.notion.so/I-O-af9b3036338c43a8bf9fa6a521cda242

'개발 > 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
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함