Gravar arquivos de texto sem Byte Order Mark (BOM)?

116

Estou tentando criar um arquivo de texto usando VB.Net com codificação UTF8, sem BOM. Alguém pode me ajudar, como fazer isso?
Posso escrever arquivos com codificação UTF8, mas como remover a marca de ordem de bytes dele?

edit1: Eu tentei um 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 criado apenas com codificação UTF8 e 2.html criado com formato de codificação ANSI.

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

Vijay Balkawade
fonte
8
Se você não quer um BOM, por que está escrevendo GetPreamble ()?
Hans Passant

Respostas:

200

Para omitir a marca de ordem de byte (BOM), seu fluxo deve usar uma instância UTF8Encodingdiferente de System.Text.Encoding.UTF8(que é configurada para gerar um BOM). Existem duas maneiras fáceis de fazer isso:

1. Especificando explicitamente uma codificação adequada:

  1. Chame o UTF8Encodingconstrutor com Falsepara o encoderShouldEmitUTF8Identifierparâmetro.

  2. Passe a UTF8Encodinginstância para o construtor de fluxo.

' 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 a codificação padrão:

Se você não fornecer um Encodingpara StreamWriter's construtor em tudo, StreamWritervai pelo uso padrão uma codificação UTF8 sem BOM, então o seguinte deve funcionar tão bem:

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

Por fim, observe que omitir o BOM só é permitido para UTF-8, não para UTF-16.

stakx - não contribui mais
fonte
Nem sempre sábio: por exemplo, My.Computer.FileSystem.WriteAllTextgrava o BOM se nenhuma codificação for especificada.
beppe9000
My.Computer.FileSystem.WriteAllTexté uma exceção a este respeito, adivinhando para compatibilidade com VB com versões anteriores, talvez? File.WriteAllTexto padrão é UFT8NoBOM.
jnm2
28

Experimente isto:

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
Nikitin Romano
fonte
6

Simplesmente use o método WriteAllTextde System.IO.File.

Verifique o exemplo de File.WriteAllText .

Este método usa a codificação UTF-8 sem uma marca de ordem de bytes (BOM), portanto, o uso do método GetPreamble retornará uma matriz de bytes vazia. Se for necessário incluir um identificador UTF-8, como uma marca de ordem de byte, no início de um arquivo, use a sobrecarga do método WriteAllText (String, String, Encoding) com codificação UTF8.

Joe.wang
fonte
O do namespace My usa BOM
beppe9000
4

Observação interessante a respeito disso: estranhamente, o método estático "CreateText ()" da classe System.IO.File cria arquivos UTF-8 sem BOM.

Em geral, esta é a fonte de bugs, mas no seu caso poderia ter sido a solução mais simples :)

Tao
fonte
4

Se você não especificar um Encodingao criar um novo, StreamWritero Encodingobjeto padrão usado é aquele UTF-8 No BOMcriado por meio de new UTF8Encoding(false, true).

Portanto, para criar um arquivo de texto sem o uso de BOM dos construtores que não exigem que você forneça uma codificação:

new StreamWriter(Stream)
new StreamWriter(String)
new StreamWriter(String, Boolean)
JG em SD
fonte
E se eu precisar especificar leaveOpen?
binki
@binki nesse caso você não pode usar a codificação padrão que StreamWriterusa. Você precisará especificar new UTF8Encoding(false, true)para que sua codificação seja capaz de especificar leaveOpene não ter o BOM.
JG em SD de
3

Acho que Roman Nikitin está certo. O significado do argumento do construtor é invertido. Falso significa sem BOM e verdadeiro significa com BOM.

Você obtém uma codificação ANSI porque um arquivo sem um BOM que não contém caracteres não-ansi é exatamente o mesmo que um arquivo ANSI. Experimente alguns caracteres especiais em sua string "hi there" e você verá a codificação ANSI mudar para sem BOM.

Jos
fonte
1

Codificação XML UTF-8 sem BOM
Precisamos enviar dados XML ao EPA e seu aplicativo que recebe nossa entrada requer UTF-8 sem BOM. Sim, o UTF-8 simples deve ser aceitável para todos, mas não para o EPA. A resposta para fazer isso está nos comentários acima. Obrigado Roman Nikitin .

Aqui está um snippet C # do código para a codificação 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 se isso realmente remove os três caracteres principais do arquivo de saída pode ser enganoso. Por exemplo, se você usar o Notepad ++ (www.notepad-plus-plus.org), ele irá relatar “Encode in ANSI”. Eu acho que a maioria dos editores de texto está contando com os caracteres BOM para saber se é UTF-8. A maneira de ver isso claramente é com uma ferramenta binária como WinHex (www.winhex.com). Como estava procurando uma diferença entre o antes e o depois, usei o aplicativo Microsoft WinDiff .

Jerry Banasik
fonte
-1

Pode ser que o texto de entrada contenha uma marca de ordem de bytes. Nesse caso, você deve removê-lo antes de escrever.


fonte
1
Por favor me ajude. Como removê-lo antes de escrever.
Vijay Balkawade
@ user180326 o leitor padrão já não filtra isso para você?
binki
-1
Dim sWriter As IO.StreamWriter = New IO.StreamWriter(shareworklist & "\" & getfilename() & ".txt", False, Encoding.Default)

Dá os resultados que você deseja (eu acho).

Mwenyeji
fonte
1
No meu PC, ele cria arquivos ANSI
Muflix