How can I get the length of a StreamReader, as I know nothing will be written to it anymore.
I thought that maybe I could pass all the data to a MemoryStream, which has a method called Length, but I got stuck on how to append a byte[] to a MemoryStream.
private void Cmd(string command, string parameter, object stream)
{
StreamWriter writer = (StreamWriter)stream;
StreamWriter input;
StreamReader output;
Process process = new Process();
try
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.FileName = "cmd";
process.Start();
input = process.StandardInput;
output = process.StandardOutput;
input.WriteLine(command + " " + parameter);
input.WriteLine("exit");
using (MemoryStream ms = new MemoryStream())
{
int length = 1024;
char[] charbuffer = new char[length];
byte[] bytebuffer = new byte[length];
while (!output.EndOfStream)
{
output.Read(charbuffer, 0, charbuffer.Length);
for (int i = 0; i < length; i++)
{
bytebuffer[i] = Convert.ToByte(charbuffer[i]);
}
//append bytebuffer to memory stream here
}
long size = ms.Length;
writer.WriteLine(size);
writer.Flush(); //send size of the following message
//send message
}
}
catch (Exception e)
{
InsertLog(2, "Could not run CMD command");
writer.WriteLine("Not valid. Ex: " + e.Message);
}
writer.Flush();
}
So, how can I dinamically append a byte[] to a MemoryStream?
There is any way better than this to get the length of output so I can warn the other end about the size of the message which will be sent?
Does this work for you?
StreamReader sr = new StreamReader(FilePath);
long x = sr.BaseStream.Length;
Stream has a Length property, but will throw an exception if the stream doesn't support seek operations. A network stream for example will throw an exception if you try to read .Length. In your code, you're processing an input stream of a process. Consider if that were user input - how would you know the length until you were completely finished reading?
If you're reading a file, you can get the length with stream.Length.
In .NET 4+, you can copy one stream to another with Stream.CopyTo, eg:
inputStream.CopyTo(outputStream);
You can also load the bytes into memory with:
byte[] data;
using (var ms = new MemoryStream())
{
stream.CopyTo(ms);
data = ms.ToArray();
}
MemoryStream has MemoryStream.Write Method , which writes a byte array to the stream:
ms.Write(bytebuffer,0,bytebuffer.Length);
So, you can call it to add another portion of bytes to the output stream. However remember, to be able to read from MemoryStream after all write operations are over, you'll have to use MemoryStream.Seek Method to set the position within the current stream to its beginning:
//all write operations
ms.Seek(0, SeekOrigin.Begin);
//now ready to be read
This is the easiest approach. Of cousre, you may dynamically move across the stream, while reading/writing. But that may be error prone.
To get the length of the stream, i.e. ms.Length, you don't have to seek the begining of the stream.
I guess, it's worth to note, that if bytebuffer is used only to store bytes before copying them into the MemoryStream, you could use MemoryStream.WriteByte Method instead. This would let you abolish bytebuffer at all.
for (int i = 0; i < length; i++)
{
ms.WriteByte(Convert.ToByte(charbuffer[i]));
}
Related
From SharePoint, I get a "Stream" for a file. I want to copy this entire file from the internet to a local file on the PC, but I want to have status while this download is occurring. How? FileStream and StreamReader seem to have bytes vs char differences when not doing a full "CopyTo" which doesn't have progress updates. There has to be a cleaner way...
using (var sr = new StreamReader(fileData.Value))
{
using (FileStream fs = new FileStream(localFile + "_tmp", FileMode.Create))
{
byte[] block = new byte[1024];
// only guessing something like this is necessary...
int count = (int)Math.Min(sr.BaseStream.Length - sr.BaseStream.Position, block.Length);
while (sr.BaseStream.Position < sr.BaseStream.Length)
{
// read requires char[]
sr.Read(block, 0, count);
// write requires byte[]
fs.Write(block, 0, count);
Log("Percent complete: " + (sr.BaseStream.Position / sr.BaseStream.Length));
count = (int)Math.Min(sr.BaseStream.Length - sr.BaseStream.Position, block.Length);
}
}
}
Just had to use BinaryReader instead of StreamReader. Easy Peasy.
I'm trying to parse messages sent from a server that's compressed using zlib, but I'm not sure how to do so with C#'s implementation of async sockets. I'm using Microsoft's example for async client socket.
https://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx
I'm guessing the correct place to do the inflation is here:
private static void ReceiveCallback( IAsyncResult ar ) {
....
string bufferedString = Encoding.ASCII.GetString(state.buffer,0,bytesRead);
....
}
I've tried passing state.buffer as the input parameter to the following function along with bytesRead as the length, but this results in a System.IO.IOException: Corrupted data ReadInternal exception.
public static string UnZip(byte[] byteArray, int length)
{
//Prepare for decompress
System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray);
System.IO.Compression.GZipStream sr = new System.IO.Compression.GZipStream(ms,
System.IO.Compression.CompressionMode.Decompress);
//Reset variable to collect uncompressed result
byteArray = new byte[length];
//Decompress
int rByte = sr.Read(byteArray, 0, byteArray.Length);
//Transform byte[] unzip data to string
System.Text.StringBuilder sB = new System.Text.StringBuilder(rByte);
//Read the number of bytes GZipStream red and do not a for each bytes in
//resultByteArray;
for (int i = 0; i < rByte; i++)
{
sB.Append((char)byteArray[i]);
}
sr.Close();
ms.Close();
sr.Dispose();
ms.Dispose();
return sB.ToString();
}
How can I inflate the contents of state.buffer?
I'm using a memory reader to read a file and put it in a MemoryStream. The MemoryStream is populated, and I'm trying to read with the BinaryReader because the endianness of the file change, so I use a Binary reader that can detect the endianness.
When I use BinaryReader.Read or BinaryReader.ReadString or BinaryReader.ReadByte, it reads the correct data, but when I use ReadInt16 or the other like that, I don't get the correct data. Is it possible to use those, I made a mistake, or should I make something to use Read() instead?
The code:
MemoryStream ms = new MemoryStream();
object[] binMakerNoteObj = exif.findTag(37500).data;
byte[] binMakerNote = binMakerNoteObj.Cast<byte>().ToArray();
ms.Write(binMakerNote, 0, binMakerNote.Length);
ms.Position = 0;
// Read the header
string t = "";
for(int i = 0; i < 6; i ++)
t += fileStream.ReadChar();
version = fileStream.ReadUInt16();
unknow = fileStream.ReadUInt16();
byteOrder = fileStream.ReadUInt16();
Need help with sending and receiving compressed data over TCP socket.
The code works perfectly fine if I don't use compression, but something very strange happens when I do use compression.. Basically, the problem is that the stream.Read() operation gets skipped and I don't know why..
My code:
using (var client = new TcpClient())
{
client.Connect("xxx.xxx.xx.xx", 6100);
using (var stream = client.GetStream())
{
// SEND REQUEST
byte[] bytesSent = Encoding.UTF8.GetBytes(xml);
// send compressed bytes (if this is used, then stream.Read() below doesn't work.
//var compressedBytes = bytesSent.ToStream().GZipCompress();
//stream.Write(compressedBytes, 0, compressedBytes.Length);
// send normal bytes (uncompressed)
stream.Write(bytesSent, 0, bytesSent.Length);
// GET RESPONSE
byte[] bytesReceived = new byte[client.ReceiveBufferSize];
// PROBLEM HERE: when using compression, this line just gets skipped over very quickly
stream.Read(bytesReceived, 0, client.ReceiveBufferSize);
//var decompressedBytes = bytesReceived.ToStream().GZipDecompress();
//string response = Encoding.UTF8.GetString(decompressedBytes);
string response = Encoding.UTF8.GetString(bytesReceived);
Console.WriteLine(response);
}
}
You will notice some extension methods above. Here is the code in case you are wondering if something is wrong there.
public static MemoryStream ToStream(this byte[] bytes)
{
return new MemoryStream(bytes);
}
public static byte[] GZipCompress(this Stream stream)
{
using (var memoryStream = new MemoryStream())
{
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress))
{
stream.CopyTo(gZipStream);
}
return memoryStream.ToArray();
}
}
public static byte[] GZipDecompress(this Stream stream)
{
using (var memoryStream = new MemoryStream())
{
using (var gZipStream = new GZipStream(stream, CompressionMode.Decompress))
{
gZipStream.CopyTo(memoryStream);
}
return memoryStream.ToArray();
}
}
The extensions work quite well in the following, so I'm sure they're not the problem:
string original = "the quick brown fox jumped over the lazy dog";
byte[] compressedBytes = Encoding.UTF8.GetBytes(original).ToStream().GZipCompress();
byte[] decompressedBytes = compressedBytes.ToStream().GZipDecompress();
string result = Encoding.UTF8.GetString(decompressedBytes);
Console.WriteLine(result);
Does anyone have any idea why the Read() operation is being skipped when the bytes being sent are compressed?
EDIT
I received a message from the API provider after showing them the above sample code. They had this to say:
at a first glance I guess the header is missing. The input must start
with a 'c' followed by the length of the input
(sprintf(cLength,"c%09d",hres) in our example). We need this because
we can't read until we find a binary 0 to recognize the end.
They previously provided some sample code in C, which I don't fully understand 100%, as follows:
example in C:
#include <zlib.h>
uLongf hres;
char cLength[COMPRESS_HEADER_LEN + 1] = {'\0'};
n = read(socket,buffer,10);
// check if input is compressed
if(msg[0]=='c') {
compressed = 1;
}
n = atoi(msg+1);
read.....
hres = 64000;
res = uncompress((Bytef *)msg, &hres, (const Bytef*)
buffer/*compressed*/, n);
if(res == Z_OK && hres > 0 ){
msg[hres]=0; //original
}
else // errorhandling
hres = 64000;
if (compressed){
res = compress((Bytef *)buffer, &hres, (const Bytef *)msg, strlen(msg));
if(res == Z_OK && hres > 0 ) {
sprintf(cLength,"c%09d",hres);
write(socket,cLength,10);
write(socket, buffer, hres);
}
else // errorhandling
makefile: add "-lz" to the libs
They're using zlib. I don't suspect that to make any difference, but I did try using zlib.net and I still get no response anyway.
Can someone give me an example of how exactly I'm supposed to send this input length in C#?
EDIT 2
In response to #quantdev, here is what I am trying now for the length prefix:
using (var client = new TcpClient())
{
client.Connect("xxx.xxx.xx.xx", 6100);
using (var stream = client.GetStream())
{
// SEND REQUEST
byte[] bytes = Encoding.UTF8.GetBytes(xml);
byte[] compressedBytes = ZLibCompressor.Compress(bytes);
byte[] prefix = Encoding.UTF8.GetBytes("c" + compressedBytes.Length);
byte[] bytesToSend = new byte[prefix.Length + compressedBytes.Length];
Array.Copy(prefix, bytesToSend, prefix.Length);
Array.Copy(compressedBytes, 0, bytesToSend, prefix.Length, compressedBytes.Length);
stream.Write(bytesToSend, 0, bytesToSend.Length);
// WAIT
while (client.Available == 0)
{
Thread.Sleep(1000);
}
// GET RESPONSE
byte[] bytesReceived = new byte[client.ReceiveBufferSize];
stream.Read(bytesReceived, 0, client.ReceiveBufferSize);
byte[] decompressedBytes = ZLibCompressor.DeCompress(bytesReceived);
string response = Encoding.UTF8.GetString(decompressedBytes);
Console.WriteLine(response);
}
}
You need to check the return value of the Read() calls you are making on the TCP stream: it is the number of bytes effectively read.
MSDN says :
Return Value
The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not
currently available, or zero (0) if the end of the stream has been
reached.
If the socket is closed, the call will return immediately 0 (which is what might be happening here).
If is not 0, then you must check how many bytes you did actually received, if it is less than client.ReceiveBufferSize, you will need additional calls to Read to retrieve the remaining bytes.
Prior to you call to read, check that some data is actually available on the socket :
while(client.Available == 0)
// wait ...
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.available%28v=vs.110%29.aspx
I think you may have the end of file or so. Can you try setting the stream position before reading the stream
stream.position = 0;
http://msdn.microsoft.com/en-us/library/vstudio/system.io.stream.read
Encoding.UTF8.GetString shouldn't be used on arbitrary byte array.
e.g.: The compressed bytes may contain NULL character, which is not allowed in UTF-8 encoded text except for being used as terminator.
If you want to print the received bytes for debugging, maybe you should just print them as integers.
I am trying to read an Http response stream twice via the following:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
stream = response.GetResponseStream();
RssReader reader = new RssReader(stream);
do
{
element = reader.Read();
if (element is RssChannel)
{
feed.Channels.Add((RssChannel)element);
}
} while (element != null);
StreamReader sr = new StreamReader(stream);
feed._FeedRawData = sr.ReadToEnd();
However when the StreamReader code executes there is no data returned because the stream has now reached the end. I tried to reset the stream via stream.Position = 0 but this throws an exception (I think because the stream can't have its position changed manually).
Basically, I would like to parse the stream for XML and have access to the raw data (in string format).
Any ideas?
Copy it into a new MemoryStream first. Then you can re-read the MemoryStream as many times as you like:
Stream responseStream = CopyAndClose(resp.GetResponseStream());
// Do something with the stream
responseStream.Position = 0;
// Do something with the stream again
private static Stream CopyAndClose(Stream inputStream)
{
const int readSize = 256;
byte[] buffer = new byte[readSize];
MemoryStream ms = new MemoryStream();
int count = inputStream.Read(buffer, 0, readSize);
while (count > 0)
{
ms.Write(buffer, 0, count);
count = inputStream.Read(buffer, 0, readSize);
}
ms.Position = 0;
inputStream.Close();
return ms;
}
Copying the stream to a MemoryStream as suggested by Iain is the right approach. But since
.NET Framework 4 (released 2010) we have Stream.CopyTo. Example from the docs:
// Create the streams.
MemoryStream destination = new MemoryStream();
using (FileStream source = File.Open(#"c:\temp\data.dat",
FileMode.Open))
{
Console.WriteLine("Source length: {0}", source.Length.ToString());
// Copy source to destination.
source.CopyTo(destination);
}
Console.WriteLine("Destination length: {0}", destination.Length.ToString());
Afterwards you can read destination as many times as you like:
// re-set to beginning and convert stream to string
destination.Position = 0;
StreamReader streamReader = new StreamReader(destination);
string text = streamReader.ReadToEnd();
// re-set to beginning and read again
destination.Position = 0;
RssReader cssReader = new RssReader(destination);
(I have seen Endy's comment but since it is an appropriate, current answer, it should have its own answer entry.)
have you tried resetting the stream position?
if this does not work you can copy the stream to a MemoryStream and there you can reset the position (i.e. to 0) as often as you want.