PrefetchedStream.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /* Copyright (C) 2016 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Text;
  11. using System.Threading;
  12. namespace Utilities
  13. {
  14. public class PrefetchedStream : Stream
  15. {
  16. public const int CacheSize = 1048576; // 1 MB
  17. private long m_cacheOffset;
  18. private byte[] m_cache = new byte[0];
  19. private Stream m_stream;
  20. private object m_syncLock = new object();
  21. public PrefetchedStream(Stream stream)
  22. {
  23. m_stream = stream;
  24. if (m_stream.CanRead)
  25. {
  26. new Thread(delegate()
  27. {
  28. lock (m_syncLock)
  29. {
  30. m_cacheOffset = 0;
  31. m_cache = new byte[CacheSize];
  32. int bytesRead = m_stream.Read(m_cache, 0, CacheSize);
  33. System.Diagnostics.Debug.Print("[{0}] {1} bytes have been prefetched.", DateTime.Now.ToString("HH:mm:ss:ffff"), bytesRead);
  34. this.Position = 0;
  35. if (bytesRead < CacheSize)
  36. {
  37. // EOF, we must trim the response data array
  38. m_cache = ByteReader.ReadBytes(m_cache, 0, bytesRead);
  39. }
  40. }
  41. }).Start();
  42. }
  43. }
  44. public override int Read(byte[] buffer, int offset, int count)
  45. {
  46. long position;
  47. lock (m_syncLock)
  48. {
  49. position = this.Position;
  50. bool isInCache = (position >= m_cacheOffset) && (position + count <= m_cacheOffset + m_cache.Length);
  51. if (!isInCache)
  52. {
  53. m_cacheOffset = position;
  54. int cacheSize = Math.Max(CacheSize, count);
  55. m_cache = new byte[cacheSize];
  56. int bytesRead = m_stream.Read(m_cache, 0, cacheSize);
  57. if (bytesRead < cacheSize)
  58. {
  59. // EOF, we must trim the response data array
  60. m_cache = ByteReader.ReadBytes(m_cache, 0, bytesRead);
  61. }
  62. }
  63. }
  64. int offsetInCache = (int)(position - m_cacheOffset);
  65. int bytesRemained = m_cache.Length - offsetInCache;
  66. int dataLength = Math.Min(count, bytesRemained);
  67. Array.Copy(m_cache, offsetInCache, buffer, offset, dataLength);
  68. lock (m_syncLock)
  69. {
  70. this.Position = position + dataLength;
  71. }
  72. return dataLength;
  73. }
  74. public override void Write(byte[] buffer, int offset, int count)
  75. {
  76. m_cache = new byte[0];
  77. m_stream.Write(buffer, offset, count);
  78. }
  79. public override void Close()
  80. {
  81. m_stream.Close();
  82. base.Close();
  83. }
  84. public override bool CanRead
  85. {
  86. get
  87. {
  88. return m_stream.CanRead;
  89. }
  90. }
  91. public override bool CanSeek
  92. {
  93. get
  94. {
  95. return m_stream.CanSeek;
  96. }
  97. }
  98. public override bool CanWrite
  99. {
  100. get
  101. {
  102. return m_stream.CanWrite;
  103. }
  104. }
  105. public override long Length
  106. {
  107. get
  108. {
  109. return m_stream.Length;
  110. }
  111. }
  112. public override long Position
  113. {
  114. get
  115. {
  116. return m_stream.Position;
  117. }
  118. set
  119. {
  120. m_stream.Position = value;
  121. }
  122. }
  123. public override void Flush()
  124. {
  125. m_stream.Flush();
  126. }
  127. public override long Seek(long offset, SeekOrigin origin)
  128. {
  129. return m_stream.Seek(offset, origin);
  130. }
  131. public override void SetLength(long value)
  132. {
  133. m_stream.SetLength(value);
  134. }
  135. }
  136. }