본문 바로가기

Study/Kotlin

Kotlin / 파일 입출력과 스레드 처리

반응형

1. 파일 I/O 처리

파일 처리는 Input과 Output에 대한 데이터 처리 -> 데이터가 계속 처리되어 흐르는 것과 같아서 스트림(Stream)이라고 한다.

바이트나 텍스트 단위로 처리해서 사람이 인식할 수 있게 만들어야 한다.

- 버퍼(Buffer) : I/O 처리의 성능을 향상하기 위해 중간에 저장공간을 두고 처리하는 방식

 

가장 기본으로 파일을 읽고 쓰는 기반 : InputSteram, OutputStream

=> 이를 기반으로 바이트 단위로 처리하도록 지원 : ByteArrayInputStream, ByteArrayOutputStream

 

바이트 스트림은 기본적으로 데이터를 읽고 쓰는 것이다.

- read 메서드로 바이트 단위 읽기 (순환하면서 모든 바이트 읽음)

- write 메서드로 한 바이트씩 씀

 

파일처리 : 읽기

IO의 기본은 스트림이므로 이를 상속한 파일도 스트림으로 처리한다.

파일을 FileInputStream의 read 메서드로 바이트 단위로 읽는다.

파일을 다른 파일에 저장하기 위해서 FileOutputSteram이 write 메서드로 쓴다. 

파일 처리가 끝나면 항상 close 메서드로 닫아야 한다.

import java.io.FileInputStream
import java.io.FileOutputStream

var fin = FileInputStream("./data.txt")
var fout = FileOutputStream("./dataout.txt")

var data = fin.read()
println("바이트 하나 읽기 : $data , ${data.toChar()}")
println("데이터 자료형 확인 : ${data.javaClass.kotlin}")

while (data != -1) {
    fout.write(data)
    data = fin.read()
}

fin.close()
fout.close()

val fin1 = FileInputStream("./dataout.txt")
var data1 = fin1.read()
while (data1 != -1) {
    print(data1.toChar())
    data1 = fin1.read()
}

fin1.close()

 

버퍼리더를 사용해 파일 처리

입력 스트림으로 객체를 생성하고 버퍼를 사용해 텍스트로 파일을 읽는다.

Files로 파일을 엵고 inputStream 메서드로 InputStream으로 변경한다.

-> 이를 bufferedReader 메서드로 버퍼로 변환하고 use 메서드에 readLines 메서드로 전체 라인을 모두 읽는다.

 

val inputStream: InputStream = File("test.txt").inputStream()
val inputString = inputStream.bufferedReader().use{it.readLines()}
println(inputString)

 

파일처리 : 쓰기

파일 읽기처럼 파일 쓰기도 스트림과 라이터로 구성되어 있다.

보통 Writer는 파일 쓰기 등을 지원하는 클래스이다.

 

FileWriter의 인자에 파일 경로를 전달해서 파일을 생성한다.

이를 다시 BufferedWriter에 전달해서 버퍼로 만든 후에 파일을 작성하고 다 작성되면 파일을 닫는다.

val content = "코틀린 세상~"
val fileName = "studyKotlin.txt"
val fw = FileWriter(fileName)
val writer = BufferedWriter(fw)

writer.append(content)
writer.flush() // 메모리에 있는 것 쓰기
writer.close()

val lines = File(fileName).readLines()
println(lines)

// 코틀린 세상~

 

파일 접근과 NIO 처리

파일에 접근할 때 버퍼, 비동기 방식을 지원하는 새로운 패키지인 nio 패키지를 사용한다.

Path메서드를 사용해 경로 등을 확인한 후에 이 파일의 존재 여부 등 다양한 메서드로 파일의 정보를 확인할 수 있다.

 

2. 스레드

컴퓨터에서 프로그램을 처리하는 방식은 오퍼레이팅 시스템의 프로세스와 스레드를 사용한 실행환경을 작동시키는 것이다.

JVM은 기본으로 멀티스레드 방식으로 실행된다. 

  • 프로세스(Process) : 특정 프로그램을 태스크로 보고 이 태스크를 실행 단위로 처리한다.
  • 스레드(Thread) : 프로세스 내부에서 작은 단위로 실행할 수 있는 기능을 한다.
  • 프로세스의 자원을 사용해서 자기 스레드가 실행되는 동안 다른 스레드를 처리하지 못하게 블로킹(block-ing)한다.
  • 프로세스는 보통 기본 메인 스레드와 다른 작업을 실행하는 별도의 스레드로 관리된다.

스레드를 처리할 때 사용되는 주요 메서드

start : 실제 스레드 환경을 구성한 환경을 실행하는 메서드. 이 메서드를 실행해야 내부에 있는 run 메서드가 실행된다

run : 스레드 클래스를 정의할 때 내부에서 살행될 코드를 작성하는 메서드.

join : 스레드가 실행된 다음 종료할 때까지 기다린다.

sleep : 스레드를 잠시 중단하고 다른 스레드를 처리한 후 다시 자기 스레드를 작동할 수 있게 만든다.

 

스레드 생성

Thread를 상속하고 run을 재정의한다.

스레드를 처리할 때 메인 스레드가 먼저 종료할 수 있으므로 현재 진행 중인 스레드가 모두 처리될 때까지 기다리기 위해 join 메서드를 실행한다.

실행 결과를 보면 메인 스레드와 보조 스레드를 사용해서 각각의 기능을 처리한 것을 볼 수 있다.

fun exec(tr: Thread){ // 스레드 내부에서 실행할 함수 정의
    println("$tr : 보조 스레드 작동중 ")
}

class MyThread : Thread(){ // 스레드 클래스를 상속
    override fun run(){
        val tr = Thread.currentThread()  // 함수 실행 스레드 확인
        exec(tr)
        println("$tr : 보조 스레드 종료 ")
    }
}

fun main(){
    val mtr = Thread.currentThread() // 현재 스레드 확인
    println("$mtr : 메인 스레드 작동중")

    val myThread = MyThread() // 스레드 객체 생성
    myThread.start() // 스레드 실행

    exec(myThread)
    
    println("$mtr : 대기중") // 스레드가 다 처리하면 출력
    myThread.join() // 보조 스레드 종료 대기
}

// Thread[#1,main,5,main] : 메인 스레드 작동중
// Thread[#21,Thread-0,5,main] : 보조 스레드 작동중 
// Thread[#21,Thread-0,5,main] : 보조 스레드 작동중 
// Thread[#21,Thread-0,5,main] : 보조 스레드 종료 
// Thread[#1,main,5,main] : 대기중

 

스레드 풀 사용

스레드를 무작정 만들면 컴퓨터의 자원을 너무 많이 사용한다.

시스템의 가용할 자원 범위를 벗어날 경우는 더 이상 스레드를 만들 수 없어서 메모리 에러가 발생한다.

특정 개수의 스레드를 풀(pool)을 만들어서 특정 스레드를 계속 할용한다.

 

/* 스레드 풀 */
val executor = Executors.newFixedThreadPool(2) // 특정 스레드 개수만큼만 사용한느 풀을 만듬
var count = 0
repeat(3) {
    executor.execute {
        Thread.sleep(10) // 스레드 임시 지연처리
        println(Thread.currentThread().name)
        count += 1
        println(count)
    }
}
println(executor.isTerminated) // 스레드 풀 미종료
executor.shutdown() // 스레드 풀 종료
println(executor.isShutdown) // 스레드 풀 종료 확인

// false
// true
// pool-1-thread-1
// 1
// pool-1-thread-2
// 2
// pool-1-thread-2
// 3

'Study > Kotlin' 카테고리의 다른 글

Kotlin/ 알고리즘 스터디  (0) 2024.01.14
Kotlin / 코루틴 처리  (0) 2023.11.12
Kotlin / 제네릭 알아보기  (0) 2023.10.22
Kotlin / 위임(delegation) 알아보기  (0) 2023.09.24
Kotlin / 함수 추가사항 알아보기  (0) 2023.09.17