Read a file to a String
You do not need to create a method for this. The recommended way to read an entire file for a String
is next :
String dados = new String(Files.readAllBytes(file.toPath()));
Preferably, specify an encoding to avoid problems with special characters:
String dados = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
Problems with some implementations
Concatenating Strings
One of the answers offers:
public static String addItemCreative(File f) {
String line, lines = "";
try {
BufferedReader br = new BufferedReader(new FileReader(f));
while ((line = br.readLine()) != null) {
lines += line;
}
} catch (Exception e) {
e.getMessage();
}
return lines;
}
This is not good because each concatenation of two strings generates a third and the memory is consumed exponentially. If the file is large, this will force the garbage collector to run multiple times, pausing the execution of the program and leading to very poor performance.
Correct is to use StringBuilder
in local implementations, which is a class that allows you to concatenate strings without the need for object synchronization. @Cantoni's answer provides an example of how to do this.
Line breaks
If the file has line breaks, you are ignoring them when joining in the String. When calling the readLine
method Java does not include breaks.
If you want the contents of the String to be the same as the one in the file, you must concatenate the breaks manually.
Calling readLine
more than once
In the question implementation, the readLine
method is called twice. If the file contains a single line, the second call will return null
.
If the file has more rows, the result will be a String with the odd rows of the file.
Handling Exceptions
The exception that should be caught is IOException
. Do not capture more generic exceptions unnecessarily. You may end up covering up for errors.
In addition, calling the getMessage
method does nothing. At a minimum vocie should print the error log to understand what is happening. For example:
} catch(IOException e) {
e.printStackTrace();
}
Or catch the error and do something about it
} catch(IOException e) {
String erro = e.getMessage();
mostraErro(erro);
}
Failed to close file
In Java it's easy to forget that not all allocated resources are automatically released.
When opening a file for reading or writing, remember to close the file afterwards.
This can be done using the close
method of one of the Reader
ployments used or automatically through try-with-resources
of Java 6. Example:
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
...
}
In the code above, the close
method of BufferedReader
will be automatically invoked at the end of block try
.
Good practices in general
Use variables in the smallest possible scope. Instead of declaring the variable line
at the beginning of the method, it can be inside the block try
and in catch
you return null directly. Reusing variables can be confusing.
A possible implementation putting together everything I described above would be:
String quebra = System.getProperty("line.separator");
public String addItemCreative(File f) {
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
StringBuilder sb = new StringBuilder();
String line;
while((line = br.readLine()) != null){
sb.append(line);
sb.append(quebra);
}
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Optional return
If you want to go beyond and semantically reinforce that the method has an optional return, for example if the file does not exist or is empty, you can use the new Java 8 interfaces as Optional
.
These interfaces prevent you from using null
to specify no value. This avoids many NullPointerException
s for lack of attention, since it forces the client code to check if a value returned by the method exists.
Example:
String quebra = System.getProperty("line.separator");
public Optional<String> addItemCreative(File f) {
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
StringBuilder sb = new StringBuilder();
String line;
while((line = br.readLine()) != null){
sb.append(line);
sb.append(quebra);
}
return sb.length() > 0 ? Optional.of(sb.toString()) : Optional.empty();
} catch (IOException e) {
e.printStackTrace();
return Optional.empty();
}
}
Now it's easy for someone who calls the method to know that it can not return some value.
Assuming you wanted to print the content. The method could be used like this:
Optional<String> conteudo = addItemCreative(arquivo);
if (conteudo.isPresent()) {
imprimir(conteudo.get());
} else {
imprimir("[arquivo vazio]");
}
Still, if you prefer a more functional format:
imprimir(addItemCreative(arquivo).orElse("[arquivo vazio]"));