我有一个文件列表,我需要按特定顺序将它们读取到给定大小的byte [].这对于单个文件本身不是问题,简单的((got = fs.Read(piece,0,pieceLength))> 0)完成工作完全正常.文件的最后一段可能比期望的要小,这很好.
现在,有一个棘手的问题:如果我有多个文件,我需要有一个连续的流,这意味着如果文件的最后一块小于pieceLength,那么我需要读取(pieceLength-got)的下一个文件,然后继续,直到最后一个文件的结尾.
基本上,给定X文件,我将始终读取完全为pieceLength long的部分,除了最后一个文件的最后一部分,它可能更小.
我只是想知道是否已经在.net(3.5 SP1)中构建了一些功能.我目前的方法是创建一个接受文件列表然后公开Read(byte[] buffer, long index, long length)
函数的类,类似于FileStream.Read().这应该是非常直接的,因为我不必更改我的读取数据的调用代码,但在重新发明轮子之前,我只想仔细检查轮子是否已经内置到BCL中.
谢谢 :)
我不相信框架中有任何内容,但我建议让它更灵活一点 - IEnumerable<Stream>
在构造函数中使用,并从Stream
自己派生.然后你可以得到文件流(假设C#3.0):
Stream combined = new CombinationStream(files.Select(file => File.Open(file));
Run Code Online (Sandbox Code Playgroud)
"所有权"部分在这里有点棘手 - 上面的内容将允许组合流获取其读取的任何流的所有权,但您可能不希望它必须遍历所有其余流并将它们全部关闭如果它是过早关闭.
这是我根据@jon skeet 的想法想到的。
它只是实现了 Read 这对我来说已经足够了。(但我不需要帮助实现 BeginRead/EndRead 方法。)这是包含同步和异步的完整代码 - Read 和 BeginRead/EndRead
internal class CombinationStream : System.IO.Stream
{
private readonly System.Collections.Generic.IList<System.IO.Stream> _streams;
private int _currentStreamIndex;
private System.IO.Stream _currentStream;
private long _length = -1;
private long _postion;
public CombinationStream(System.Collections.Generic.IList<System.IO.Stream> streams)
{
if (streams == null)
{
throw new System.ArgumentNullException("streams");
}
_streams = streams;
if (streams.Count > 0)
{
_currentStream = streams[_currentStreamIndex++];
}
}
public override void Flush()
{
if (_currentStream != null)
{
_currentStream.Flush();
}
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
throw new System.InvalidOperationException("Stream is not seekable.");
}
public override void SetLength(long value)
{
this._length = value;
}
public override int Read(byte[] buffer, int offset, int count)
{
int result = 0;
int buffPostion = offset;
while (count > 0)
{
int bytesRead = _currentStream.Read(buffer, buffPostion, count);
result += bytesRead;
buffPostion += bytesRead;
_postion += bytesRead;
if (bytesRead <= count)
{
count -= bytesRead;
}
if (count > 0)
{
if (_currentStreamIndex >= _streams.Count)
{
break;
}
_currentStream = _streams[_currentStreamIndex++];
}
}
return result;
}
public override long Length
{
get
{
if (_length == -1)
{
_length = 0;
foreach (var stream in _streams)
{
_length += stream.Length;
}
}
return _length;
}
}
public override long Position
{
get { return this._postion; }
set { throw new System.NotImplementedException(); }
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new System.InvalidOperationException("Stream is not writable");
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
}
Run Code Online (Sandbox Code Playgroud)
也可作为 NuGet 包使用
Install-Package CombinationStream
Run Code Online (Sandbox Code Playgroud)