OutOfMemoryError while break zip file into two parts - glassfish-3

My application breaks .zip file into two parts. It works fine when file size is under 100MB. If file size is more than 100MB it gives
java.lang.OutOfMemoryError
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:198)
I'm using glassfishV3 and JDK6
-Xms512m -Xmx512m is not enough
then I have set
<jvm-options>-Xms1024m</jvm-options>
<jvm-options>-Xmx1024m</jvm-options>
but then it gives
"Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine."
public void create() {
byte[] bFile = takeByteArr("file1.zip");
byte[] bPart1 = Arrays.copyOfRange(bFile, 0, 100000);
byte[] bPart2 = Arrays.copyOfRange(bFile, 100000, bFile.length);
createFile(bPart1, "part1.zip");
createFile(bPart2, "part2.zip");
}
void createFile(byte[] bFile, String path) {
try {
FileOutputStream fos = new FileOutputStream(path);
fos.write(bFile);
fos.close();
} catch (FileNotFoundException ex) {
System.out.println("FileNotFoundException : " + ex);
} catch (IOException ioe) {
System.out.println("IOException : " + ioe);
}
}
byte[] takeByteArr(String filePath) {
File file = new File(filePath);
byte[] bFile = new byte[(int) file.length()];
try {
FileInputStream fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return bFile;
}

As already suggested in a comment large files are not read in one part but into a smaller buffer. The buffer is then processed, in your case this would be saving the part file to disk, and reused in a loop which reads the file chunk by chunk. This method has the advantage that you only need as much memory as the size of your buffer is.
The FileInputStream class has a method named read(byte[] b, int off, int len) which reads len number of bytes starting at offset off in byte array b from the InputStream. The method returns an int representing the number of bytes read during the method call and -1 if nothing could be read.
Example:
byte[] b = new byte[1024];
int read = inputStream.read(b, 0, 1024);
Now you have a byte array b which is 1024 bytes large and contains read bytes of content.
You can loop through your file, but you have to pay attention to the last part. The byte array buffer will also have the size 100000 but I guess you don't want to create the last part with that size. Therefore you have to recreate the buffer with number of bytes which are really the last part of the content.
Your code could look like this:
public void create() throws IOException {
FileInputStream in = new FileInputStream(new File("file1.zip"));
byte[] b = new byte[100000];
int read;
int counter = 0;
while ((read = in.read(b, 0, 100000)) != -1) {
if(read != 100000) { // <- the last part
b = Arrays.copyOfRange(b, 0, read);
}
createFile(b, "part" + counter++ + ".zip");
b = new byte[100000];
}
}

Related

TCP Communication: How to send data from HoloLens by pressing a key and read data in a loop?

I need to establish a two-way communication like TCP between the UWP app (Hololens) as a client and Python on my PC as a server in a way that client sends the data when a key is pressed and receives the data in a while loop (when the data comes from the server).
I went through this link. This blog code is completely in accordance with what I need. The only problem is that it is written with system networking but I need to use windows networking instead.
Part of the code in Link1 of sending and reading functions:
Read stream
private void ListenForData()
{
try
{
socketConnection = new TcpClient("192.168.0.16", 5000);
Debug.Log("Connection successful");
Byte[] bytes = new Byte[1024];
while (true)
{
// Get a stream object for reading
using (NetworkStream stream = socketConnection.GetStream())
{
int length;
// Read incoming stream into byte array.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
var incomingData = new byte[length];
Array.Copy(bytes, 0, incomingData, 0, length);
// Convert byte array to string message.
string serverMessage = Encoding.ASCII.GetString(incomingData);
Debug.Log("server message received as: " + serverMessage);
updateText = serverMessage;
}
}
}
}
catch (SocketException socketException)
{
Debug.Log("Socket exception: " + socketException);
}
}
Write stream:
public void SendMessage(string clientMessage)
{
if (socketConnection == null)
{
return;
}
try
{
// Get a stream object for writing.
NetworkStream stream = socketConnection.GetStream();
if (stream.CanWrite)
{
//string clientMessage = "This is a message from one of your clients.";
// Convert string message to byte array.
byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage);
// Write byte array to socketConnection stream.
stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
Debug.Log("Client sent message: " + clientMessage);
}
}
catch (SocketException socketException)
{
Debug.Log("Socket exception: " + socketException);
}
}
Other published codes do not put read and write parts in separate functions.

Download File Servlet - File Content contains binary

I had tried to develop a servlet that allow user to download file but it allow user to download the file but the file content contains binary garbage and not human readable. May I know what could be the reason ?
Code
int length = -1, index = 0;
byte[] buffer = null;
String attachmentPath = null, contentType = null, extension = null;
File attachmentFile = null;
BufferedInputStream input = null;
ServletOutputStream output = null;
ServletContext context = null;
attachmentPath = request.getParameter("attachmentPath");
if (attachmentPath != null && !attachmentPath.isEmpty()) {
attachmentFile = new File(attachmentPath);
if (attachmentFile.exists()) {
response.reset();
context = super.getContext();
contentType = context.getMimeType(attachmentFile.getName());
response.setContentType(contentType);
response.addHeader("content-length", String.valueOf(attachmentFile.length()));
response.addHeader("content-disposition", "attachment;filename=" + attachmentFile.getName());
try {
buffer = new byte[AttachmentTask.DEFAULT_BUFFER_SIZE];
input = new BufferedInputStream(new FileInputStream(attachmentFile));
output = response.getOutputStream();
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
index += length;
// output.write(length);
}
output.flush();
input.close();
output.close();
} catch (FileNotFoundException exp) {
logger.error(exp.getMessage());
} catch (IOException exp) {
logger.error(exp.getMessage());
}
} else {
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} catch (IOException exp) {
logger.error(exp.getMessage());
}
}
It is relate to writing file as binary or text mode or browser settings?
Please help.
Thanks.
The problem is not in the code given so far. You're properly using InputStream/OutputStream instead of a Reader/Writer to stream the file.
The cause of the problem is more likely in the way how you created/saved the file. This problem will manifest when you've used a Reader and/or Writer which is not been instructed to use the proper character encoding for the characters being read/written. Perhaps you're creating an upload/download service and the fault was in the upload process itself?
Assuming that the data is in UTF-8, you should have created the reader as follows:
Reader reader = new InputStreamReader(new FileInputStream(file), "UTF-8"));
and the writer as follows:
Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
But if you actually don't need to manipulate the stream on a per-character basis, but just wanted to transfer the data unmodified, then you should actually have used InputStream/OutputStream all the time.
See also:
Unicode - How to get the characters right?

Download large file in small chunks in C#

I need to download some file which is more than 25 MB large, but my network only allow to request a file of 25 MB only.
I am using following code
const long DefaultSize = 26214400;
long Chunk = 26214400;
long offset = 0;
byte[] bytesInStream;
public void Download(string url, string filename)
{
long size = Size(url);
int blocksize = Convert.ToInt32(size / DefaultSize);
int remainder = Convert.ToInt32(size % DefaultSize);
if (remainder > 0) { blocksize++; }
FileStream fileStream = File.Create(#"D:\Download TEST\" + filename);
for (int i = 0; i < blocksize; i++)
{
if (i == blocksize - 1)
{
Chunk = remainder;
}
HttpWebRequest req = (HttpWebRequest)System.Net.WebRequest.Create(url);
req.Method = "GET";
req.AddRange(Convert.ToInt32(offset), Convert.ToInt32(Chunk+offset));
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
// StreamReader sr = new StreamReader(resp.GetResponseStream());
using (Stream responseStream = resp.GetResponseStream())
{
bytesInStream = new byte[Chunk];
responseStream.Read(bytesInStream, 0, (int)bytesInStream.Length);
// Use FileStream object to write to the specified file
fileStream.Seek((int)offset, SeekOrigin.Begin);
fileStream.Write(bytesInStream,0, bytesInStream.Length);
}
offset += Chunk;
}
fileStream.Close();
}
public long Size(string url)
{
System.Net.WebRequest req = System.Net.HttpWebRequest.Create(url);
req.Method = "HEAD";
System.Net.WebResponse resp = req.GetResponse();
resp.Close();
return resp.ContentLength;
}
It is properly writing content on disk but content is not working
You should check how much was read before write, something like this (and you don't need to remember the offset to seek, the seek is automatic when you write):
int read;
do
{
read = responseStream.Read(bytesInStream, 0, (int)bytesInStream.Length);
if (read > 0)
fileStream.Write(bytesInStream, 0, read);
}
while(read > 0);
There is a similar SO questions that might help you
Segmented C# file downloader
and
How to open multiple connections to download single file?
Also this code project article
http://www.codeproject.com/Tips/307548/Resume-Suppoert-Downloading
Range is zero based and you should subtract 1 from upper bound.
request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(offset, chunkSize + offset - 1);
I published correct code fragment at the following link:
https://stackoverflow.com/a/48019611/1099716
Akka streams can help download file in small chunks from a System.IO.Stream using multithreading. https://getakka.net/articles/intro/what-is-akka.html
The Download method will append the bytes to the file starting with long fileStart. If the file does not exist, fileStart value must be 0.
using Akka.Actor;
using Akka.IO;
using Akka.Streams;
using Akka.Streams.Dsl;
using Akka.Streams.IO;
private static Sink<ByteString, Task<IOResult>> FileSink(string filename)
{
return Flow.Create<ByteString>()
.ToMaterialized(FileIO.ToFile(new FileInfo(filename), FileMode.Append), Keep.Right);
}
private async Task Download(string path, Uri uri, long fileStart)
{
using (var system = ActorSystem.Create("system"))
using (var materializer = system.Materializer())
{
HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
request.AddRange(fileStart);
using (WebResponse response = request.GetResponse())
{
Stream stream = response.GetResponseStream();
await StreamConverters.FromInputStream(() => stream, chunkSize: 1024)
.RunWith(FileSink(path), materializer);
}
}
}

Biztalk 2010 Custom Pipeline Component returns binary

I have created a custom pipeline component which transforms a complex excel spreadsheet to XML. The transformation works fine and I can write out the data to check. However when I assign this data to the BodyPart.Data part of the inMsg or a new message I always get a routing failure. When I look at the message in the admin console it appears that the body contains binary data (I presume the original excel) rather than the XML I have assigned - see screen shot below. I have followed numerous tutorials and many different ways of doing this but always get the same result.
My current code is:
public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
//make sure we have something
if (inmsg == null || inmsg.BodyPart == null || inmsg.BodyPart.Data == null)
{
throw new ArgumentNullException("inmsg");
}
IBaseMessagePart bodyPart = inmsg.BodyPart;
//create a temporary directory
const string tempDir = #"C:\test\excel";
if (!Directory.Exists(tempDir))
{
Directory.CreateDirectory(tempDir);
}
//get the input filename
string inputFileName = Convert.ToString(inmsg.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties"));
swTemp.WriteLine("inputFileName: " + inputFileName);
//set path to write excel file
string excelPath = tempDir + #"\" + Path.GetFileName(inputFileName);
swTemp.WriteLine("excelPath: " + excelPath);
//write the excel file to a temporary folder
bodyPart = inmsg.BodyPart;
Stream inboundStream = bodyPart.GetOriginalDataStream();
Stream outFile = File.Create(excelPath);
inboundStream.CopyTo(outFile);
outFile.Close();
//process excel file to return XML
var spreadsheet = new SpreadSheet();
string strXmlOut = spreadsheet.ProcessWorkbook(excelPath);
//now build an XML doc to hold this data
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(strXmlOut);
XmlDocument finalMsg = new XmlDocument();
XmlElement xEle;
xEle = finalMsg.CreateElement("ns0", "BizTalk_Test_Amey_Pipeline.textXML",
"http://tempuri.org/INT018_Workbook.xsd");
finalMsg.AppendChild(xEle);
finalMsg.FirstChild.InnerXml = xDoc.FirstChild.InnerXml;
//write xml to memory stream
swTemp.WriteLine("Write xml to memory stream");
MemoryStream streamXmlOut = new MemoryStream();
finalMsg.Save(streamXmlOut);
streamXmlOut.Position = 0;
inmsg.BodyPart.Data = streamXmlOut;
pc.ResourceTracker.AddResource(streamXmlOut);
return inmsg;
}
Here is a sample of writing the message back:
IBaseMessage Microsoft.BizTalk.Component.Interop.IComponent.Execute(IPipelineContext pContext, IBaseMessage pInMsg)
{
IBaseMessagePart bodyPart = pInMsg.BodyPart;
if (bodyPart != null)
{
using (Stream originalStrm = bodyPart.GetOriginalDataStream())
{
byte[] changedMessage = ConvertToBytes(ret);
using (Stream strm = new AsciiStream(originalStrm, changedMessage, resManager))
{
// Setup the custom stream to put it back in the message.
bodyPart.Data = strm;
pContext.ResourceTracker.AddResource(strm);
}
}
}
return pInMsg;
}
The AsciiStream used a method like this to read the stream:
override public int Read(byte[] buffer, int offset, int count)
{
int ret = 0;
int bytesRead = 0;
byte[] FixedData = this.changedBytes;
if (FixedData != null)
{
bytesRead = count > (FixedData.Length - overallOffset) ? FixedData.Length - overallOffset : count;
Array.Copy(FixedData, overallOffset, buffer, offset, bytesRead);
if (FixedData.Length == (bytesRead + overallOffset))
this.changedBytes = null;
// Increment the overall offset.
overallOffset += bytesRead;
offset += bytesRead;
count -= bytesRead;
ret += bytesRead;
}
return ret;
}
I would first of all add more logging to your component around the MemoryStream logic - maybe write the file out to the file system so you can make sure the Xml version is correct. You can also attach to the BizTalk process and step through the code for the component which makes debugging a lot easier.
I would try switching the use of MemoryStream to a more basic custom stream that writes the bytes for you. In the BizTalk SDK samples for pipeline components there are some examples for a custom stream. You would have to customize the stream sample so it just writes the stream. I can work on posting an example. So do the additional diagnostics above first.
Thanks,

OutOfMemoryException when send big file 500MB using FileStream ASPNET

I'm using Filestream for read big file (> 500 MB) and I get the OutOfMemoryException.
I use Asp.net , .net 3.5, win2003, iis 6.0
I want this in my app:
Read DATA from Oracle
Uncompress file using FileStream and BZip2
Read file uncompressed and send it to asp.net page for download.
When I read file from disk, Fails !!! and get OutOfMemory...
. My Code is:
using (var fs3 = new FileStream(filePath2, FileMode.Open, FileAccess.Read))
{
byte[] b2 = ReadFully(fs3, 1024);
}
// http://www.yoda.arachsys.com/csharp/readbinary.html
public static byte[] ReadFully(Stream stream, int initialLength)
{
// If we've been passed an unhelpful initial length, just
// use 32K.
if (initialLength < 1)
{
initialLength = 32768;
}
byte[] buffer = new byte[initialLength];
int read = 0;
int chunk;
while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
{
read += chunk;
// If we've reached the end of our buffer, check to see if there's
// any more information
if (read == buffer.Length)
{
int nextByte = stream.ReadByte();
// End of stream? If so, we're done
if (nextByte == -1)
{
return buffer;
}
// Nope. Resize the buffer, put in the byte we've just
// read, and continue
byte[] newBuffer = new byte[buffer.Length * 2];
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read] = (byte)nextByte;
buffer = newBuffer;
read++;
}
}
// Buffer is now too big. Shrink it.
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}
Now, I specify my issue better.
Uncompress file using FileStream and BZip2 is OK, all is right.
The Problem is the following:
Read fat big file in disk (> 500 MB) in byte[] and send bytes to Response (asp.net) for download it.
When use
http://www.yoda.arachsys.com/csharp/readbinary.html
public static byte[] ReadFully
I get the error: OutOfMemoryException...
If better BufferedStream than Stream (FileStream, MemoryStream, ...) ??
Using BufferedStream , Can I read big file of 700 MB ?? (any sample code source using BufferedStream for download big file)
I think, this is the question: Not "how to read a 500mb file into memory?" , But "how to send a large file to the ASPNET Response stream?"
I found this code by Cheeso:
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
Response.BufferOutput= false; // to prevent buffering
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
Response.OutputStream.Write(buffer, 0, bytesRead);
}
}
Is it good code ?? any improvements for high performance ??
A collegue say me, use
Response.TransmitFile(filePath);
Now, another question, better TransmitFile or code by Cheeso ??
Many years ago, in msdn magazine appears great article about it but I cannot access http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/,
Update: You can access using webarchive in the link: https://web.archive.org/web/20070627063111/http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/
Any suggestions, comments, sample code source??
I've created download page which allows user to download up to 4gb (may be more) few months ago. Here is my working snippet:
private void TransmitFile(string fullPath, string outFileName)
{
System.IO.Stream iStream = null;
// Buffer to read 10K bytes in chunk:
byte[] buffer = new Byte[10000];
// Length of the file:
int length;
// Total bytes to read:
long dataToRead;
// Identify the file to download including its path.
string filepath = fullPath;
// Identify the file name.
string filename = System.IO.Path.GetFileName(filepath);
try
{
// Open the file.
iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
System.IO.FileAccess.Read, System.IO.FileShare.Read);
// Total bytes to read:
dataToRead = iStream.Length;
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=" + outFileName);
Response.AddHeader("Content-Length", iStream.Length.ToString());
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (Response.IsClientConnected)
{
// Read the data in buffer.
length = iStream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the output.
Response.Flush();
buffer = new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
}
Response.Close();
}
}
You do not need to hold the whole file in memory just read it and write to the response stream in a loop.
I came across this question in my search to return a FileStreamResult from a controller, as I kept running into issues while working with large streams due to .Net trying to build the entire response all at once. Pavel Morshenyuk's answer was a huge help, but I figured I'd share the BufferedFileStreamResult that I ended up with.
/// <summary>Based upon https://stackoverflow.com/a/3363015/595473 </summary>
public class BufferedFileStreamResult : System.Web.Mvc.FileStreamResult
{
public BufferedFileStreamResult(System.IO.Stream stream, string contentType, string fileDownloadName)
: base(stream, contentType)
{
FileDownloadName = fileDownloadName;
}
public int BufferSize { get; set; } = 16 * 1024 * 1024;//--16MiB
protected override void WriteFile(System.Web.HttpResponseBase response)
{
try
{
response.Clear();
response.Headers.Set("Content-Disposition", $"attachment; filename={FileDownloadName}");
response.Headers.Set("Content-Length", FileStream.Length.ToString());
byte[] buffer;
int bytesRead;
while (response.IsClientConnected)//--Prevent infinite loop if user disconnects
{
buffer = new byte[BufferSize];
//--Read the data in buffer
if ((bytesRead = FileStream.Read(buffer, 0, BufferSize)) == 0)
{
break;//--Stop writing if there's nothing left to write
}
//--Write the data to the current output stream
response.OutputStream.Write(buffer, 0, bytesRead);
//--Flush the data to the output
response.Flush();
}
}
finally
{
FileStream?.Close();
response.Close();
}
}
}
Now, in my controller, I can just
return new BufferedFileStreamResult(stream, contentType, fileDownloadName);
There are more than one solution
1- Using RecyclableMemoryStream instead of MemoryStream solution
You can read more about RecyclableMemoryStream here :
http://www.philosophicalgeek.com/2015/02/06/announcing-microsoft-io-recycablememorystream/
https://github.com/Microsoft/Microsoft.IO.RecyclableMemoryStream
2- Using MemoryTributary instead of MemoryStream
You can read more about MemoryTributary here :
https://www.codeproject.com/Articles/348590/A-replacement-for-MemoryStream?msg=5257615#xx5257615xx
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace LiquidEngine.Tools
{
/// <summary>
/// MemoryTributary is a re-implementation of MemoryStream that uses a dynamic list of byte arrays as a backing store, instead of a single byte array, the allocation
/// of which will fail for relatively small streams as it requires contiguous memory.
/// </summary>
public class MemoryTributary : Stream /* http://msdn.microsoft.com/en-us/library/system.io.stream.aspx */
{
#region Constructors
public MemoryTributary()
{
Position = 0;
}
public MemoryTributary(byte[] source)
{
this.Write(source, 0, source.Length);
Position = 0;
}
/* length is ignored because capacity has no meaning unless we implement an artifical limit */
public MemoryTributary(int length)
{
SetLength(length);
Position = length;
byte[] d = block; //access block to prompt the allocation of memory
Position = 0;
}
#endregion
#region Status Properties
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
#endregion
#region Public Properties
public override long Length
{
get { return length; }
}
public override long Position { get; set; }
#endregion
#region Members
protected long length = 0;
protected long blockSize = 65536;
protected List<byte[]> blocks = new List<byte[]>();
#endregion
#region Internal Properties
/* Use these properties to gain access to the appropriate block of memory for the current Position */
/// <summary>
/// The block of memory currently addressed by Position
/// </summary>
protected byte[] block
{
get
{
while (blocks.Count <= blockId)
blocks.Add(new byte[blockSize]);
return blocks[(int)blockId];
}
}
/// <summary>
/// The id of the block currently addressed by Position
/// </summary>
protected long blockId
{
get { return Position / blockSize; }
}
/// <summary>
/// The offset of the byte currently addressed by Position, into the block that contains it
/// </summary>
protected long blockOffset
{
get { return Position % blockSize; }
}
#endregion
#region Public Stream Methods
public override void Flush()
{
}
public override int Read(byte[] buffer, int offset, int count)
{
long lcount = (long)count;
if (lcount < 0)
{
throw new ArgumentOutOfRangeException("count", lcount, "Number of bytes to copy cannot be negative.");
}
long remaining = (length - Position);
if (lcount > remaining)
lcount = remaining;
if (buffer == null)
{
throw new ArgumentNullException("buffer", "Buffer cannot be null.");
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException("offset",offset,"Destination offset cannot be negative.");
}
int read = 0;
long copysize = 0;
do
{
copysize = Math.Min(lcount, (blockSize - blockOffset));
Buffer.BlockCopy(block, (int)blockOffset, buffer, offset, (int)copysize);
lcount -= copysize;
offset += (int)copysize;
read += (int)copysize;
Position += copysize;
} while (lcount > 0);
return read;
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
Position = offset;
break;
case SeekOrigin.Current:
Position += offset;
break;
case SeekOrigin.End:
Position = Length - offset;
break;
}
return Position;
}
public override void SetLength(long value)
{
length = value;
}
public override void Write(byte[] buffer, int offset, int count)
{
long initialPosition = Position;
int copysize;
try
{
do
{
copysize = Math.Min(count, (int)(blockSize - blockOffset));
EnsureCapacity(Position + copysize);
Buffer.BlockCopy(buffer, (int)offset, block, (int)blockOffset, copysize);
count -= copysize;
offset += copysize;
Position += copysize;
} while (count > 0);
}
catch (Exception e)
{
Position = initialPosition;
throw e;
}
}
public override int ReadByte()
{
if (Position >= length)
return -1;
byte b = block[blockOffset];
Position++;
return b;
}
public override void WriteByte(byte value)
{
EnsureCapacity(Position + 1);
block[blockOffset] = value;
Position++;
}
protected void EnsureCapacity(long intended_length)
{
if (intended_length > length)
length = (intended_length);
}
#endregion
#region IDispose
/* http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx */
protected override void Dispose(bool disposing)
{
/* We do not currently use unmanaged resources */
base.Dispose(disposing);
}
#endregion
#region Public Additional Helper Methods
/// <summary>
/// Returns the entire content of the stream as a byte array. This is not safe because the call to new byte[] may
/// fail if the stream is large enough. Where possible use methods which operate on streams directly instead.
/// </summary>
/// <returns>A byte[] containing the current data in the stream</returns>
public byte[] ToArray()
{
long firstposition = Position;
Position = 0;
byte[] destination = new byte[Length];
Read(destination, 0, (int)Length);
Position = firstposition;
return destination;
}
/// <summary>
/// Reads length bytes from source into the this instance at the current position.
/// </summary>
/// <param name="source">The stream containing the data to copy</param>
/// <param name="length">The number of bytes to copy</param>
public void ReadFrom(Stream source, long length)
{
byte[] buffer = new byte[4096];
int read;
do
{
read = source.Read(buffer, 0, (int)Math.Min(4096, length));
length -= read;
this.Write(buffer, 0, read);
} while (length > 0);
}
/// <summary>
/// Writes the entire stream into destination, regardless of Position, which remains unchanged.
/// </summary>
/// <param name="destination">The stream to write the content of this stream to</param>
public void WriteTo(Stream destination)
{
long initialpos = Position;
Position = 0;
this.CopyTo(destination);
Position = initialpos;
}
#endregion
}
}

Resources