Hay varios factores en juego aquí:
- Los archivos de texto no tienen metadatos intrínsecos para describir su codificación (para todo lo que se habla de impuestos de escuadras angulares, hay motivos XML es popular)
- La codificación por defecto para Windows sigue siendo una de 8 bits (o doublebyte) carácter "ANSI" set con un rango limitado de valores - archivos de texto escritos en este formato no son portátiles
- para contar un archivo Unicode de una Archivo ANSI, las aplicaciones de Windows se basan en la presencia de un byte order mark al comienzo del archivo (not strictly true - Raymond Chen explains). En teoría, la lista de materiales está allí para decirle el endianess (orden de bytes) de los datos. Para UTF-8, aunque solo hay un orden de bytes, las aplicaciones de Windows dependen de los bytes del marcador para descubrir automáticamente que es Unicode (aunque observará que el Bloc de notas tiene una opción de codificación en sus diálogos de abrir/guardar).
- Es incorrecto decir que Java está roto porque no escribe una BOM UTF-8 automáticamente. En sistemas Unix, sería un error escribir una BOM en un archivo de script, por ejemplo, y muchos sistemas Unix usan UTF-8 como su codificación predeterminada. Hay momentos en los que no desea que en Windows, o bien, como cuando estás añadir datos a un archivo existente:
fos = new FileOutputStream(FileName,Append);
Aquí es un método fiable de añadir datos UTF-8 en un archivo:
private static void writeUtf8ToFile(File file, boolean append, String data)
throws IOException {
boolean skipBOM = append && file.isFile() && (file.length() > 0);
Closer res = new Closer();
try {
OutputStream out = res.using(new FileOutputStream(file, append));
Writer writer = res.using(new OutputStreamWriter(out, Charset
.forName("UTF-8")));
if (!skipBOM) {
writer.write('\uFEFF');
}
writer.write(data);
} finally {
res.close();
}
}
Uso:
public static void main(String[] args) throws IOException {
String chinese = "\u4E0A\u6D77";
boolean append = true;
writeUtf8ToFile(new File("chinese.txt"), append, chinese);
}
Nota: si el archivo ya existía y se optó por añadir y los datos existentes no era codificación UTF-8, la única cosa que el código w crear mal es un desastre.
Aquí es el tipo Closer
utilizado en este código:
public class Closer implements Closeable {
private Closeable closeable;
public <T extends Closeable> T using(T t) {
closeable = t;
return t;
}
@Override public void close() throws IOException {
if (closeable != null) {
closeable.close();
}
}
}
Este código hace una mejor estimación de estilo de Windows acerca de cómo leer el archivo basado en marcas de orden de bytes:
private static final Charset[] UTF_ENCODINGS = { Charset.forName("UTF-8"),
Charset.forName("UTF-16LE"), Charset.forName("UTF-16BE") };
private static Charset getEncoding(InputStream in) throws IOException {
charsetLoop: for (Charset encodings : UTF_ENCODINGS) {
byte[] bom = "\uFEFF".getBytes(encodings);
in.mark(bom.length);
for (byte b : bom) {
if ((0xFF & b) != in.read()) {
in.reset();
continue charsetLoop;
}
}
return encodings;
}
return Charset.defaultCharset();
}
private static String readText(File file) throws IOException {
Closer res = new Closer();
try {
InputStream in = res.using(new FileInputStream(file));
InputStream bin = res.using(new BufferedInputStream(in));
Reader reader = res.using(new InputStreamReader(bin, getEncoding(bin)));
StringBuilder out = new StringBuilder();
for (int ch = reader.read(); ch != -1; ch = reader.read())
out.append((char) ch);
return out.toString();
} finally {
res.close();
}
}
Uso :
public static void main(String[] args) throws IOException {
System.out.println(readText(new File("chinese.txt")));
}
(System.out utiliza la codificación predeterminada, por lo que si se imprime nada Sensi ble depende de su plataforma y configuration.)
posible duplicado de [Qué es la codificación de caracteres y por qué debería molestarme con él] (http://stackoverflow.com/questions/10611455/what-is-character-encoding-and -por qué-debería-molestar-con-eso) – Raedwald