Я должен передать большие файлы между компьютерами на через ненадежные соединения с помощью WCF.
Поскольку я хочу смочь возобновить файл, и я не хочу быть ограниченным в моем размере файла WCF, я разделяю файлы на блоки в части 1 МБ. Они "разделяют на блоки", транспортируются как поток. Который работает довольно хороший, до сих пор.
Мои шаги:
Моя проблема находится на шаге 2. Я предполагаю, что, когда я создаю поток памяти из массива байтов, он закончится на LOH и в конечном счете вызовет outofmemory исключение. Я не мог на самом деле создать эту ошибку, возможно, я неправ в своем предположении.
Теперь, я не хочу отправлять байт [] в сообщении, поскольку WCF скажет мне, что размер массива является слишком большим. Я могу изменить макс. позволенный размер массива и/или размер моего блока, но я надеюсь, что существует другое решение.
Мой фактический вопрос (вопросы):
Btw.: На стороне получения I простых чтений меньшие блоки от прибывающего потока и пишут им непосредственно в файл, таким образом, никакие большие включенные массивы байтов.
Править:
текущее решение:
for (int i = resumeChunk; i < chunks; i++)
{
byte[] buffer = new byte[chunkSize];
fileStream.Position = i * chunkSize;
int actualLength = fileStream.Read(buffer, 0, (int)chunkSize);
Array.Resize(ref buffer, actualLength);
using (MemoryStream stream = new MemoryStream(buffer))
{
UploadFile(stream);
}
}
Надеюсь, все в порядке. Это мой первый ответ на StackOverflow.
Да, безусловно, если размер вашего фрагмента превышает 85000 байт, массив будет размещен в куче больших объектов. Вы, вероятно, не очень быстро исчерпаете память, поскольку вы выделяете и освобождаете смежные области памяти, которые имеют одинаковый размер, поэтому, когда память заполняется, среда выполнения может вместить новый фрагмент в старую, освобожденную область памяти.
Я бы немного обеспокоился вызовом Array.Resize, так как он создаст другой массив (см. http://msdn.microsoft.com/en-us/library/1ffy6686 (VS.80) .aspx ). Это необязательный шаг, если actualLength == Chunksize будет использоваться для всех фрагментов, кроме последнего. Поэтому я как минимум предлагаю:
if (actualLength != chunkSize) Array.Resize(ref buffer, actualLength);
Это должно удалить много выделений.Если фактический размер не совпадает с размером chunkSize, но все еще> 85000, тогда новый массив также будет размещен в куче больших объектов, что может привести к его фрагментации и, возможно, вызвать очевидные утечки памяти. Я считаю, что на то, чтобы действительно исчерпать память, по-прежнему потребуется много времени, поскольку утечка будет довольно медленной.
Я думаю, что лучше было бы использовать какой-то буферный пул для предоставления массивов. Вы можете свернуть свой собственный (это было бы слишком сложно), но WCF предоставляет его для вас. Я немного переписал ваш код, чтобы воспользоваться этим:
BufferManager bm = BufferManager.CreateBufferManager(chunkSize * 10, chunkSize);
for (int i = resumeChunk; i < chunks; i++)
{
byte[] buffer = bm.TakeBuffer(chunkSize);
try
{
fileStream.Position = i * chunkSize;
int actualLength = fileStream.Read(buffer, 0, (int)chunkSize);
if (actualLength == 0) break;
//Array.Resize(ref buffer, actualLength);
using (MemoryStream stream = new MemoryStream(buffer))
{
UploadFile(stream, actualLength);
}
}
finally
{
bm.ReturnBuffer(buffer);
}
}
предполагается, что реализация UploadFile может быть переписана так, чтобы принимать int вместо no. байтов для записи.
Надеюсь, это поможет
Джо
Я не уверен в первой части вашего вопроса, но что касается лучшего способа - не рассматривали ли вы BITS? Он позволяет фоновую загрузку файлов по http. Вы можете предоставить ему http:// или file:// URI. Она возобновляется с того места, где была прервана, и загружает куски байтов, используя метод RANGE в http HEADER. Он используется Windows Update.Вы можете подписаться на события, которые предоставляют информацию о ходе выполнения и завершении.