android에 파일을 저장 할 수 있는 곳은 내부저장소/외부저장소 가 있다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val am = resources.assets //resource Manager : Provides access to an application's raw asset files
try {
val inputStream = am.open("food_1.csv", AssetManager.ACCESS_BUFFER)
// accessMode를 이용해서 asset 읽기. 내용을 읽기 위해 inputStream 을 리턴
val br = BufferedReader((InputStreamReader(inputStream, Charset.forName("UTF-16"))))
//리턴받은 InputStream(데이터가 전송되는 통로, 1byte 씩만 읽어옴. 한글 처리 x)의 byte를 "UTF-16"방식으로 처리 하겠다. - 한글 처리위해
//괄호 안에서 처리한 inputstreamReader을 char 단위로 buffer을 이용해 읽겠다. - char로 처리 되어 있으므로 BufferdReader로 읽을 수 있음
//(BufferdReader는 char 단위로 처리. BufferedInputStream은 byte 단위로처리)
val list = br.use(BufferedReader::readLines)
//br의 메소드인 readLines로 모든 라인을 읽어오자
//보다시피 한줄 한줄이 리스트 요소로 들어간다.
br.close()
//stream을 닫고 memory leak 이 일어나지 않게 한다.
} catch (e: IOException) {
e.printStackTrace();
}
}
AssetManager.open() 메소드의 accessMode
- ACCESS_BUFFER : 빠르고 작은 읽기 (버퍼를 이용하니까 그런듯?)
- ACCESS_RANDOM : chunk 단위로 읽기. 앞뒤를 탐색
- ACCESS_STREAMING : 순서대로 읽기. 때때로 앞을 탐색
- ACCESS_UNKOWN : 데이터를 어떻게 접근할지 모를 때
지금은 inputStream을 열고 , 파일을 읽고, inputStream을 닫을때 모두 하나의 try-catch 에서 실행했지만,
1. 파일을 열어 정상적으로 읽었으나 Stream을 닫을 때 에러 발생의 경우
2. 파일을 찾지 못했을 경우
3. 파일을 찾았으나 읽지 못했을 경우
4. 파일을 찾았은 읽지 못하여 fileStream을 닫으려고 했으나 닫지 못했을 경우
를 각각 try-catch 처리해줘야한다고 한다.
참고 : FileReader 은 inputStreamReader을 상속받았다. 따라서, inputStreamReader처럼 char을 기준으로 읽는다.- bufferReader 이용
byte를 기준으로 읽고 싶다면, FileInputStream을 사용. - BufferedInputStream 이용
fun main() {
val br = BufferedReader(//char 단위로 처리.
(InputStreamReader( //inputStream의 byte단위를 char단위로 변환시키는 중개자
FileInputStream("파일이 있는 위치/파일이름.확장자"), //파일을 바이트 단위로 읽어서 inputStream 만듬
Charset.forName("UTF-16")
))
)
//여기서 의문점이 생겼다.
//FileInputStream(바이트 단위의 스트림)을 만들고 InputStreamReader로 byte >char 단위로 스트림을 변환하는
//이중 처리를 하는 이유가 궁금했다.
//FileReader를 이용하면 바로 char 단위로 파일을 읽는 inputStream을 만들 수 있는데 말이다.
//하지만 직접 해보니..
//FileReader는 인코딩을 지정할 수가 없다!(자바 11에서는 가능하다고함. 하지만 나는 1.8을 쓰고있지.)
//그래서 굳이 이중처리를 해야함에도 불구하고,
//FileInputStream로 바이트단위 but, 인코딩 지정가능 스트림 >> InputStreamReader로 char단위 스트림
//이렇게 스트림을 만들어 주는 것 같다!!!
// val br = BufferedReader((FileReader("파일위치/파일이름.확장자")))
val list = br.use(BufferedReader::readLines)
br.close()
list.forEach {
println(it)
}
}
private fun writeCSV() {
try {
val map = mapOf("키" to "맵")
val bw =
BufferedWriter(FileWriter(("파일위치/파일이름.확장자"), true))
//fileWriter/BufferedWriter - char 단위로 파일 작성
//append - true : 기존 파일 내용 냅두고 그 다음줄 부터 쓴다. false : 기존 파일 내용 날리고 덮어쓴다(새로쓴다)
//바이트 단위로 파일을 쓰고싶다면 > FileOutputStream . BufferedOutputStream 이용
val iterator = map.iterator()
while (iterator.hasNext()) {
val word = iterator.next()
bw.write("${word.key},${word.value}")
bw.newLine()
bw.flush()
//버퍼의 내용을 파일에 write 한다.
//flush()를 호출하지 않는다면 내용이 버퍼에만 남고 파일에는 쓰이지 않는 상황이 됨.
}
bw.close()
//close 호출은 스트림을 닫는 역할.
// 스트림을 닫으면 그 스트림을 다시 이용하여 파일에 쓰는 것이 불가능
} catch (e: Exception) {
println(e)
}
}