The problem is on this line:
r = (char) fin.read();
But before you understand, consider the code below:
int x = (char) -1;
System.out.println(x);
The code above prints 65535
. This happens basically because the literal -1
is a int
(that in Java takes 32 bits), and in doing cast for char
(which only has 16 bits), the extra bits are "lost".
Only that int
is a guy Signed (with signal, allows representing positive and negative numbers) and char
is unsigned (no signal, only represents positive numbers). That is, although bytes are the same, the way they are interpreted can change. In a very concise way, the -1
is represented with all bits equal to 1 (according to complement rule 2). In doing cast for char
, the extra bits are "lost", but there are still 16 bits left equal to 1. But as char
is unsigned, this is interpreted as the number 65535. And this is the value that r
receives in your code.
That is, your while
never ends, because r
will never be equal to -1
.
To solve, just don’t do the cast:
while ((r = fin.read()) != -1) {
if (r == ' ')
fout.write('-');
else fout.write(r);
}
After all, if you look at the documentation, you will see that read
returns a int
and write
gets a int
as parameter. There is no need to do the cast, not least because int
and char
are "interchangeable":
int x = ' ';
System.out.println(x); // 32 - valor do espaço na tabela ASCII
x = 32;
// imprime como char
System.out.println("[" + (char) x + "]"); // [ ]
System.out.println(x == ' '); // true
Another detail is that the way you are closing the files is wrong. To ensure that they are closed, place calls from close
in a block finally
:
FileInputStream fin = null;
FileOutputStream fout = null;
try {
fin = new FileInputStream("origin.txt");
fout = new FileOutputStream("destiny.txt");
int r;
while ((r = fin.read()) != -1) {
if (r == ' ')
fout.write('-');
else
fout.write(r);
}
} catch (IOException exc) {
System.out.println("Error while copying the files");
} finally {
try {
if (fin != null)
fin.close();
} catch (IOException exc) {
System.out.println("Error while closing the files");
}
try {
if (fout != null)
fout.close();
} catch (IOException exc) {
System.out.println("Error while closing the files");
}
}
So you ensure that the files will be closed at the end.
Or, from Java 7, prefer to use a block Try-with-Resources, which already closes everything automatically, without the need for a block finally
:
try (FileInputStream fin = new FileInputStream("origin.txt");
FileOutputStream fout = new FileOutputStream("destiny.txt")) {
int r;
while ((r = fin.read()) != -1) {
if (r == ' ')
fout.write('-');
else
fout.write(r);
}
} catch (IOException exc) {
System.out.println("Error while copying the files");
}
Another option is to use a BufferedReader
to read multiple characters at once, instead of reading one by one:
char[] buffer = new char[1024];
try (Reader in = new BufferedReader(new FileReader("origin.txt"));
Writer out = new BufferedWriter(new FileWriter("destiny.txt"))) {
int lidos;
while ((lidos = in.read(buffer)) != -1) {
for (int i = 0; i < lidos; i++) {
if (buffer[i] == ' ')
buffer[i] = '-';
}
out.write(buffer, 0, lidos);
}
} catch (IOException exc) {
System.out.println("Error while copying the files");
}
Or, if the file is not too large, you can also upload all the content into one String
, replace and write it in the other file:
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Path origin = Paths.get("origin.txt");
Charset charset = StandardCharsets.UTF_8; // escolha o encoding no qual o arquivo está
String content = new String(Files.readAllBytes(origin), charset);
Files.write(Paths.get("destiny.txt"), content.replaceAll(" ", "-").getBytes(charset));
For the above code, I used the bundle java.nio.file