입출력 I/O 스트림입출력 스트림의 구분바이트 단위 스트림과 문자단위 스트림System클래스의 표준 입출력 멤버InputStreamScanner vs BufferedReader기반 스트림과 보조스트림BufferedInputStream과 BufferedOutputStream(보조 스트림)DataInputStream과 DataOutputStream(보조 스트림)ByteArrayInputStream vs byte[]직렬화(serialization)SerializableExternalizable그외 입출력 클래스들File ManagementFile classFileNotFoundException 발생 시ClassPath에서 File 읽기Java SDKApplicationContext 의 ResourceLoader 인터페이스 이용File로 부터 텍스트 읽기File에 텍스트 쓰기Creating and deleting files and directoriesApache Commons FileUtils and IOUtils
InputStream이란?java.io vs java.nio입출력 I/O 스트림

- A stream can be limited or endless
- Java I/O stream은 바이트기반 or 문자기반(character-based) 둘 다 가능함(data를 raw byte로 이해할 것이냐, 문자로 이해할 것이냐)
- 입출력은 입력을 받는 대상이 뭔지 출력을 하는 대상이 뭔지에 따라 달라지는데 이를 스트림을 통해 추상화하는것(바이트가 오고 가게 됨)
- 입출력이 구현되는 곳 : 파일디스크, 키보드, 마우스, 네트웍, 메모리 등 모든 자료가 입력되고 출력되는 곳
입출력 스트림의 구분
- 대상 기준 : 입력 스트림 / 출력 스트림
- 입력 스트림 : FileInputStream, FileReader, BufferedInputStream, BufferedReader 등
- 출력 스트림 : FileOutputStream, FileWriter, BufferedOutputStream, BufferedWriter 등
- 자료의 종류 : 바이트 스트림 / 문자 스트림(문자 단위로 핸들링 할때는 인코딩이 중요함)
- 기능 : 기반 스트림/ 보조 스트림
바이트 단위 스트림과 문자단위 스트림
- 바이트 스트림(*Input*, *Output*)
- FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream 등
- ObjectInputStream : serialize된 객체 파일을 deserialize할 때 이용
- PipedInputStream : thread간의 communication을 위해 사용하는 input stream. 한 Thread에서 읽고 다른 Thread로 쓰기작업
- PrintStream : 데이터를 문자들로 출력하는 기능을 가진 OutputStream
- 문자 스트림(*read, *write)
- FileReader, FileWriter, BufferedReader, BufferedWriter, CharArrayReader, CharArrayWriter, InputStreamReader, OutputStreamWriter, PipedReader, PipedWriter, StringReader, StringWriter,,
System클래스의 표준 입출력 멤버
- System.out.println() : 표준 출력(모니터) 스트림
- out 변수의 타입이
PrintStream
- System.in : 표준 입력(키보드) 스트림
- System.in.read() : 한바이트씩 읽음
- 60을 입력하면, 6에 해당하는 컴퓨터에서의 비트값인 54가 반환, 0에 해당하는 48이 반환됨 ⇒ 숫자를 그대로 입력받고 싶으면 Scanner의 nextInt 메서드 사용하기
- 한글 안깨지게 출력하려면 2바이트씩 읽어주어야함 (InputStreamReader)
- System.err : 표준 에러 출력(모니터) 스트림
InputStream
- 바이트 단위 입력 스트림 최상위 추상 클래스(한글은 2바이트씩이라 한글입력스트림에 대해서는 깨지게 출력됨)
Scanner vs BufferedReader
- Scanner는 토큰 기반으로 input에서 읽어들이고, BufferedReader는 한 줄 단위로 읽고 그 줄에서 토큰으로 끊어서 읽어들이기 때문에 Scanner가 읽는데 시간이 조금 더 걸림
- Scanner가 입력 데이터를 구문 분석하고, BufferedReader는 단순히 문자 시퀀스를 읽기 때문에 스캐너에 비해 조금 더 빠름
- Scanner로 읽을때 memory를 되게 많이 잡아먹는 이슈가 있음 - 이유가 뭘까..?
기반 스트림과 보조스트림
- 기반 스트림
- 대상에 직접 자료를 읽고 쓰는 기능의 스트림
- input : 쓸 대상, 읽을 대상
- 보조 스트림
- 직접 읽고 쓰는 기능은 없이 추가적인 기능을 더해주는 스트림
- input: InputStream, OutputStream
- 보조 스트림은 직접 읽고 쓰는 기능은 없으므로 항상 기반 스트림이나 또 다른 보조 스트림을 생성자의 매개 변수로 포함함

BufferedInputStream과 BufferedOutputStream(보조 스트림)
DataInputStream과 DataOutputStream(보조 스트림)
- 자료가 메모리에 저장된 상태 그대로 읽거나 쓰는 스트림
- short 정수면 short 정수.
ByteArrayInputStream vs byte[]
- input이 항상 byte[] 면, stream을 쓸 필요가 없음
- 그러나, ByteArrayInputStream을 쓴다는 것은 해당 byte가 읽기 전용이라는 것을 강하게 암시할 수 있고 input이 가끔 byte[] 이고, 또는 file일 수도 있고, network connection일 수 있다면 ByteArrayInputStream을 통해 byte의 stream 이라는 추상화를 적용할 수 있음.
- "a stream of bytes, and I don't care where they come from."
ByteArrayInputStream을 쓰면 좋은 예시
- You're writing a library that takes bytes and processes them somehow (maybe it's an image processing library, for instance). Users of your library may supply bytes from a file, or from a
byte[]
in memory, or from some other source. So, you provide an interface that accepts anInputStream
— which means that if what they have is abyte[]
, they need to wrap it in a ByteArrayInputStream.
- You're writing code that reads a network connection. But to unit test that code, you don't want to have to open up a connection; you want to just supply some bytes in the code. So the code takes an InputStream, and your test provides a ByteArrayInputStream.
직렬화(serialization)
- 인스턴스의 상태를 그대로 파일 저장하거나 네트웍으로 전송하고 (serialization) 이를 다시 복원(deserialization) 하는 방식
- 직렬화는 인스턴스의 내용이 외부로 유출되는 것이므로 프로그래머가 해당 객체에 대한 직렬화 의도를 표시해야 함 →
implements Serializable
- transient : 직렬화 하지 않으려는 멤버 변수에 사용함 (Socket등 직렬화 할 수 없는 객체)
Serializable
- 대부분 거의 이걸로 많이 씀
Externalizable
그외 입출력 클래스들
- Scanner 클래스
- File 클래스 : 입출력 기능은 없고, 파일의 이름, 경로, 읽기 전용 등의 속성을 알 수 있음
- RandomAccessFile 클래스 : 입출력 클래스 중 유일하게 파일에 대한 입력과 출력을 동시에 할 수 있는 클래스
- 파일 포인터가 있어서 읽고 쓰는 위치의 이동이 가능함
File Management
File class
- File class constructor를 부른다고 해서 File System에 바로 파일이 생성되는 것이 아님
- 파일 생성 위해서는 createNewFile() 메서드를 호출해야 함
- File 클래스가 data를 담고 있기 위해서는 File System에 생성되어야 함
FileNotFoundException 발생 시
- new File(”.”) 로 getAbsolutePath() 호출하여 현재 경로를 확인
- 해당 현재 경로 기준으로 파일을 위치시켜서 파일 읽으면 잘 찾을 수 있음
ClassPath에서 File 읽기
Java SDK
// Class 를 이용하여 classpath의 파일 읽기 // src/main/resources 아래에서 절대 경로를 넣어주어야 함 @Test public void givenFileNameAsAbsolutePath_whenUsingClasspath_thenFileData() { String expectedData = "Hello, world!"; Class clazz = FileOperationsTest.class; InputStream inputStream = clazz.getResourceAsStream("/fileTest.txt"); String data = readFromInputStream(inputStream); Assert.assertThat(data, containsString(expectedData)); } // ClassLoader를 이용하여 classpath의 파일 읽기 // src/main/resources 를 루트로 해서 파일 경로 넣어주면 됨 ClassLoader classLoader = getClass().getClassLoader(); // 현재 클래스의 클래스로더 InputStream inputStream = classLoader.getResourceAsStream("fileTest.txt"); String data = readFromInputStream(inputStream);
ApplicationContext 의 ResourceLoader 인터페이스 이용
File로 부터 텍스트 읽기
@Test void name() { String path = "/Users/geuno/Downloads/index.html"; File f = new File(path); try (BufferedReader reader = new BufferedReader(new FileReader(f))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } }
File에 텍스트 쓰기
- BufferedWriter
- PrintWriter
- FileOutputStream
- Files
Creating and deleting files and directories
@Test void listFilesInDirectory() { String path = "/Users/geuno/Downloads"; File f = new File(path); File[] files = f.listFiles(); for (File file : files) { System.out.println(file.getName()); } } @Test void createFile() throws IOException { String path = "/Users/geuno/Downloads/a.txt"; File f = new File(path); f.createNewFile(); } @Test void createDirectoryAndCreateDelete() throws IOException { String path = "/Users/geuno/Downloads/a/b/a.txt"; File f = new File(path); try { f.mkdirs(); f.createNewFile(); f.delete(); } catch (IOException e) { System.out.println(e); } }
Apache Commons FileUtils and IOUtils
[Baeldung ] Apache Commons IO
- FileUtils class. 기능들
- writing to a file
- reading from a file
- make a directory including parent directories
- copying files and directories
- deleting files and directories
- converting to and from a URL
- listing files and directories by filter and extension
- comparing file content
- file last changed date
- calculating a checksum
- IOUtils class : general I/O stream manipulation methos
- closeQuietly - these methods close a stream ignoring nulls and exceptions
- toXxx/read - these methods read data from a stream
- write - these methods write data to a stream
- copy - these methods copy all the data from one stream to another
- contentEquals - these methods compare the content of two streams
This class provides static utility methods for input/output operations.