Nice programing

StreamWriter 및 UTF-8 바이트 순서 표시

nicepro 2021. 1. 5. 21:09
반응형

StreamWriter 및 UTF-8 바이트 순서 표시


StreamWriter 및 Byte Order Marks에 문제가 있습니다. 문서에는 Encoding.UTF8 인코딩에 바이트 순서 표시가 활성화되어 있지만 파일이 작성 될 때 일부는 표시가 있고 다른 일부는 표시되지 않는다고 설명하는 것 같습니다.

다음과 같은 방법으로 스트림 작성기를 만들고 있습니다.

this.Writer = new StreamWriter(this.Stream, System.Text.Encoding.UTF8);

무슨 일이 일어날 수 있는지에 대한 아이디어를 주시면 감사하겠습니다.


누군가 이미 지적했듯이 인코딩 인수없이 호출하면 트릭이 발생합니다. 그러나 명시 적으로 표현하려면 다음을 시도하십시오.

using (var sw = new StreamWriter(this.Stream, new UTF8Encoding(false)))

핵심은 Encoding.UTF8Encoding을 사용하는 대신 새로운 UTF8Encoding (false)을 생성하는 것입니다. 이는 BOM 추가 여부를 제어하는 ​​것입니다.

이것은 인코딩 인수없이 StreamWriter를 호출하는 것과 동일하며 내부적으로는 동일한 작업을 수행합니다.


이 문제는 클래스 의 정적 UTF8속성사용하고 있기 때문입니다 .Encoding

속성이 반환 한 클래스 의 인스턴스 에서 GetPreamble메서드 가 호출 되면 바이트 순서 표시 (3 자 바이트 배열)를 반환하고 다른 내용이 스트림에 기록되기 전에 스트림에 기록됩니다 (새 스트림이라고 가정). ).EncodingUTF8

다음 과 같이 UTF8Encoding클래스 의 인스턴스를 직접 생성하여이를 방지 할 수 있습니다 .

// As before.
this.Writer = new StreamWriter(this.Stream, 
    // Create yourself, passing false will prevent the BOM from being written.
    new System.Text.UTF8Encoding());

기본 매개 변수가없는 생성자에 대한 문서에 따라 (강조 내) :

이 생성자 는 유니 코드 바이트 순서 표시를 제공하지 않는 인스턴스를 만들고 잘못된 인코딩이 감지 될 때 예외를 throw하지 않습니다.

이것은에 대한 호출이 GetPreamble빈 배열을 반환하므로 BOM이 기본 스트림에 기록되지 않음을 의미합니다.


내 답변은 필요한 모든 정보가 포함 된 HelloSam의 답변을 기반으로합니다. OP가 요구하는 것은 BOM이 파일로 내보내 지는지 확인하는 방법 뿐이라고 생각합니다.

따라서 UTF8Encoding ctor에 false를 전달하는 대신 true를 전달해야합니다.

    using (var sw = new StreamWriter("text.txt", new UTF8Encoding(true)))

아래 코드를 시도하고 16 진 편집기에서 결과 파일을 열고 BOM이 포함 된 파일과 포함되지 않은 파일을 확인하십시오.

class Program
{
    static void Main(string[] args)
    {
        const string nobomtxt = "nobom.txt";
        File.Delete(nobomtxt);

        using (Stream stream = File.OpenWrite(nobomtxt))
        using (var writer = new StreamWriter(stream, new UTF8Encoding(false)))
        {
            writer.WriteLine("HelloПривет");
        }

        const string bomtxt = "bom.txt";
        File.Delete(bomtxt);

        using (Stream stream = File.OpenWrite(bomtxt))
        using (var writer = new StreamWriter(stream, new UTF8Encoding(true)))
        {
            writer.WriteLine("HelloПривет");
        }
    }

생성자가 UTF-8 BOM을 추가하지 않는 것을 본 유일한 경우는 호출 할 때 스트림이 위치 0에 있지 않은 경우입니다. 예를 들어, 아래 코드에서 BOM은 작성되지 않았습니다.

using (var s = File.Create("test2.txt"))
{
    s.WriteByte(32);
    using (var sw = new StreamWriter(s, Encoding.UTF8))
    {
        sw.WriteLine("hello, world");
    }
}

다른 사람들이 말했듯 StreamWriter(stream)이 인코딩을 지정하지 않고 생성자를 사용하는 경우 BOM이 표시되지 않습니다.


Do you use the same constructor of the StreamWriter for every file? Because the documentation says:

To create a StreamWriter using UTF-8 encoding and a BOM, consider using a constructor that specifies encoding, such as StreamWriter(String, Boolean, Encoding).

I was in a similar situation a while ago. I ended up using the Stream.Write method instead of the StreamWriter and wrote the result of Encoding.GetPreamble() before writing the Encoding.GetBytes(stringToWrite)


I found this answer useful (thanks to @Philipp Grathwohl and @Nik), but in my case I'm using FileStream to accomplish the task, so, the code that generates the BOM goes like this:

using (FileStream vStream = File.Create(pfilePath))
{
    // Creates the UTF-8 encoding with parameter "encoderShouldEmitUTF8Identifier" set to true
    Encoding vUTF8Encoding = new UTF8Encoding(true);
    // Gets the preamble in order to attach the BOM
    var vPreambleByte = vUTF8Encoding.GetPreamble();

    // Writes the preamble first
    vStream.Write(vPreambleByte, 0, vPreambleByte.Length);

    // Gets the bytes from text
    byte[] vByteData = vUTF8Encoding.GetBytes(pTextToSaveToFile);
    vStream.Write(vByteData, 0, vByteData.Length);
    vStream.Close();
}

Seems that if the file already existed and didn't contain BOM, then it won't contain BOM when overwritten, in other words StreamWriter preserves BOM (or it's absence) when overwriting a file.


Could you please show a situation where it don't produce it ? The only case where the preamble isn't present that I can find is when nothing is ever written to the writer (Jim Mischel seem to have find an other, logical and more likely to be your problem, see it's answer).

My test code :

var stream = new MemoryStream();
using(var writer = new StreamWriter(stream, System.Text.Encoding.UTF8))
{
    writer.Write('a');
}
Console.WriteLine(stream.ToArray()
    .Select(b => b.ToString("X2"))
    .Aggregate((i, a) => i + " " + a)
    );

ReferenceURL : https://stackoverflow.com/questions/5266069/streamwriter-and-utf-8-byte-order-marks

반응형