Search code examples
c#filestreamstreamwriterbinarywriter

Writing string and bytes to the same FileStream


I need to create a file where some parts are strings (utf-8), while some parts are bytes.

I tinkered for hours with StreamWriter and BinaryWriter, but this is the only thing that works:

        using (var stream = new FileStream(_caminho, FileMode.Create, FileAccess.Write))
        {
            using (var writer = new StreamWriter(stream))
            {
                writer.Write(myString);
            }   
        }
        using (var stream = new FileStream(_caminho, FileMode.Append, FileAccess.Write))
        {
            using (var writer = new BinaryWriter(stream))
            {
                writer.Write(oneSingleByte);
            }
        }

The problem is that I have to close the FileStream and open another one just to write a single byte, because either the BinaryStream.Write(string) method prepends a "length" field (undesired in my case) or the StreamWriter.Write(byte) encodes the byte value instead of actually writing directly.

My question is: is there another class I can use so that I can create the FileStream only once, and write my string and my byte one after another?


Solution

  • BinaryWriter prefixes written data so BinaryReader can read it. Without those prefixes, you must know exactly what you're doing when writing and reading the file.

    You can omit both writers and directly write into the file if that's what you want:

    using (var stream = new FileStream(_caminho, FileMode.Append, FileAccess.Write))
    {
        stream.WriteByte('0'); 
        WriteString(stream, "foo", Encoding.UTF8);
    }
    
    private void WriteString(Stream stream, string stringToWrite, Encoding encoding)
    {
        var charBuffer = encoding.GetBytes(stringToWrite);
        stream.Write(charBuffer, 0, charBuffer.Length);
    }
    

    You'll need to explicitly specify the encoding to get the bytes in, as String.ToByteArray returns the string as Unicode characters, which is .NET language for "UTF-16LE", giving you two bytes per character.