public Write ( byte buffer, int offset, int count ) : void | ||
buffer | byte | The buffer holding data to write to the stream. |
offset | int | the offset within that data array to find the first byte to write. |
count | int | the number of bytes to write. |
Результат | void |
public override void Write(byte[] buffer, int offset, int count)
{
bool mustWait = false;
// This method does this:
// 0. handles any pending exceptions
// 1. write any buffers that are ready to be written,
// 2. fills a work buffer; when full, flip state to 'Filled',
// 3. if more data to be written, goto step 1
if (_isClosed)
throw new InvalidOperationException();
// dispense any exceptions that occurred on the BG threads
if (_pendingException != null)
{
_handlingException = true;
var pe = _pendingException;
_pendingException = null;
throw pe;
}
if (count == 0) return;
if (!_firstWriteDone)
{
// Want to do this on first Write, first session, and not in the
// constructor. We want to allow MaxBufferPairs to
// change after construction, but before first Write.
_InitializePoolOfWorkItems();
_firstWriteDone = true;
}
do
{
// may need to make buffers available
EmitPendingBuffers(false, mustWait);
mustWait = false;
// use current buffer, or get a new buffer to fill
int ix = -1;
if (_currentlyFilling >= 0)
{
ix = _currentlyFilling;
TraceOutput(TraceBits.WriteTake,
"Write notake wi({0}) lf({1})",
ix,
_lastFilled);
}
else
{
TraceOutput(TraceBits.WriteTake, "Write take?");
if (_toFill.Count == 0)
{
// no available buffers, so... need to emit
// compressed buffers.
mustWait = true;
continue;
}
ix = _toFill.Dequeue();
TraceOutput(TraceBits.WriteTake,
"Write take wi({0}) lf({1})",
ix,
_lastFilled);
++_lastFilled; // TODO: consider rollover?
}
WorkItem workitem = _pool[ix];
int limit = ((workitem.buffer.Length - workitem.inputBytesAvailable) > count)
? count
: (workitem.buffer.Length - workitem.inputBytesAvailable);
workitem.ordinal = _lastFilled;
TraceOutput(TraceBits.Write,
"Write lock wi({0}) ord({1}) iba({2})",
workitem.index,
workitem.ordinal,
workitem.inputBytesAvailable
);
// copy from the provided buffer to our workitem, starting at
// the tail end of whatever data we might have in there currently.
Buffer.BlockCopy(buffer,
offset,
workitem.buffer,
workitem.inputBytesAvailable,
limit);
count -= limit;
offset += limit;
workitem.inputBytesAvailable += limit;
if (workitem.inputBytesAvailable == workitem.buffer.Length)
{
// No need for interlocked.increment: the Write()
// method is documented as not multi-thread safe, so
// we can assume Write() calls come in from only one
// thread.
TraceOutput(TraceBits.Write,
"Write QUWI wi({0}) ord({1}) iba({2}) nf({3})",
workitem.index,
workitem.ordinal,
workitem.inputBytesAvailable );
#if !PCL
if (!ThreadPool.QueueUserWorkItem( _DeflateOne, workitem ))
throw new Exception("Cannot enqueue workitem");
#else
System.Threading.Tasks.Task.Run(() => _DeflateOne(workitem));
#endif
_currentlyFilling = -1; // will get a new buffer next time
}
else
_currentlyFilling = ix;
if (count > 0)
TraceOutput(TraceBits.WriteEnter, "Write more");
}
while (count > 0); // until no more to write
TraceOutput(TraceBits.WriteEnter, "Write exit");
return;
}
public void Zlib_ParallelDeflateStream() { var sw = new System.Diagnostics.Stopwatch(); sw.Start(); TestContext.WriteLine("{0}: Zlib_ParallelDeflateStream Start", sw.Elapsed); int sz = 256*1024 + this.rnd.Next(120000); string FileToCompress = System.IO.Path.Combine(TopLevelDir, String.Format("Zlib_ParallelDeflateStream.{0}.txt", sz)); CreateAndFillFileText( FileToCompress, sz); TestContext.WriteLine("{0}: Created file: {1}", sw.Elapsed, FileToCompress ); byte[] original = File.ReadAllBytes(FileToCompress); int crc1 = DoCrc(FileToCompress); TestContext.WriteLine("{0}: Original CRC: {1:X8}", sw.Elapsed, crc1 ); byte[] working = new byte[WORKING_BUFFER_SIZE]; int n = -1; long originalLength; MemoryStream ms1 = new MemoryStream(); { using (FileStream fs1 = File.OpenRead(FileToCompress)) { originalLength = fs1.Length; using (var compressor = new Ionic.Zlib.ParallelDeflateOutputStream(ms1, true)) { while ((n = fs1.Read(working, 0, working.Length)) != 0) { compressor.Write(working, 0, n); } } } ms1.Seek(0, SeekOrigin.Begin); } TestContext.WriteLine("{0}: Compressed {1} bytes into {2} bytes", sw.Elapsed, originalLength, ms1.Length); var crc = new Ionic.Crc.CRC32(); int crc2= 0; byte[] decompressedBytes= null; using (MemoryStream ms2 = new MemoryStream()) { using (var decompressor = new DeflateStream(ms1, CompressionMode.Decompress, false)) { while ((n = decompressor.Read(working, 0, working.Length)) != 0) { ms2.Write(working, 0, n); } } TestContext.WriteLine("{0}: Decompressed", sw.Elapsed); TestContext.WriteLine("{0}: Decompressed length: {1}", sw.Elapsed, ms2.Length); ms2.Seek(0, SeekOrigin.Begin); crc2 = crc.GetCrc32(ms2); decompressedBytes = ms2.ToArray(); TestContext.WriteLine("{0}: Decompressed CRC: {1:X8}", sw.Elapsed, crc2 ); } TestContext.WriteLine("{0}: Checking...", sw.Elapsed ); bool check = true; if (originalLength != decompressedBytes.Length) { TestContext.WriteLine("Different lengths."); check = false; } else { for (int i = 0; i < decompressedBytes.Length; i++) { if (original[i] != decompressedBytes[i]) { TestContext.WriteLine("byte {0} differs", i); check = false; break; } } } Assert.IsTrue(check,"Data check failed"); TestContext.WriteLine("{0}: Done...", sw.Elapsed ); }