2

I'm working on a function to process some data and output the results as a csv file. I am using a 'use' block to wrap the function and ensure all the resources are closed. the problem I am running into is that I want the function to return the newly created File to the caller. The use block has the ability to return a value, however since it is being called with a bufferedWriter, there is no ability to actually return the File object from inside the block. Can anyone offer suggestions on how to solve this?

I want to do something like:

fun List<Contact>.buildCsv():File
{
    return File("people.csv").bufferedWriter(Charsets.ISO_8859_1).use { out ->

            out.write("a,b,c,d\n")
            this.forEach {
                out.write(it.toString())
            }
        }

}

but that code does not compile.

3
  • 2
    You can't return a File in Java. It's not what you think. The functionality of that class is really to manipulate paths and the like. It really has little to do with the actual content of a file system. If you really want to return a 'file' you would do well to think of it as returning a stream to the actual content (and all that entails) Commented Mar 26 at 20:44
  • I am not very familiar with Kotlin, but I would use a library over just trying to create CSV content the way you are doing it. If things get complicated, your output will pay the price. Commented Mar 26 at 21:12
  • I'd recommend you don't tie yourself to Files and hence the file system. It gets messy when unit testing. (You do write unit tests, right?) Instead of a File, pass an OutputStream or a StreamWriter. In a test you can pass one that collects what gets written in a byte array or string. In real life, you can still pass a stream that writes to a file. But this decouples I/O from the logic in your buildCsv function. Commented Mar 26 at 22:44

2 Answers 2

3

You can use some builtin scope functions such as apply, also, etc.

An example:

fun List<Contact>.buildCsv() = File("people.csv").apply {
    bufferedWriter(Charsets.ISO_8859_1).use { out ->
        out.write("a,b,c,d\n")
        forEach { out.write("$it") }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

The Kotlin ideomatic way to this.
This answer would be perfect if it included strong advice to use one of the many CSV libraries available, instead of manually writing the content.
2

How about:

fun List<Contact>.buildCsv(): File {
    val file = File("people.csv")

    file.bufferedWriter(Charsets.ISO_8859_1).use { out ->
        out.write("a,b,c,d\n")
        this.forEach {
            out.write(it.toString())
        }
    }

    return file
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.