Scala

Scala와 Java에서 일반적인 파일 입출력

partner_jun 2017. 5. 11. 17:58

자바는 1.7부터 PathsFiles 클래스를 이용해 이전보다 훨씬 간편하게 파일 입출력이 가능해졌다.



1. Path 객체

// 상대주소나 절대주소를 이용한 Path
Path path = Paths.get("/resources/test.txt");

// URI를 이용한 Path
ClassLoader classLoader = FileInputOutputJava.class.getClassLoader();
URL url = classLoader.getResource("test.txt");
Path resourcePath = Paths.get(url.toURI()); // throw URISyntacException

Paths.get() 메소드를 이용해 직접 파일의 위치를 입력하거나 URI 객체를 이용해 파일을 입력 받아 Path 객체를 만들 수 있다.



2. 자바 1.7의 Files 클래스를 이용한 입출력

앞서 만든 Path 객체를 Files 클래스의 메소드 파라미터로 사용해 파일을 읽어오거나 쓸 수 있다.

/* 파일 읽기 */
// List로 읽기
List<String> lines = Files.readAllLines(resourcePath); // IOException
lines.forEach(System.out::println);

// Byte로 읽기
byte[] bytes = Files.readAllBytes(resourcePath);

// Stream으로 읽기
Stream<String> stream = Files.lines(path);


/* 파일 쓰기 */
List<String> result = Arrays.asList("Hello", "World", "!!!");
Files.write(writePath, result, StandardOpenOption.CREATE);

파일을 쓸 때 작성하는 Files.write() 메소드의 마지막 파라미터는 파일 쓰기 옵션으로 파일을 새로 만들거나 덧붙이기, 혹은 삭제같은 옵션을 선택할 수 있다. 자세한 옵션들 공식 문서를 참조하자.


예제에서 볼 수 있듯 파일의 라인들을 List나 Stream, 바이트로 읽어낼 수 있다. 그 뿐 아니라 이전 버전에서 작성된 코드나 특별한 용도로 쓰이는 BufferedReader나 InputStream으로도 읽어 올 수 있다.

//BufferedReader
BufferedReader bufferedReader = Files.newBufferedReader(path);

// InputStream
InputStream inputStream = Files.newInputStream(path);



3. 스칼라에서 파일 읽기

스칼라에는 자바의 Files 클래스와 비슷한 Source Object가 있다.

// URI로 읽기
val uri = getClass.getResource("/test.txt").toURI
val sourceFromUri = Source.fromFile(uri)

// Resources에서 명시적으로 읽기
val sourceFromResource = Source.fromResource("test.txt")

// 절대 / 상대 주소로 만든 File 객체에서 읽기
val file = new File("/test.txt")
val sourceFromFile = Source.fromFile(file)


값을 읽어오는 방법도 자바의 Files와 비슷하다.

// Source에서 Iterator 문자열 얻어오기
val lines: Iterator[String] = source.getLines()
lines.foreach(println)

// BufferedReader 얻어오기
val sourceBufferedReader = source.bufferedReader()


하지만 스칼라의 SourceFiles와 다르게 바이트 배열로 얻어올 수 있는 메소드가 없다. 대신 URL에 접속해 Body를 가져오는 메소드가 있다(쓸모는 없다). 

val html = Source.fromURL("http://www.naver.com")
// 오버로드된 다른 메소드에서는 코덱이나 인코딩 타입을 입력받는다.
println(html)



4. 스칼라에서 자바 1.7의 Files 사용하기

스칼라의 Source Object는 간단한 문자열 파일을 읽어오는데는 좋지만 FIles만큼 다양한 기능은 없다. 심지어 파일 쓰기도 불가능하다. 때문에 자바의 FIles 클래스를 사용하면 편해지는 경우가 많다.


1) 스칼라 Collection을 자바 Collection으로 변환하기

Files자바 Collection을 파라미터로 입력받으므로 변환이 필요하다.

val lst = Seq("Hello", "World", "!!!")

// Scala List -> Java List
val javaList: java.util.List[String] = JavaConverters.seqAsJavaList(lst)

// Java List -> Scala List
val scalaList: List[String] = JavaConverters.asScalaIterator(javaList.iterator())
.toList

JavaConverters Object를 보면 짐작할 수 있듯 List 외의 다른 Collection도 자바 Collection으로 변환할 수 있다. 다른 메소드들은 공식문서를 참조하자. 메소드 이름과 파라미터 목록을 보면 직관적으로 사용할 수 있다.



2) Path 객체 만들고 파일 쓰기

자바에서와 마찬가지로 Path 객체를 만들고 그 Path 객체를 이용해 파일을 읽거나 쓸 수 있다.

// URI로 Path 만들기
val uriPath = Paths.get(uri)
val writePath1 = Paths.get(uriPath.getParent.toString, "resultByScala.txt")

// 절대 / 상대 주소로 Path 만들기
val writePath2 = Paths.get("./", "resultByScala.txt")


Files.write(writePath1, javaList, StandardOpenOption.CREATE)