FileStreaming 背后的原理

Principles behind FileStreaming

我最近在做一个涉及很多FileStreaming的项目,这是我以前没有真正接触过的。
为了尝试更好地了解这些方法的原理,我编写了一些代码(理论上)将文件从一个 dir 下载到另一个,并逐步完成,评论我对什么的理解每一步都实现了,就像这样...

从 DownloadRequest 对象获取文件信息对象

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 时到底发生了什么的任何澄清或扩展。
我可以实现下载,现在我知道我需要编写什么代码才能执行这样的下载,但我想知道更多关于 为什么 它有效的信息。我在网上找不到 'beginner-friendly' 或分步说明。

幕后发生了什么?

流只是一种抽象,从根本上说,它就像数据集合中的指针一样工作。

以"Hello World!"的例子字符串为例,它只是字符的集合,本质上就是字节。

作为流,它可以表示为:

  1. 长度为 12(可能更多,包括终止字符等)
  2. 流中的位置。

您通过移动位置和请求数据来读取流。

所以阅读上面的文字(在伪代码中)可能是这样的:

do
    get next byte
    add gotten byte to collection
while not the end of the stream

the entire data is now in the collection

在从文件系统或远程机器等来源访问数据时,流确实有用。

想象一个大小为几千兆字节的文件,如果 OS 在程序想要读取它(比如视频播放器)时将所有文件加载到内存中,就会出现很多问题.

相反,程序请求访问文件,OS returns 一个流;流告诉程序有多少数据,并允许它访问该数据。

根据实现的不同,OS 可能会在程序访问它之前将一定数量的数据加载到内存中,这被称为 缓冲区

但从根本上说,程序只是请求下一位数据,OS 要么从缓冲区获取数据,要么从源(例如磁盘上的文件)获取数据。

相同的原则适用于不同计算机之间的流,除了请求下一位数据很可能涉及到远程机器请求它。

.NET FileStream class 和 Stream 基础 class,最终都只是遵从 windows 系统来处理流,它们并没有什么特别之处,只是你可以用抽象来做些什么,使它们如此强大。

写入流是一样的,只是将数据放入缓冲区,以供请求者访问。


无限数据

正如用户指出的,流可用于不确定长度的数据。

所有流操作都需要时间,因此读取流通常是一个阻塞操作,会等待数据可用。

因此您可以在流仍然打开时一直循环,并等待数据进入 - 实际中的一个例子是实时视频广播。

我找到了一本书 - C# 5.0 All-In-One For Dummies - 它解释了所有 Stream 类 的一切,它们是如何工作的,哪一个是最合适的等等。
才读了大概30分钟,就已经有了这样的理解。
优秀的向导!