这是我关于 downloading files in chunks 问题的延续.解释会很大,所以我会尽量把它分成几个部分。
1)我试图做什么?
我正在为 Window-Phone 应用程序创建一个下载管理器。首先我尝试解决下载的问题
大文件(解释在上一个问题中)。不,我想添加“可恢复下载”功能。
2)我已经做过的事情。
目前我有一个运行良好的下载管理器,它可以超越 Windows Phone 的 RAM 限制。
这个管理器的特点是,它允许使用 HTTP Range header 下载小块文件。
对其工作原理的快速解释:
该文件以恒定大小的块下载。我们称这个大小为“delta”。下载文件块后,
它以追加模式保存到本地存储(硬盘,在 WP 上称为隔离存储)(因此,下载的字节数组是
总是添加到文件的末尾)。下载单个块后的语句
if (mediaFileLength >= delta) // mediaFileLength is a length of downloaded chunk
被检查。如果是真的,那
意味着,还有一些东西可供下载,并且这个方法被递归调用。否则就意味着,这个块
是最后一个,没有什么可以下载了。
3)有什么问题?
直到我在一次性下载时使用了这个逻辑(一次性我的意思是,当您开始下载文件并等待下载完成时)
效果很好。但是,我决定,我需要“恢复下载”功能。 所以,事实:
3.1) 我知道,文件块大小是一个常数。
3.2) 我知道,当文件完全下载与否。 (这是我的应用程序逻辑的间接结果,
不会因解释而使您厌烦,只是假设这是事实)
在这两个陈述的假设下,我可以证明,下载的块数等于
(CurrentFileLength)/delta .其中 CurrentFileLenght 是已下载文件的大小(以字节为单位)。
要继续下载文件,我应该简单地设置所需的标题并调用下载方法。这似乎是逻辑,不是吗?我试图实现它:
// Check file size
using (IsolatedStorageFileStream fileStream = isolatedStorageFile.OpenFile("SomewhereInTheIsolatedStorage", FileMode.Open, FileAccess.Read))
{
int currentFileSize = Convert.ToInt32(fileStream.Length);
int currentFileChunkIterator = currentFileSize / delta;
}
我看到的结果是什么?下载的文件长度等于 2432000 字节( delta 是 304160 ,总文件大小约为 4,5 MB ,我们只下载了其中的一半)。所以结果是
大约 7,995 . (它实际上是 long/int 类型,所以它是 7,而应该是 8!)为什么会发生这种情况?
简单的数学告诉我们,文件长度应该是 2433280 ,所以给定的值非常接近,但不相等。
进一步的调查表明,所有值都来自
fileStream.Length
不准确,但都接近。为什么会这样? 我不知道确切,但也许 .Length 值是从文件元数据中获取的。
也许,这种四舍五入对于这种方法来说是正常的。也许,当下载中断时,文件没有完全保存......(不,那真的很棒,不可能)
所以问题就解决了 - 它是 “如何确定下载的块数” .问题是如何解决。
4)我对解决问题的想法。
我的第一个想法是在这里使用数学。设置一些 epsilon-neiborhood 并在
currentFileChunkIterator = currentFileSize / delta;
中使用它声明。但这将要求我们记住第一类和第二类错误(或者误报和错过,如果您不喜欢统计术语。)也许,没有什么可以下载的了。
另外,我没有检查,如果提供的值和真实值的差异应该永久增长
否则会出现周期性波动。对于小尺寸(大约 4-5 MB),我只看到了增长,但这并不能证明什么。
所以,我在这里寻求帮助,因为我不喜欢我的解决方案。
5) 我想听到的答案是:
是什么导致了实际值(value)和接收值(value)之间的差异?
有没有办法获得真正的值(value)?
如果没有,我的解决方案是否适合这个问题?
还有其他更好的解决方案吗?
附言我不会设置 Windows-Phone 标签,因为我不确定这个问题是否与操作系统有关。我使用了隔离存储工具
检查下载文件的大小,它向我显示与收到的值相同(我很抱歉截图中的俄语):
最佳答案
我正在回答您的更新:
到目前为止,这是我的理解:实际写入文件的长度(四舍五入到下一个 1KiB)比您实际写入文件的长度要长。这会导致您对“file.Length == 下载量”的假设是错误的。
一种解决方案是单独跟踪此信息。创建一些元数据结构(可以使用相同的存储机制持久化)以准确跟踪已下载的块以及文件的整个大小:
[DataContract] //< I forgot how serialization on the phone works, please forgive me if the tags differ
struct Metadata
{
[DataMember]
public int Length;
[DataMember]
public int NumBlocksDownloaded;
}
假设您继续以连续方式下载它们,这足以重建哪些块已被下载,哪些块尚未下载。
编辑
当然,在将数据写入流之前,您必须将代码从简单的追加更改为将流的位置移动到正确的块:
file.Position = currentBlock * delta;
file.Write(block, 0, block.Length);
关于c# - "Where are my bytes?"或文件长度特征调查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14848786/