본문 바로가기

개발기술/Java

Java 코딩구현 - Java I/O

Java I/O

Java IO (Input/Output) is the set of APIs that lets your program read from and write to data sources like

Data Source Java I/O API Used
📁 Files File, FileReader, FileWriter, InputStream, OutputStream, Files, Path, FileChannel
🔌 Network Socket, ServerSocket (java.io) → SocketChannel, Selector (java.nio)
⌨️ Keyboard / Console System.in, System.out, Console
🧠 Memory (Buffers) ByteArrayInputStream, ByteArrayOutputStream (java.io), ByteBuffer (java.nio)
⚙️ Other programs ProcessBuilder, Process.getInputStream() / OutputStream()

 

 

 

입력과 출력 (I/O) : 전체 구조

  데이터가 한 애플리케이션에서 다른 매체로 전송될 때는 바이트 직렬화(Byte Serialization) 과정을 거칩니다. 이 과정은 데이터를 특정한 형태의 바이트 스트림으로 변환하여 전송 가능하게 만드는 단계입니다. 이후, 데이터를 수신하는 매체는 메타데이터를 참고해 역직렬화(Deserialization) 과정을 거쳐 원래 사용 가능한 형태로 변환합니다. 이를 통해 다른 애플리케이션이나 매체에서 데이터를 이해하고 활용할 수 있습니다.

 

 

  • 입력과 출력(I/O):
    • 애플리케이션에서 외부 시스템과의 데이터를 주고받는 과정.
    • 입력: 데이터를 받는 작업
    • 출력: 데이터를 보내는 작업
  • Byte Serialization(바이트 직렬화):
    • 데이터를 바이트 스트림 형태로 변환하여 전송 가능하게 만드는 과정.
    • 바이트 단위로 변환된 데이터는 네트워크, 파일 시스템 등 다양한 매체를 통해 전송됩니다.
  • Meta Data(메타데이터):
    • 데이터에 관한 정보(형식, 타입, 크기 등)를 포함하여 역직렬화 시 데이터의 의미를 해석하는 데 도움을 줍니다.
    • 직렬화된 데이터가 목적지에서 올바르게 해석될 수 있도록 데이터 구조에 대한 정보를 포함합니다.
  • Deserialization(역직렬화):
    • 수신된 바이트 스트림을 원래의 데이터 형태로 복원하는 과정.
    • 메타데이터를 활용해 데이터를 정확하게 복원하여 애플리케이션이 사용 가능한 상태로 변환합니다.

 

 

 

스트림(Stream)

Java의 I/O 시스템에서는 스트림(Stream) 이라는 개념을 핵심으로 데이터를 순차적으로 읽거나 쓰는 방식으로 작업합니. 스트림은 Java I/O 시스템의 핵심 요소로, 데이터를 순차적으로 읽고 쓰는 데 사용됩니다. 스트림에는 두 가지 주요 유형이 있습니다.

  1. 바이트 스트림(Byte Streams):
    • InputStream / OutputStream: 바이트 데이터를 읽고 쓰기 위한 기본 클래스.
    • FileInputStream / FileOutputStream: 파일에서 데이터를 읽고 쓰기 위해 사용되는 클래스.
    • BufferedInputStream / BufferedOutputStream: 버퍼를 추가하여 I/O 작업 횟수를 줄여 효율을 높입니다.
  2. 문자 스트림(Character Streams):
    • Reader / Writer: 문자 데이터를 읽고 쓰기 위한 기본 클래스.
    • FileReader / FileWriter: 파일 I/O 작업을 위해 사용되는 클래스.
    • BufferedReader / BufferedWriter: 텍스트를 효율적으로 읽고 쓰는 메서드를 포함하여, 예를 들어 readLine() 메서드를 통해 한 줄씩 읽는 작업이 가능합니다.

 

 

    •  

 

JAVA FileSystem

과거 FILE I/O의 복잡성을 해결하기 위해서 도입한 nio package. Path객체와 Files의 method로 파일의 내용을 모두 읽을 수 있다.

import java.nio.file .*;
import java.io.IOException;
import java.util.List;

    public class FileInputExample {
        public static void main(String[] args) throws IOException {
            // Use Path and Files to read the file
            Path filePath = Paths.get("input.txt");

            // Read all lines at once into a List
            List<String> lines = Files.readAllLines(filePath);

            // Process the file line by line
            lines.forEach(System.out::println);
        }
    }

입력과 출력 (I/O) : 파일시스템

  • File: Represents file and directory's path in an abstract, system-independent manner.
  • 실제로 파일을 생성하는 것이 아니라, 파일이라는 대상을 해당 주소에 추상적으로 만들어내는 객체. 객체 생성을 한다고 실제로 파일을 생성하지는 않음.
File file = new File("example.txt");
file.exists();           // ❓ Does the file exist on disk?
file.createNewFile();    // ✅ Now actually creates it if it doesn’t exist
file.delete();           // 🗑️ Deletes it from disk
Method Description
file.exists() Check if the file or directory exists
file.createNewFile() Create a new file (if it doesn't exist)
file.delete() Delete the file
file.isFile() Is it a file (not a directory)?
file.isDirectory() Is it a directory?
file.length() File size in bytes
file.getAbsolutePath() Get full path as string
file.mkdirs() Create directory and parents

 

Common Exception of File System

  • Does not check if there is existing entity or if its file or directory
    • Shoule have checked if there is same named entity
    • a file and a folder can't have the same name at the same location
File file = new File("example");
file.createNewFile();

File dir = new File("example");
dir.mkdir(); // ❌ Fails silently or returns false

 

 

 

Safe handling strategy

File file = new File("something");

if (file.exists()) {
    if (file.isDirectory()) {
    System.out.println("It's a directory. Cannot use as a file.");
    } else {
        System.out.println("It's a regular file.");
    }
        } else {
        // create the file or directory safely
        }

 

 

  •   FileWriter:  Used for writing character data to a file. If the file specified in the FileWriter constructor does not exist, it will be created automatically.   is often wrapped in higher-level classes like BufferedWriter to improve performance through buffering.
    • IOException needs to be handled because file operations can fail for various reasons (like the file does not exist).
    • Key Methods:
      • Constructors: FileWriter(String fileName), FileWriter(File file, boolean append).
      • write(): Writes text into the file.
  • BufferedReader / BufferedWriter: The BufferedWriter/reader in Java is specifically designed to wrap around any object that extends the abstract Writer/reader class, thereby providing improved efficiency through buffering. 
    • ex ) BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt")); bw.write("Hello, world!"); bw.close();
    • 버퍼를 마지막에 close를 해야 stream이 flush가되어 저장매체에 저장된다.
    • Constructors : BufferedReader(Reader in, int sz) for custom buffer sizes / BufferedWriter(Writer out, int sz) for custom buffer sizes.
      • The constructors for BufferedReader and BufferedWriter in Java are designed to wrap around other reader and writer objects, respectively.  
  • StringBuilder: 문자열을 자주 추가하거나 변경할때 사용하는 자료형. DS관점에서 Dynamic Array와 유사하며 기능적으로 StringBuilder와 거의 동일하다. 쓰레드 안정성에서 Single Thread에서는 StringBuilder, Multi Thread에서는 StringBuffer을 사용한다. Builder는 Ram에서 메모리를 충분히 할당받으나 buffer은 ram에서 8000char 가량밖에 할당되지 않고 꽉 찰시 flush를 통해 file로 저장한다.  stringbuffer은 크키는 한정되지 않으나 synchronization을 위해 lock이 구현되어 있어 비교적 비효율적이다.
    • StringBuilder variable = new StringBuilder("text")
    • method
      • append(str,char): Appends the specified string to this character sequence.
        • string에서 a+b로도 concatnation이 가능하지만 string buffer은 dynamic하게 크기가 변하기 때문에 static한 string에 비해서 메모리 비효율적이다.
      • insert(index, String str): Inserts the specified string into this character sequence.
      • delete(strindex, endindex) : Removes the characters substring that begins at the specified start and to at index end - 1
      • reverse() : Reverses the characters within the StringBuffer.
      • setLength() - Sets or adjusts the length of the character sequence. If the new length is shorter, the sequence is truncated; if longer, it is padded with null characters ('\u0000').
      • toString() : Converts Stringbuilder to String
      • String과 공용메서드 : charat(index), substringsubstring(int beginIndex, int endIndex), 
 

 

 

 

 

 

입력과 출력 (I/O) : 입력

The java.io package is part of Java's original I/O API and provides classes for system input and output through data streams, serialization, and the file system.

  • 1. System.in.read() : this method reads raw byte data from the standard input stream (System.in), which typically means it reads one character at a time from the user's keyboard input.
  • 2. InputStreamReader : 개발자의 편의성을 위해서 데이터를 한번에 1바이트씩 읽어들이도록 정의한 도구. 
  • 3. BufferedReader : Ram에서 buffer memory를 할당받아서, inputstream을 통해 들어오는 데이터를 쌓아나가는 곳. bufferedreader와 inputstreamreader가 같이 쓰일때는 1바이트씩이 아니라 bulk로 데이터가 들어온다.
    • 생성 : BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
      • readLine(): Reads a line of text. A line is considered to be terminated by any one of a line feed
      • close(): Closes the stream and releases any system resources associated with it.
      • hasMoreTokens(): Tests if there are more tokens available from this tokenizer's string.
  • 4. Stringbuilder : bufferedreader에서 readline으로 받아들인 값은 stringbuilder에 계속 해서 append된다. 이는, string은 고정된 사이즈의 개체인 반면 stringbuilder는 유동적인 사이즈의 배열로 새로 제3의 string을 계속 만들지 않아도 되기때문이다.
  •  StringTokenizer(String str, String delimiter(option), boolean returnDelims(option)) : is used to break a string into tokens as the String.split() but faster performance.  the default delimiters : whitespace characters (spaces, tabs, new lines, etc.). If returnDelims is true, then the delimiters themselves will also be returned as tokens.
    • 생성 : StringTokenizer tokenizer = new StringTokenizer(parameters);
    • nextToken(): Returns the next token from this string tokenizer.
    • hasMoreTokens(): Tests if there are more tokens available from this tokenizer's string.
  • Stringtokenizer와 BufferReader 사용예시

 

 

    •  *Scanner sc = new Scanner(System.in)
      • S`System.in` 을 통해서 사용자의 입력이나 다소 복잡하기에 `Scanner` 라는 클래스를 주로 사용한다.
      • Scanner Method
        • scanner.nextLine()엔터( `\n` )을 입력할 때 까지 문자를 가져온다.
        • nextInt(), nextDouble(), nextFloat(), etc.: to read and convert the next token of the input into a specific type (int, double, float, etc.)..
        • next() : Finds and returns the next complete token that's delimited by space.
        • hasNextLine(), hasNextInt(), hasNextDouble()`: Checks if there is another line, int, double, etc., to read and return true useful for loop or if statement
        • close() : Closes the scanner and releases any resources associated with it
          • Scanner method 중 nextint는 입력값 (ex: 5\n) 중 숫자만 취득하고 나머지 \n을 버퍼메모리에 두기 때문에 nextLine을 실행하여 \n 값을 처리해주어야한다.
      • File file = new File("filename") : 파일 인스턴스를 생성후 scanner의 매개변수로 입력하면 파일의 내용이 system input으로 입력됨.

입력과 출력 (I/O) : 출력

  • `System.out.println()` : 값과 한줄 띄우기를 콘솔에 출력하는 기능이다.
    • java는 문자열과 더해지는 다른 데이터형을 자동적으로 string으로 conversion되기 때문에 System.out.println("a + b = " + sum); 의 표현이 가능함. 반면 python은 자동변환이 되지 않아서 다음과 같이 변환이 필요함. print("a + b = " + str(sum)) or print(f"a + b = {sum}")
  • `System.out.print()` : 한줄 띄우기없이(n : 한줄띄우기), 값을 콘솔에 출력하는 기능이다.
  • BufferWriter : BufferedWriter is a class used to write text to a character-output stream, buffering characters so as to provide for the efficient writing of single characters, arrays, and strings. Throw Exception 처리를 반드시 해주어야함.
    • ex : BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
    • write(String s, int off, int len): Writes a portion of a string.
    • newLine(): Adds a line separator. The line separator string is defined by the system property line.separator, which is not necessarily a newline (\n) character.
    • flush(): Flushes the buffer, which forces any characters buffered by the BufferedWriter to be written to the underlying output.
    • close(): Closes the writer, but first flushes it one last time to ensure all data in the buffer is written out. After closing, the writer can no longer be used.

 

file.exists();           // ❓ Does the file exist on disk?
file.createNewFile();    // ✅ Now actually creates it if it doesn’t exist
file.delete();           // 🗑️ Deletes it from disk