I'm trying to recieve a tcp packet in C# but I don't know when can I stop reading from the stream.
Here's what I've tried:
for(int i = 0; i < stm.Length; i += chunkSize)
{
bb = new byte[chunkSize];
k = stm.Read(bb, 0, bb.Length);
ns.Write(bb, 0, k);
}
But it threw me an error about that the stream is not seekable.
So I've tried this:
int k = chunkSize;
while (k == chunkSize)
{
bb = new byte[chunkSize];
k = stm.Read(bb, 0, bb.Length);
ns.Write(bb, 0, k);
}
Is there anything to do?
Thanks :)
Here we go:
int read;
while((read = stm.Read(bb, 0, bb.Length)) > 0) {
// process "read"-many bytes from bb
ns.Write(bb, 0, read);
}
"read" will be non-positive at the end of the stream, and only at the end of the stream.
Or more simply (in 4.0):
stm.CopyTo(ns);
a binary reader is what you would require since it knows exactly how many bytes to read!
It prefixes the length of the bytes and so it knows how much to read!
Related
I am trying to use binary writer/reader to serialize and deserialize a 2D array, this is the code I am using for this:
public class Connect4BoardData : ASerializable
{
public int[,] board = new int[6, 7] {
{ 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0} };
public int rows = 6, columns = 7;
public override void Serialize(Packet pPacket)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
pPacket.Write(board[i, j]);
}
}
}
public override void Deserialize(Packet pPacket)
{
rows = 6;
columns = 7;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
board[i, j] = pPacket.ReadInt();
}
}
}
}
When I eventually try to read it however, it just doesn't work. I seem to get a [42, 1] array instead, and I honestly do not understand why it happens. If I try array.GetLength(1), I get an "index out of bounds exception for some reason, but I am still able to access array[x, 0], where x is 0 to 41. Moreover when I attempted to write and read columns and rows in the methods, it read them as
rows = 6, columns = 70000000000000 ...
The code to write and read ints is as follows:
public void Write (int pInt) { writer.Write(pInt); }
public int ReadInt() { return reader.ReadInt32(); }
with writer and reader assigned like this:
private BinaryWriter writer; //only used in write mode, to write bytes into a byte array
private BinaryReader reader; //only used in read mode, to read bytes from a byte array
/**
* Create a Packet for writing.
*/
public Packet()
{
//BinaryWriter wraps a Stream, in this case a MemoryStream, which in turn wraps an array of bytes
writer = new BinaryWriter(new MemoryStream());
}
/**
* Create a Packet from an existing byte array so we can read from it
*/
public Packet (byte[] pSource)
{
//BinaryReader wraps a Stream, in this case a MemoryStream, which in turn wraps an array of bytes
reader = new BinaryReader(new MemoryStream(pSource));
}
EDIT: Serialize and Deserialize is called like this:
public void Write (ASerializable pSerializable) {
//write the full classname into the stream first
Write(pSerializable.GetType().FullName);
//then ask the serializable object to serialize itself
pSerializable.Serialize(this);
}
public ASerializable ReadObject()
{
//get the classname from the stream first
Type type = Type.GetType(ReadString());
//create an instance of it through reflection (requires default constructor)
ASerializable obj = (ASerializable)Activator.CreateInstance(type);
obj.Deserialize(this);
return obj;
}
Everything else I write and read works fine, 1D arrays, strings, booleans. I hope I provided enough info and context, but if not let me know and I'll update the question ASAP, its quite a large assignment.
And one more thing, I am not going to be using BinaryFormatter for this, its an assignment that requires BianryWriter/Reader, so please don't recommend this in answers
Thank you!
Send an array of bytes
public static void SendFile(string path)
{
byte[] data = File.ReadAllBytes(path);
stream.Write(data, 0, data.Length);
}
Getting the byte array
List<byte> list = new List<byte>();
byte[] data = new byte[64];
int bytes = 0;
do
{
bytes = stream.Read(data, 0, data.Length);
for (int i = 0; i < data.Length; i++)
{
list.Add(data[i]);
}
} while (stream.DataAvailable);
return list.ToArray();
Creating a file
byte[] file = ReciveFile().ToArray();
File.WriteAllBytes(message, file);
Appear extra characters like these
before
after
How to fix? Thanks
You need to check how many bytes were read. Otherwise the end of your buffer may contain garbage if the file's length isn't an exact multiple of 64.
do
{
bytes = stream.Read(data, 0, data.Length);
for (int i = 0; i < bytes; i++) //use bytes, not data.Length
{
list.Add(data[i]);
}
} while (bytes > 0);
Hi i currently use the following code to split a file into muliple 2mb smaller parts.
const int BUFFER_SIZE = 20 * 1024;
byte[] buffer = new byte[BUFFER_SIZE];
using (Stream input = File.OpenRead(inputFile)) {
int index = 0;
while (input.Position < input.Length) {
using (Stream output = File.Create(path)) {
int remaining = chunkSize, bytesRead;
while (remaining > 0 && (bytesRead = input.Read(buffer, 0,
Math.Min(remaining, BUFFER_SIZE))) > 0) {
output.Write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
}
}
index++;
}
This works perfectly, and will split a 10mb file into 5 x 2mb files 0.part,2.part ect...
I would like to know how I would generate just part 3 again knowing the chunkSize always stays at 2mb. I can achieve this by wrapping in an if,else and evaluating index, but with a 1GB file this process can take a while to loop through. I'd like to understand this function more and how I can just get the part of the file I require?
input.Position property is settable. If you know that you need part 3, set Position to 2*chunkSize to skip the first two chunks, and do the innermost while loop once to copy from that position to the output:
int desiredChunkNumber = 3;
using (Stream input = File.OpenRead(inputFile)) {
input.Position = (desiredChunkNumber - 1) * chunkSize;
using (Stream output = File.Create(path)) {
int remaining = chunkSize, bytesRead;
while (remaining > 0 && (bytesRead = input.Read(buffer, 0,
Math.Min(remaining, BUFFER_SIZE))) > 0) {
output.Write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
}
}
I have a MemoryStream which is created from a File at runtime.
Then the MemoryStream is edited and some bytes are removed.
Now I have to maintain a Constant Filesize so I have to fill the MemoryStream with 0xFF bytes..
What is the Fastest way to Do this Operation?
I know, that I always can loop through the MemoryStream sizes and add 0xFF's but I need to know a faster and more efficient way to do it!
If you have many bytes to write to the stream, it may be more efficient to write a array rather than each byte individually:
static void Fill(this Stream stream, byte value, int count)
{
var buffer = new byte[64];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = value;
}
while (count > buffer.Length)
{
stream.Write(buffer, 0, buffer.Length);
count -= buffer.Length;
}
stream.Write(buffer, 0, count);
}
The Microsoft website has the code snippet:
using (FileStream fsSource = new FileStream(pathSource,
FileMode.Open, FileAccess.Read))
{
// Read the source file into a byte array.
byte[] bytes = new byte[fsSource.Length];
int numBytesToRead = (int)fsSource.Length;
int numBytesRead = 0;
while (numBytesToRead > 0)
{
// Read may return anything from 0 to numBytesToRead.
int n = fsSource.Read(bytes, numBytesRead, numBytesToRead);
// Break when the end of the file is reached.
if (n == 0)
break;
numBytesRead += n;
numBytesToRead -= n;
}
}
What concerns me is that fsSource.Length is a long, whereas numBytesRead is an int so at most only 2 * int.MaxValue can be read into bytes (the head and the tail of the stream). So my questions are:
Is there some reason that this is OK?
If not, how should you read a FileStream into a byte[].
In this situation I wouldn't even bother processing the FileStream manually; use File.ReadAllBytes instead:
byte[] bytes = File.ReadAllBytes(pathSource);
To answer your question:
The sample code is good for most of applications where we are not reaching extremes.
If you have really long stream like say a video, use BufferedStream. Sample code is available at MSDN site
Example using ReadAllBytes:
private byte[] m_cfgBuffer;
m_cfgBuffer = File.ReadAllBytes(m_FileName);
StringBuilder PartNbr = new StringBuilder();
StringBuilder Version = new StringBuilder();
int i, j;
byte b;
i = 356; // We know that the cfg file header ends at position 356 (1st hex(80))
b = m_cfgBuffer[i];
while (b != 0x80) // Scan for 2nd hex(80)
{
i++;
b = m_cfgBuffer[i];
}
// Now extract the part number - 6 bytes after hex(80)
m_PartNbrPos = i + 5;
for (j = m_PartNbrPos; j < m_PartNbrPos + 6; j++)
{
char cP = (char)m_cfgBuffer[j];
PartNbr.Append(cP);
}
m_PartNbr = PartNbr.ToString();
// Now, extract version number - 6 bytes after part number
m_VersionPos = (m_PartNbrPos + 6) + 6;
for (j = m_VersionPos; j < m_VersionPos + 2; j++)
{
char cP = (char)m_cfgBuffer[j];
Version.Append(cP);
}
m_Version = Version.ToString();