C# How to write one byte at an offset? - c#

Im trying to write a single byte at a certain location in a file. This is what im using at the moment:
BinaryWriter bw = new BinaryWriter(File.Open(filename, FileMode.Open));
bw.BaseStream.Seek(0x6354C, SeekOrigin.Begin);
bw.Write(0xB0);
bw.Close();
The problem is that BinaryWriter.Write(args) writes a four-byte signed integer at the position. I wish to only write one byte at the particular location. And then later possibly two bytes else where, how I specify how many bytes to write?

change
bw.Write(0xB0);
to
bw.Write((byte)0xB0);

There is absolutely no need to use a high-level BinaryWriter just to write a simple byte to a stream - It's more efficient and tidy just to do this:
Stream outStream = File.Open(filename, FileMode.Open);
outStream.Seek(0x6354C, SeekOrigin.Begin);
outStream.WriteByte(0xb0);
(In general you also shouldn't really Seek after attaching a BinaryWriter to your stream - the BinaryWriter should be in control of the stream, and changing things "behind its back" is a bit dirty)

You could cast to byte:
bw.Write((byte)0xB0);
This should cause the correct overloaded version of Write to be invoked.

Related

Write float array into a binary file c#

I have a float array :
float[] samples32array
I need to convert it into a binary file so I can read it in matlab.
Is there any way to do that?
It's simple. First, you should use FileStream and create a file. Then, you can use BinaryWriter, which can write any C# datatype into an underlaying stream, such as a FileStream.
using (FileStream file = File.Create(path))
{
using (BinaryWriter writer = new BinaryWriter(file))
{
foreach (float value in samples32array)
{
writer.Write(value);
}
}
}
Since the constructor of BinaryWriter accepts the basic type Stream, any stream type can be used. It works for file streams as well as NetworkStream or a MemoryStream etc. It's a very generic class.
And please avoid converting the float[] into a byte[] beforehand as it will allocate memory and this is bad if your array is big (don't know if that's the case for you).
You can use BinaryWriter to write the data to a file very easily:
foreach (var value in samples32array)
{
writer.Write(value);
}
Now BinaryWriter is guaranteed to use little-endian format, so in your Matlab call, you should specify a machinefmt value of l to explicitly read it in little-endian format too.
This SO answer shows a way to convert a float array into a byte array. Then you can use File.WriteAllBytes() method to write it out to a file. How MatLab reads it, though, will be the issue.
I found some documentation for MatLab for the fread command. It looks like is has some arguments that will allow you to define the precision of the read. You may be able to use "float" as the precision value. Though, the is a bit of an educated guess as I am not very familiar with MatLab.

Unexpected MemoryStream behavior

I am reading and writing to the same MemoryStream.
Something like this(possible compilation mistakes):
MemoryStream stream = new MemoryStream();
stream.Write("1234",0,4);
stream.Position -= 4;
stream.Read(buffer,0,4);
Why do I HAVE to move Position? Why it is not separate to read and write?
Is there any other Stream that can be used?
Because that's how streams are supposed to work. You have one position, see it as a cursor, set at a point in the stream at which you can read or write. Reading and writing both advance this position.
If you're merely using a MemoryStream to exchange data between callers, as a pseudo IPC mechanism, then perhaps some better way exists to do so.

How to write data at a particular position in c#?

I am making an application in c#. In that application I have one byte array and I want to write that byte array data to particular position.
Here i used the following logic.
using(StreamWriter writer=new StreamWriter(#"D:\"+ FileName + ".txt",true))
{
writer.WriteLine(Encoding.ASCII.GetString(Data),IndexInFile,Data.Length);
}
But whenever i am writing data in file, it starts writing from starting.
My condition is that suppose at the initial I have empty file and I want to start writing in file from position 10000. Please help me .Thanks in advance.
Never try to write binary data as strings, like you do. It won't work correctly. Write binary data as binary data. You can use Stream for that instead of StreamWriter.
using (Stream stream = new FileStream(fileName, FileMode.OpenOrCreate))
{
stream.Seek(1000, SeekOrigin.Begin);
stream.Write(Data, 0, Data.Length);
}
You can set the position inside the stream like this:
writer.BaseStream.Seek( 1000, SeekOrigin.Begin);
Add this before your WriteLine code.
Note that I have not included any code to check that there is at least 1000 chars inside the file to start with.
The WriteLine overload you are using is this one:
TextWriter.WriteLine Method (Char[], Int32, Int32)
In particular the IndexInFile argument supplied is actually the index in the buffer from which to begin reading not the index in the file at which to begin writing - this explains why you are writing at the start of the file not at IndexInFile as you expect.
You should obtain access to the underlying Stream and Seek to the desired position in the file first and then write to the file.
Maybe a bit hacky, but you can access the BaseStream property of the StreamWriter and use Seek(long offset, SeekOrigin origin) on it. (But be warned, as not every stream can use Seek.)

Loading XML into a memorystream

SO I am trying to get a simple dataset from the strInstallDataSet string into the dataset, using the code below, when I have the debugger connected I can see that strInstallDataSet has data, byteArray has data, but even after reading msDataset has nothing, length just sits at 0, I have tried setting the position before and after reading but it still just doesn't pick up any data. Any ideas?
MemoryStream msDataset = new MemoryStream();
if (strInstallDataSet != null)
{
// Convert string to byte array.
byte[] byteArray = Encoding.ASCII.GetBytes(strInstallDataSet);
msDataset.Read(byteArray, 0, byteArray.Length);
// Put stream back into dataset object.
dsInstallData.ReadXml(msDataset);
msDataset.Close();
msDataset.Dispose();
}
You probably want to be doing the following:
using(StringReader reader = new StringReader(strInstallDataSet))
{
dsInstallData.ReadXml(reader);
}
You are not writing anything to the stream, only reading msDataset.Read...
Side note 1: you are using very low level methods - there are Reader/Writer classes that will correctly take care of encoding already.
Side note 2: use "using" instead of manually calling Close or Dispose (and don't call 2 of them together as both do exactly the same things).
You're misunderstanding what the MemoryStream.Read() does, it reads into the byte array, not into the memorystream.
You want MemoryStream.Write() where you have MemoryStream.Read()
Or better yet...
MemoryStream xmlMemoryStream = new MemoryStream(byteArray);
You must use Write method instead of read. I think you want to write your bytearray into your memory stream.

Why does BinaryWriter prepend gibberish to the start of a stream? How do you avoid it?

I'm debugging some issues with writing pieces of an object to a file and I've gotten down to the base case of just opening the file and writing "TEST" in it. I'm doing this by something like:
static FileStream fs;
static BinaryWriter w;
fs = new FileStream(filename, FileMode.Create);
w = new BinaryWriter(fs);
w.Write("test");
w.Close();
fs.Close();
Unfortunately, this ends up prepending a box to the front of the file and it looks like so:
TEST, with a fun box on the front. Why is this, and how can I avoid it?
Edit: It does not seem to be displaying the box here, but it's the unicode character that looks like gibberish.
They are not byte-order marks but a length-prefix, according to MSDN:
public virtual void Write(string value);
Writes a length-prefixed string to
[the] stream
And you will need that length-prefix if you ever want to read the string back from that point. See BinaryReader.ReadString().
Additional
Since it seems you actually want a File-Header checker
Is it a problem? You read the length-prefix back so as a type-check on the File it works OK
You can convert the string to a byte[] array, probably using Encoding.ASCII. But hen you have to either use a fixed (implied) length or... prefix it yourself. After reading the byte[] you can convert it to a string again.
If you had a lot of text to write you could even attach a TextWriter to the same stream. But be careful, the Writers want to close their streams. I wouldn't advice this in general, but it is good to know. Here too you will have to mark a Point where the other reader can take over (fixed header works OK).
That's because a BinaryWriter is writing the binary representation of the string, including the length of the string. If you were to write straight data (e.g. byte[], etc.) it won't include that length.
byte[] text = System.Text.Encoding.Unicode.GetBytes("test");
FileStream fs = new FileStream("C:\\test.txt", FileMode.Create);
BinaryWriter writer = new BinaryWriter(fs);
writer.Write(text);
writer.Close();
You'll notice that it doesn't include the length. If you're going to be writing textual data using the binary writer, you'll need to convert it first.
The byte at the start is the length of the string, it's written out as a variable-length integer.
If the string is 127 characters or less, the length will be stored as one byte. When the string hits 128 characters, the length is written out as 2, and it will move to 3 and 4 at some lengths as well.
The problem here is that you're using BinaryWriter, which writes out data that BinaryReader can read back in later. If you wish to write out in a custom format of your own, you must either drop writing strings like that, or drop using BinaryWriter altogether.
As Henk pointed out in this answer, this is the length of the string (as a 32-bit int).
If you don't want this, you can either write "TEST" manually by writing the ASCII characters for each letter as bytes, or you could use:
System.Text.Encoding.UTF8.GetBytes("TEST")
And write the resulting array (which will NOT contain a length int)
What you're seeing is actually a 7 bit encoded integer, which is a kind of integer compression.
The BinaryWriter prepend the text with this so readers (i.e. BinaryReader) will know how long the written string is.
BinaryWriter.Write7BitEncodedInt
BinaryReader.Read7BitEncodedInt
You can read more about the implementation details of this at http://dpatrickcaldwell.blogspot.se/2011/09/7-bit-encoding-with-binarywriter-in-net.html.
You can save it as a UTF8 encoded byte array like this:
...
BinaryWriter w = new BinaryWriter(fs);
w.Write(UTF8Encoding.Default.GetBytes("test"));
...
That's a byte order mark, most likely. It's because the stream's encoding is set to Unicode.
Remember that Java strings are internally encoded in UTF-16.
So, "test" is actually made of the bytes 0xff, 0xfe (together the byte order mark), 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00.
You probably want to work with bytes instead of streams of characters.
Sounds like byte order marks.
http://en.wikipedia.org/wiki/Byte-order_mark
Perhaps you want to write the string as UTF-8.

Categories