One comment about your code:
It is generally regarded as incorrect to check whether a file exists before reading from it. That's because of a potential race condition, where the existence of the file can change after you check, but before the read happens. The better approach is to try reading the file, and examine the error, if there is one. Or, if you are creating a new file, you would just try writing to it, and examine any error to find out if the file already existed.
>> how does it handle LARGE FILES?
It's kind of up to you. If you use the String class to do reading and writing, it's likely that the entire file is going to be read and converted to a String in memory. (The String is in memory, the file's raw data isn't necessarily all in memory, since files can be read with memory mapping.) This is probably fine for strings up to several megabytes.
For very large files, you probably need to read the raw data yourself, and create the string in pieces (which, depending on your app, might not need to all be in memory at once). This is not trivial, though, because of the complexities of decoding UTF-8 — you must divide the file at points which don't break into any multi-byte sequences. Because of the way UTF-8 is designed, you can (for example) scan forward or backward in file data until you find a CR or LF character, and break there.
But such optimizations are very sensitive to your app's constraints. Sometimes doing the simple, obvious thing is best, sometimes you have to work hard. There is no single answer.