我最近在做一个涉及很多FileStreaming
的项目,这是我以前没有真正接触过的。
为了尝试更好地熟悉这些方法的原理,我编写了一些代码(理论上)将文件从一个 dir
下载到另一个,并逐步完成,在我的评论中了解每个步骤实现的目标,就像这样......
从 DownloadRequest 对象获取 fileinfo 对象
RemoteFileInfo fileInfo = svr.DownloadFile(request);
WCF 服务中的 DownloadFile 方法
public RemoteFileInfo DownloadFile(DownloadRequest request)
{
RemoteFileInfo result = new RemoteFileInfo(); // create empty fileinfo object
try
{
// set filepath
string filePath = System.IO.Path.Combine(request.FilePath , @"\" , request.FileName);
System.IO.FileInfo fileInfo = new System.IO.FileInfo(filePath); // get fileinfo from path
// check if exists
if (!fileInfo.Exists)
throw new System.IO.FileNotFoundException("File not found",
request.FileName);
// open stream
System.IO.FileStream stream = new System.IO.FileStream(filePath,
System.IO.FileMode.Open, System.IO.FileAccess.Read);
// return result
result.FileName = request.FileName;
result.Length = fileInfo.Length;
result.FileByteStream = stream;
}
catch (Exception ex)
{
// do something
}
return result;
}
使用从 fileinfo 返回的 FileStream 读入新的写入流
// set new location for downloaded file
string basePath = System.IO.Path.Combine(@"C:\SST Software\DSC\Compilations\" , compName, @"\");
string serverFileName = System.IO.Path.Combine(basePath, file);
double totalBytesRead = 0.0;
if (!Directory.Exists(basePath))
Directory.CreateDirectory(basePath);
int chunkSize = 2048;
byte[] buffer = new byte[chunkSize];
// create new write file stream
using (System.IO.FileStream writeStream = new System.IO.FileStream(serverFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
do
{
// read bytes from fileinfo stream
int bytesRead = fileInfo.FileByteStream.Read(buffer, 0, chunkSize);
totalBytesRead += (double)bytesRead;
if (bytesRead == 0) break;
// write bytes to output stream
writeStream.Write(buffer, 0, bytesRead);
} while (true);
// report end
Console.WriteLine(fileInfo.FileName + " has been written to " + basePath + " - Done!");
writeStream.Close();
}
我所希望的是对使用 FileStream
时到底发生了什么的任何澄清或扩展。
我可以实现下载,现在我知道我需要编写什么代码来执行这样的下载,但我想知道更多关于为什么它有效的信息。我在网上找不到任何“初学者友好”或分步说明。
幕后发生了什么?
最佳答案
流只是一种抽象,从根本上说,它就像数据集合中的指针一样工作。
以“Hello World!”为例例如,它只是字符的集合,从根本上讲只是字节。
作为一个流,它可以表示为:
- 长度为 12(可能更多,包括终止字符等)
- 流中的位置。
您通过移动位置和请求数据来读取流。
所以阅读上面的文本可能(在伪代码中)看起来像这样:
do
get next byte
add gotten byte to collection
while not the end of the stream
the entire data is now in the collection
在从文件系统或远程机器等来源访问数据时,流真的很有用。
想象一个大小为几千兆字节的文件,如果操作系统在程序(例如视频播放器)想要读取它时将所有文件加载到内存中,就会出现很多问题。
相反,程序请求访问文件,操作系统返回一个流;流告诉程序有多少数据,并允许它访问该数据。
根据具体实现,操作系统可能会在程序访问数据之前将一定数量的数据加载到内存中,这称为缓冲区。
但从根本上说,程序只是请求下一位数据,而操作系统要么从缓冲区中获取,要么从源(例如磁盘上的文件)获取。
相同的原则适用于不同计算机之间的流,除了请求下一位数据很可能涉及到远程机器请求它。
.NET FileStream
类和 Stream
基类,最终都只是遵从 Windows 系统处理流,它们没有什么特别之处,这正是您可以用抽象来做的事情,使它们如此强大。
写入流是一样的,但它只是将数据放入缓冲区,以供请求者访问。
无限数据
正如用户指出的,流可用于不确定长度的数据。
所有流操作都需要时间,因此读取流通常是一个阻塞操作,会等待数据可用。
因此,当流仍然打开时,您可以永远循环,并等待数据进入 - 这在实践中的一个例子是实时视频广播。
关于c# - FileStreaming 背后的原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29916087/