I'm using the msdn example here:
http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx
I changed the FileStream to a MemoryStream and it doesn't read the bytes
when I change it back to FileStream it works fine.
Any clue?
Thanks
CompressMemoryStream();
Stream requestStream = _request.EndGetRequestStream(ar);
const int bufferLength = 2048;
byte[] buffer = new byte[bufferLength];
int count = 0;
int readBytes = 0;
do
{
//MemoryStream _compressedOutStream
//is created/filled by 'CompressMemoryStream()'
readBytes = _compressedOutStream.Read(buffer, 0, bufferLength);
requestStream.Write(buffer, 0, readBytes);
count += readBytes;
}
while (readBytes != 0);
requestStream.Close();
state.Request.BeginGetResponse(
new AsyncCallback(EndGetResponseCallback),
state
);
What's the value of readBytes on the first iteration through the loop?
My first guess would be that you made the same mistake that I often make: writing to a stream, then forgetting to rewind it to the beginning before starting to read back from it. If that's the case, then readBytes will be zero on the first (and only) loop iteration, because you're at the end of the stream -- there's nothing to read.
Try setting stream.Position = 0 before you start reading.
Related
My goal is to send a file over a TCP connection using NetworkStream.
I first send the length of the data I'm going to send, and then I use a filestream and a binary writter to send the data byte by byte.
While debugging the process, I found out that some '0' bytes are being put at the beggining of the file on the receiving end.
For example, the base file's content azertyuiop is received as azerty (4 spaces replacing uiop), causing files like images to be corrupted.
The code I've got so far :
(Where br is a BinaryReader and bw is a BinaryWriter)
Sender:
using (var readStream = new FileStream(fileLocation, FileMode.Open))
{
// Send the data length first
bw.Write(new FileInfo(fileLocation).Length);
bw.Flush();
var buffer = new byte[1];
while (readStream.Read(buffer, 0, 1) > 0)
{
bw.Write(buffer[0]);
bw.Flush();
}
}
Receiver:
// Get data length
var dataLength = br.ReadInt32();
using (var fs = new FileStream(newFileLocation, FileMode.Create))
{
var buffer = new byte[1];
for(int i = 0; i < dataLength; i++)
{
br.Read(buffer, 0, 1);
fs.Write(buffer, 0, 1);
}
}
What am I missing or doing wrong ?
The problem could be the following:
bw.Write(new FileInfo(fileLocation).Length);
...
var dataLength = br.ReadInt32();
The Length property is actually of type long (8 bytes). But you are reading the value as Int32 (4 bytes), leaving the other 4 bytes in the stream.
fileinfo.length is a long not an int32
I'm sending data to Lector device.
Normally I received data from device when I sending on hercules.
Hercules is returning "sRA eExtIn1 0 0 0".
The below code has waiting line stream.Read() function.
How can I getting data from device?
string responseData = null;
using (TcpClient client = new TcpClient("10.1.13.102", 2111))
{
using (NetworkStream stream = client.GetStream())
{
byte[] sentData = System.Text.Encoding.ASCII.GetBytes("<STX>sRN eExtIn1<ETX>");
stream.Write(sentData, 0, sentData.Length);
byte[] buffer = new byte[32];
int bytes;
if (client.Connected)
{
while ((bytes = stream.Read(buffer, 0, buffer.Length)) != 0)
{
for (int i = 0; i < bytes; i++)
{
responseData += (char)buffer[i];
}
}
}
}
}
The mistake you're making, and the other answer is also making, is assuming that stream.Read won't return until it has read 32 bytes. That is incorrect.
https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read(v=vs.110).aspx
This method reads data into the buffer parameter and returns the
number of bytes successfully read. If no data is available for
reading, the Read method returns 0. The Read operation reads as much
data as is available, up to the number of bytes specified by the size
parameter.
It will return when there is no data available to read or 32 bytes have been read, whichever comes first. So if, for example, the client is slow or the network very busy, the response may not have arrived yet when you call stream.Read. Consequently, there will be nothing to read so it will return 0 and you will exit, failing to read the data. In fact, you may have to call stream.Read any number of times to get the full 32 bytes if the network is very saturated and data is arriving a few bytes at a time (not likely with such a small packet, but you have to code it that way).
So your code needs to look like this (note the additional while loop):
using (TcpClient client = new TcpClient("10.1.13.102", 2111))
{
using (NetworkStream stream = client.GetStream())
{
byte[] sentData = System.Text.Encoding.ASCII.GetBytes("<STX>sRN eExtIn1<ETX>");
stream.Write(sentData, 0, sentData.Length);
byte[] buffer = new byte[32];
int bytes;
if (client.Connected)
{
int bytesRead = 0;
while (bytesRead < buffer.Length)
{
while ((bytes = stream.Read(buffer, 0, buffer.Length)) != 0)
{
for (int i = 0; i < bytes; i++)
{
responseData += (char)buffer[i];
}
bytesRead += bytes;
}
}
}
}
}
Thanks everybody.
I found solution of my question.
and tags should be describe as bytes. Like below.
byte[] byt = System.Text.Encoding.ASCII.GetBytes("sRN DItype");
stream.Write(STX, 0 , 1);
stream.Write(byt, 0, byt.Length);
stream.Write(ETX, 0, 1);
stream.Read(buffer, 0, buffer.Length);
I'm trying to read a local file and upload it on ftp server. when i read a image file, everything is ok, but when i read a doc or docx file, FileStream returns length = 0. Here is my code:
i checked with some other files, it appears that it only works fine with images and it returns 0 for any other file
if (!ftpClient.FileExists(fileName))
{
try
{
ftpClient.ValidateCertificate += (control, e) => { e.Accept = true; };
const int BUFFER_SIZE = 64 * 1024; // 64KB buffer
byte[] buffer = new byte[BUFFER_SIZE];
using (Stream readStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read))
using (Stream writeStream = ftpClient.OpenWrite(fileName))
{
while (readStream.Position < readStream.Length)
{
buffer.Initialize();
int bytesRead = readStream.Read(buffer, 0, BUFFER_SIZE);
writeStream.Write(buffer, 0, bytesRead);
}
readStream.Flush();
readStream.Close();
writeStream.Flush();
writeStream.Close();
DeleteTempFile(tempFilePath);
return true;
}
}
catch (Exception ex)
{
return false;
}
}
I couldn't find whats wrong with it. could you please help me?
While this doesn't answer your specific question, you don't actually need to know the length of your stream. Just keep reading until you hit a zero length read. A zero byte read is guaranteed to indicate the the end of any stream.
Return Value
Type: System.Int32
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.
while (true)
{
int bytesRead = readStream.Read(buffer, 0, BUFFER_SIZE);
if(bytesRead==0)
{
break;
}
writeStream.Write(buffer, 0, bytesRead);
}
alternatively:
readStream.CopyTo(writeStream);
is probably the most concise method of stating your goal...
it was just a silly mistake, i have two fileupload and i've saved the other fileupload, so it creates a zero length file. as it appears the code works fine.
thanks everyone.
First I would like to say that I tried to do research on how to understand what I'm about to ask but just couldn't come up with what I was looking for. This being said I thought I would ask some of you crazy smart people to explain this in lamens terms for me as best as possible.
My issue is that I have a perfectly good "Copy Pasted" code to download a file using ftpWebRequest. I will paste the code below:
public static void DownloadFiles()
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://****/test.zip");
request.Credentials = new NetworkCredential("****", "*****");
request.UseBinary = true;
request.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writer = new FileStream("***/test.zip", FileMode.Create);
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[2048];
readCount = responseStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
writer.Write(buffer, 0, readCount);
readCount = responseStream.Read(buffer, 0, bufferSize);
}
responseStream.Close();
response.Close();
writer.Close();
}
Like I said this works perfectly and downloads the zip file without any issues. What I'm trying to understand because I think "Copy Paste" code is a horrible idea is how this is actually functinning. The only part that I do not understand is what is actually happening between these points:
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[2048];
readCount = responseStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
writer.Write(buffer, 0, readCount);
readCount = responseStream.Read(buffer, 0, bufferSize);
}
If someone would be so kind to please explain what is actually happening in the buffer, why we set it to 2048 and what the while loop is actually doing would be very appreciated. Just as a side not I have gone through the code and put message boxes and other debug's in to try and understand whats going on but without success. Thank you in advance and I apologize if this seems very elementary.
data is read from the stream in 2 kB chunks and written to file:
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[2048]; // a buffer is created
// bytes are read from stream into buffer. readCount contains
// number of bytes actually read. it can be less then 2048 for the last chunk.
// e.g if there are 3000 bytes of data, first Read will read 2048 bytes
// and second will read 952 bytes
readCount = responseStream.Read(buffer, 0, bufferSize);
while (readCount > 0) // as long as we have read some data
{
writer.Write(buffer, 0, readCount); // write that many bytes from buffer to file
readCount = responseStream.Read(buffer, 0, bufferSize); // then read next chunk
}
The code reads the contents of the responseStream into the buffer array and writes it out to the writer. The while loop is necessary because when you call Read() on a stream, there's no guarantee it will read enough bytes to fill the buffer. The stream only guarantees that, if there's anything to read (in other words, you haven't reached the end of the stream) it will read at least one byte. Whatever it does, it will return the actual number of bytes read. So, you have to keep calling Read() until it returns 0, meaning that you've reached the end of the stream. The size of the buffer is arbitrary. You could use a buffer of length 1 but there might be performance benefits to using something around 2-4kb (due to typical sizes of network packets or disk sectors) .
i'm implementing a wcf service that accepts image streams. however i'm currently getting an exception when i run it. as its trying to get the length of the stream before the stream is complete. so what i'd like to do is buffer the stream until its complete. however i cant find any examples of how to do this...
can anyone help?
my code so far:
public String uploadUserImage(Stream stream)
{
Stream fs = stream;
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);// this causes exception
File.WriteAllBytes(filepath, bytes);
}
Rather than try to fetch the length, you should read from the stream until it returns that it's "done". In .NET 4, this is really easy:
// Assuming we *really* want to read it into memory first...
MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
memoryStream.Position = 0;
File.WriteAllBytes(filepath, memoryStream);
In .NET 3.5 there's no CopyTo method, but you can write something similar yourself:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
However, now we've got something to copy a stream, why bother reading it all into memory first? Let's just write it straight to a file:
using (FileStream output = File.OpenWrite(filepath))
{
CopyStream(stream, output); // Or stream.CopyTo(output);
}
I'm not sure what you are returning (or not returning), but something like this might work for you:
public String uploadUserImage(Stream stream) {
const int KB = 1024;
Byte[] bytes = new Byte[KB];
StringBuilder sb = new StringBuilder();
using (BinaryReader br = new BinaryReader(stream)) {
int len;
do {
len = br.Read(bytes, 0, KB);
string readData = Encoding.UTF8.GetString(bytes);
sb.Append(readData);
} while (len == KB);
}
//File.WriteAllBytes(filepath, bytes);
return sb.ToString();
}
A string can hold up to 2 GB, I believe.
Try this :
using (StreamWriter sw = File.CreateText(filepath))
{
stream.CopyTo(sw);
sw.Close();
}
Jon Skeets answer for .Net 3.5 and below using a Buffer Read is actually done incorrectly.
The buffer isn't cleared between reads which can result in issues on any read that returns less than 8192, for example if the 2nd read, read 192 bytes, the 8000 last bytes from the first read would STILL be in the buffer which would then be returned to the stream.
My code below you supply it a Stream and it will return a IEnumerable array.
Using this you can for-each it and Write to a MemoryStream and then use .GetBuffer() to end up with a compiled merged byte[].
private IEnumerable<byte[]> ReadFullStream(Stream stream) {
while(true) {
byte[] buffer = new byte[8192];//since this is created every loop, its buffer is cleared
int bytesRead = stream.Read(buffer, 0, buffer.Length);//read up to 8192 bytes into buffer
if (bytesRead == 0) {//if we read nothing, stream is finished
break;
}
if(bytesRead < buffer.Length) {//if we read LESS than 8192 bytes, resize the buffer to essentially remove everything after what was read, otherwise you will have nullbytes/0x00bytes at the end of your buffer
Array.Resize(ref buffer, bytesRead);
}
yield return buffer;//yield return the buffer data
}//loop here until we reach a read == 0 (end of stream)
}