¿Escribir archivos de texto sin marca de orden de bytes (BOM)?

116

Estoy tratando de crear un archivo de texto usando VB.Net con codificación UTF8, sin BOM. ¿Alguien puede ayudarme, cómo hacer esto?
Puedo escribir un archivo con codificación UTF8 pero, ¿cómo eliminar la marca de orden de bytes?

edit1: He probado un código como este;

    Dim utf8 As New UTF8Encoding()
    Dim utf8EmitBOM As New UTF8Encoding(True)
    Dim strW As New StreamWriter("c:\temp\bom\1.html", True, utf8EmitBOM)
    strW.Write(utf8EmitBOM.GetPreamble())
    strW.WriteLine("hi there")
    strW.Close()

        Dim strw2 As New StreamWriter("c:\temp\bom\2.html", True, utf8)
        strw2.Write(utf8.GetPreamble())
        strw2.WriteLine("hi there")
        strw2.Close()

1.html se crea con codificación UTF8 solamente y 2.html se crea con formato de codificación ANSI.

Enfoque simplificado: http://whatilearnttuday.blogspot.com/2011/10/write-text-files-without-byte-order.html

Vijay Balkawade
fuente
8
Si no desea una lista de materiales, ¿por qué está escribiendo GetPreamble ()?
Hans Passant

Respuestas:

200

Para omitir la marca de orden de bytes (BOM), su flujo debe usar una instancia UTF8Encodingdiferente a System.Text.Encoding.UTF8(que está configurada para generar una BOM). Hay dos formas sencillas de hacer esto:

1. Especificar explícitamente una codificación adecuada:

  1. Llame al UTF8Encodingconstructor con Falsepara el encoderShouldEmitUTF8Identifierparámetro.

  2. Pase la UTF8Encodinginstancia al constructor de la secuencia.

' VB.NET:
Dim utf8WithoutBom As New System.Text.UTF8Encoding(False)
Using sink As New StreamWriter("Foobar.txt", False, utf8WithoutBom)
    sink.WriteLine("...")
End Using
// C#:
var utf8WithoutBom = new System.Text.UTF8Encoding(false);
using (var sink = new StreamWriter("Foobar.txt", false, utf8WithoutBom))
{
    sink.WriteLine("...");
}

2. Usando la codificación predeterminada:

Si no proporciona un constructor de Encodingto StreamWriteren absoluto, StreamWriterutilizará de forma predeterminada una codificación UTF8 sin BOM, por lo que lo siguiente debería funcionar igual de bien:

' VB.NET:
Using sink As New StreamWriter("Foobar.txt")
    sink.WriteLine("...")
End Using
// C#:
using (var sink = new StreamWriter("Foobar.txt"))
{
    sink.WriteLine("...");
}

Finalmente, tenga en cuenta que omitir la lista de materiales solo está permitido para UTF-8, no para UTF-16.

stakx - ya no contribuye
fuente
No siempre es prudente: por ejemplo, My.Computer.FileSystem.WriteAllTextescribe la lista de materiales si no se especifica ninguna codificación.
beppe9000
My.Computer.FileSystem.WriteAllText¿Es una excepción en este sentido, adivinando la compatibilidad con versiones anteriores de VB quizás? File.WriteAllTextpor defecto es UFT8NoBOM.
jnm2
28

Prueba esto:

Encoding outputEnc = new UTF8Encoding(false); // create encoding with no BOM
TextWriter file = new StreamWriter(filePath, false, outputEnc); // open file with encoding
// write data here
file.Close(); // save and close it
Roman Nikitin
fuente
6

Simplemente use el método WriteAllTextde System.IO.File.

Consulte la muestra de File.WriteAllText .

Este método usa codificación UTF-8 sin una marca de orden de bytes (BOM), por lo que el uso del método GetPreamble devolverá una matriz de bytes vacía. Si es necesario incluir un identificador UTF-8, como una marca de orden de bytes, al principio de un archivo, utilice la sobrecarga del método WriteAllText (String, String, Encoding) con codificación UTF8.

Joe.wang
fuente
El del espacio de nombres Mi usa BOM
beppe9000
4

Nota interesante con respecto a esto: extrañamente, el método estático "CreateText ()" de la clase System.IO.File crea archivos UTF-8 sin BOM.

En general, esta es la fuente de errores, pero en su caso podría haber sido la solución más simple :)

Tao
fuente
4

Si no especifica un Encodingal crear uno nuevo, StreamWriterel Encodingobjeto predeterminado utilizado es el UTF-8 No BOMque se crea mediante new UTF8Encoding(false, true).

Entonces, para crear un archivo de texto sin el uso de BOM de los constructores que no requieren que proporciones una codificación:

new StreamWriter(Stream)
new StreamWriter(String)
new StreamWriter(String, Boolean)
JG en SD
fuente
¿Qué pasa si necesito especificar leaveOpen?
binki
@binki en ese caso no puede usar la codificación predeterminada que StreamWriterusa. Deberá especificar new UTF8Encoding(false, true)que su codificación pueda especificar leaveOpeny no tener la lista de materiales.
JG en SD
3

Creo que Roman Nikitin tiene razón. El significado del argumento del constructor se invierte. Falso significa que no hay lista de materiales y verdadero significa con lista de materiales.

Obtiene una codificación ANSI porque un archivo sin una lista de materiales que no contiene caracteres no ansi es exactamente lo mismo que un archivo ANSI. Pruebe algunos caracteres especiales en su cadena "hola" y verá que la codificación ANSI cambia a sin BOM.

jos
fuente
1

Codificación XML UTF-8 sin BOM
Necesitamos enviar datos XML a la EPA y su aplicación que toma nuestra entrada requiere UTF-8 sin BOM. Oh, sí, el UTF-8 simple debería ser aceptable para todos, pero no para la EPA. La respuesta para hacer esto está en los comentarios anteriores. Gracias Roman Nikitin .

A continuación, se muestra un fragmento de código C # para la codificación XML:

    Encoding utf8noBOM = new UTF8Encoding(false);  
    XmlWriterSettings settings = new XmlWriterSettings();  
    settings.Encoding = utf8noBOM;  
          
    using (XmlWriter xw = XmlWriter.Create(filePath, settings))  
    {  
        xDoc.WriteTo(xw);  
        xw.Flush();  
    }    

Ver si esto realmente elimina los tres caracteres principales del archivo de salida puede ser engañoso. Por ejemplo, si usa Notepad ++ (www.notepad-plus-plus.org), informará "Codificar en ANSI". Supongo que la mayoría de los editores de texto cuentan con los caracteres BOM para saber si es UTF-8. La forma de ver esto claramente es con una herramienta binaria como WinHex (www.winhex.com). Como buscaba un antes y un después, utilicé la aplicación Microsoft WinDiff .

Jerry Banasik
fuente
-1

Es posible que su texto de entrada contenga una marca de orden de bytes. En ese caso, debe eliminarlo antes de escribir.


fuente
1
Por favor ayúdame. Cómo quitarlo antes de escribir.
Vijay Balkawade
@ user180326 ¿el lector predeterminado ya no lo filtra por usted?
binki
-1
Dim sWriter As IO.StreamWriter = New IO.StreamWriter(shareworklist & "\" & getfilename() & ".txt", False, Encoding.Default)

Te da resultados como los que quieres (creo).

Mwenyeji
fuente
1
En mi PC crea archivos ANSI
Muflix