- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在将一些旧代码转换为在 c# 中使用异步时,我开始发现 DeflateStream 的 Read() 和 ReadAsync() 方法的返回值变体存在问题。
我认为从同步代码转换过来
bytesRead = deflateStream.Read(buffer, 0, uncompressedSize);
它是
的等效异步版本bytesRead = await deflateStream.ReadAsync(buffer, 0, uncompressedSize);
应该总是返回相同的值。
查看添加到问题底部的更新代码 - 以正确的方式使用流 - 因此使最初的问题变得无关紧要
我发现在多次迭代后这并不成立,在我的特定情况下导致转换后的应用程序出现随机错误。
我是不是漏掉了什么?
下面是简单的重现案例(在控制台应用程序中),其中 Assert
将在迭代 #412 的 ReadAsync
方法中为我中断,输出看起来像这个:
....
ReadAsync #410 - 2055 bytes read
ReadAsync #411 - 2055 bytes read
ReadAsync #412 - 453 bytes read
---- DEBUG ASSERTION FAILED ----
我的问题是,为什么此时 DeflateStream.ReadAsync
方法返回 453 个字节?
注意:这只发生在某些输入字符串上——CreateProblemDataString
中大量的 StringBuilder
是我能想到的为这篇文章构建字符串的最佳方式。
class Program
{
static byte[] DataAsByteArray;
static int uncompressedSize;
static void Main(string[] args)
{
string problemDataString = CreateProblemDataString();
DataAsByteArray = Encoding.ASCII.GetBytes(problemDataString);
uncompressedSize = DataAsByteArray.Length;
MemoryStream memoryStream = new MemoryStream();
using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, true))
{
for (int i = 0; i < 1000; i++)
{
deflateStream.Write(DataAsByteArray, 0, uncompressedSize);
}
}
// now read it back synchronously
Read(memoryStream);
// now read it back asynchronously
Task retval = ReadAsync(memoryStream);
retval.Wait();
}
static void Read(MemoryStream memoryStream)
{
memoryStream.Position = 0;
using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress, true))
{
byte[] buffer = new byte[uncompressedSize];
int bytesRead = -1;
int i = 0;
while (bytesRead > 0 || bytesRead == -1)
{
bytesRead = deflateStream.Read(buffer, 0, uncompressedSize);
System.Diagnostics.Debug.WriteLine("Read #{0} - {1} bytes read", i, bytesRead);
System.Diagnostics.Debug.Assert(bytesRead == 0 || bytesRead == uncompressedSize);
i++;
}
}
}
static async Task ReadAsync(MemoryStream memoryStream)
{
memoryStream.Position = 0;
using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress, true))
{
byte[] buffer = new byte[uncompressedSize];
int bytesRead = -1;
int i = 0;
while (bytesRead > 0 || bytesRead == -1)
{
bytesRead = await deflateStream.ReadAsync(buffer, 0, uncompressedSize);
System.Diagnostics.Debug.WriteLine("ReadAsync #{0} - {1} bytes read", i, bytesRead);
System.Diagnostics.Debug.Assert(bytesRead == 0 || bytesRead == uncompressedSize);
i++;
}
}
}
/// <summary>
/// This is one of the strings of data that was causing issues.
/// </summary>
/// <returns></returns>
static string CreateProblemDataString()
{
StringBuilder sb = new StringBuilder();
sb.Append("0601051081 ");
sb.Append(" ");
sb.Append(" 225021 0300420");
sb.Append("34056064070072076361102 13115016017");
sb.Append("5 192 230237260250 2722");
sb.Append("73280296 326329332 34535535");
sb.Append("7 3 ");
sb.Append(" 4");
sb.Append(" ");
sb.Append(" 50");
sb.Append("6020009 030034045 063071076 360102 13");
sb.Append("1152176160170 208206 23023726025825027227328");
sb.Append("2283285 320321333335341355357 622005009 0");
sb.Append("34053 060070 361096 130151176174178172208");
sb.Append("210198 235237257258256275276280290293 3293");
sb.Append("30334 344348350 ");
sb.Append(" ");
sb.Append(" ");
sb.Append(" ");
sb.Append(" 225020012014 046042044034061");
sb.Append("075078 361098 131152176160170 208195210 230");
sb.Append("231260257258271272283306 331332336 3443483");
sb.Append("54 29 ");
sb.Append(" ");
sb.Append(" 2");
sb.Append("5 29 06 0");
sb.Append("1 178 17");
sb.Append("4 205 2");
sb.Append("05 195 2");
sb.Append("31 231 23");
sb.Append("7 01 01 0");
sb.Append("2 260 26");
sb.Append("2 274 2");
sb.Append("72 274 01 01 0");
sb.Append("3 1 5 3 6 43 52 ");
return sb.ToString();
}
}
更新代码以正确地将流读入缓冲区
输出现在看起来像这样:
...
ReadAsync #410 - 2055 bytes read
ReadAsync #411 - 2055 bytes read
ReadAsync PARTIAL #412 - 453 bytes read, offset for next read = 453
ReadAsync #412 - 1602 bytes read
ReadAsync #413 - 2055 bytes read
...
static void Read(MemoryStream memoryStream)
{
memoryStream.Position = 0;
using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress, true))
{
byte[] buffer = new byte[uncompressedSize]; // buffer to hold known fixed size record.
int bytesRead; // number of bytes read from Read operation
int offset = 0; // offset for writing into buffer
int i = -1; // counter to track iteration #
while ((bytesRead = deflateStream.Read(buffer, offset, uncompressedSize - offset)) > 0)
{
offset += bytesRead; // offset in buffer for results of next reading
System.Diagnostics.Debug.Assert(offset <= uncompressedSize, "should never happen - because would mean more bytes read than requested.");
if (offset == uncompressedSize) // buffer full, complete fixed size record in buffer.
{
offset = 0; // buffer is now filled, next read to start at beginning of buffer again.
i++; // increment counter that tracks iteration #
System.Diagnostics.Debug.WriteLine("Read #{0} - {1} bytes read", i, bytesRead);
}
else // buffer still not full
{
System.Diagnostics.Debug.WriteLine("Read PARTIAL #{0} - {1} bytes read, offset for next read = {2}", i+1, bytesRead, offset);
}
}
}
}
static async Task ReadAsync(MemoryStream memoryStream)
{
memoryStream.Position = 0;
using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress, true))
{
byte[] buffer = new byte[uncompressedSize]; // buffer to hold known fixed size record.
int bytesRead; // number of bytes read from Read operation
int offset = 0; // offset for writing into buffer
int i = -1; // counter to track iteration #
while ((bytesRead = await deflateStream.ReadAsync(buffer, offset, uncompressedSize - offset)) > 0)
{
offset += bytesRead; // offset in buffer for results of next reading
System.Diagnostics.Debug.Assert(offset <= uncompressedSize, "should never happen - because would mean more bytes read than requested.");
if (offset == uncompressedSize) // buffer full, complete fixed size record in buffer.
{
offset = 0; // buffer is now filled, next read to start at beginning of buffer again.
i++; // increment counter that tracks iteration #
System.Diagnostics.Debug.WriteLine("ReadAsync #{0} - {1} bytes read", i, bytesRead);
}
else // buffer still not full
{
System.Diagnostics.Debug.WriteLine("ReadAsync PARTIAL #{0} - {1} bytes read, offset for next read = {2}", i+1, bytesRead, offset);
}
}
}
}
最佳答案
Damien 的评论完全正确。但是,你的错误很常见,恕我直言,这个问题值得一个实际的答案,如果没有其他原因,只是为了帮助犯同样错误的其他人更容易找到问题的答案。
所以,要清楚:
对于 .NET 中所有面向流的 I/O 方法都是如此,其中一个方法提供一个 byte[]
缓冲区并且读取的字节数由该方法返回,唯一的假设你可以做出大概的字节数是:
当使用这些方法中的任何一种进行阅读时,您甚至不能指望相同的方法总是返回相同数量的字节(取决于上下文……显然在某些情况下,这实际上是确定性的,但您仍然不应该依赖它), 并且不能保证不同的方法,即使是从同一源读取的方法,也总是会返回与其他方法相同的字节数。
由调用者将字节作为流读取,考虑指定每次调用读取的字节数的返回值,并以适合该特定字节流的任何方式重新组装这些字节。
注意在处理Stream
对象时,可以使用Stream.CopyTo()
方法。当然,它只是复制到另一个 Stream
对象。但在许多情况下,无需将目标对象视为 Stream
即可使用。例如。您只想将数据作为文件写入,或者您想将其复制到 MemoryStream
,然后使用 MemoryStream.ToArray()
方法将其转换为数组字节数(然后您可以访问它而无需担心在给定的读取操作中读取了多少字节......当您到达数组时,所有这些都已被读取:))。
关于c# - DeflateStream.ReadAsync (.NET 4.5 System.IO.Compression) 读取字节的返回值与等效读取方法不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27821889/
zlib中的deflate()和compress()函数之间有什么区别? 我浏览了在线示例,其中一些使用deflate,而另一些使用compress。 我应该如何决定在哪种情况下使用另一种情况? 最佳
这是我的config.rb preferred_syntax = :sass http_path = '/' css_dir = 'css' sass_dir = 'sass' images_dir
我正在查看 Oracle 的 OLTP 表压缩(11g 及以上)文档以及在线资源以查找语法并遇到两个不同的版本: COMPRESS FOR ALL OPERATIONS 和 COMPRESS FOR
我目前在 .NET 2.0 下使用 SharpZipLib,通过它我需要将单个文件压缩为单个压缩存档。为此,我目前正在使用以下内容: string tempFilePath = @"C:\Users\
本文整理了Java中org.apache.hadoop.io.compress.zlib.ZlibCompressor.compress()方法的一些代码示例,展示了ZlibCompressor.co
我从 Azure Synapse 收到此建议。 推荐详情我们检测到您可以通过拆分存储帐户中暂存的压缩文件来提高负载吞吐量。一个好的经验法则是将压缩文件拆分为 60 个或更多,以最大限度地提高负载的并行
这个问题继续讨论开始 here 。我发现 HTTP 响应正文无法被解码为 JSON 对象,因为后者的 deflate 压缩。现在我想知道如何用Golang进行解压。我将不胜感激任何能够显示我的代码中的
我刚开始为新雇主工作。对于我的上一个雇主,我们使用 LESS 并将其编译为 .css 文件,然后将其压缩为 .min.css 文件。对于我的新雇主,我们也使用 LESS。但是这里我们不仅编译了LESS
我在终端中使用 compress file.txt 压缩了一个文件并得到了(如预期的那样)file.txt.Z 当我将该文件传递给 Go 中的 ioutil.ReadFile 时, buf0, err
当我打开Android Studio时,Android Studio将从commons-compress-1.12.jar下载https://jcenter.bintray.com/org/apach
我收到此错误,但我不知道为什么突然遇到 django-pipeline 问题。 我正在 virtualenv 下运行该项目,我尝试使用所需的基本应用程序创建一个新项目,看看它是否可以修复它,但我总是收
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
对于压缩由 fasta 核苷酸序列组成的数据集,推荐的压缩算法是什么(.xz、tar.gz、tar.bz2 等)? 此类数据的推荐压缩机制是什么? 基于字典的压缩 基于自适应字典的压缩 基于LZW算法
我正在寻找一个支持解压期间随机访问的通用压缩库。我想将维基百科压缩成单一的压缩格式,同时我想从中解压/提取个别文章。 当然,我可以单独压缩每篇文章,但这不会给出太大的压缩率。我听说 LZO 压缩文件由
我想压缩一串位,然后我想解压缩它。任何机构都可以通过提及快速无损压缩和解压缩技术来帮助我,如果可能的话,它的编程实现可以帮助我。 最佳答案 如果您正在寻找速度,那么考虑像 LZ4 这样的快速压缩算法是
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 4年前关闭。 Improve this qu
当我们压缩一个文件夹时,我们输入命令tar -cjf folder.tar.bz2 folder,它会将整个文件夹压缩到其中。 无论如何要压缩文件夹中的所有内容,但该文件夹不应出现在存档中? 示例 -
来自 Shannon's Source Coding Theorem我们知道压缩字符串的熵受原始字符串熵的限制,如下所示: H(X) <= L < H(X) + 1/N 其中 H(X) 是源字符串的熵
假设您有一个四字节整数,并且您想将其压缩为更少的字节。您可以压缩它,因为较小的值比较大的值更有可能(即,值的概率随其大小而降低)。您应用以下方案来生成 1、2、3 或 4 字节的结果: 请注意,在下面
是否有可能使用某种简单算法打包大文件,使我读取数据的速度比未压缩文件快(由于硬盘驱动器比未压缩速度慢)? 我需要什么样的压缩率?任何快速压缩算法都能做到吗? 最佳答案 是。当从硬盘上读取压缩系数为4的
我是一名优秀的程序员,十分优秀!