如何将包含PDF文件数据的两个内存流合并为一个

时间:2015-08-25 12:41:43

标签: c# itextsharp memorystream

我正在尝试将两个PDF文件读入两个内存流,然后返回一个包含两个流数据的流。但我似乎不明白我的代码有什么问题。

示例代码:

string file1Path = "Sampl1.pdf";
string file2Path = "Sample2.pdf";
MemoryStream stream1 = new MemoryStream(File.ReadAllBytes(file1Path));
MemoryStream stream2 = new MemoryStream(File.ReadAllBytes(file2Path));
stream1.Position = 0;
stream1.Copyto(stream2);
return stream2;   /*supposed to be containing data of both stream1 and stream2 but contains data of stream1 only*/  

1 个答案:

答案 0 :(得分:5)

注意:

  

整个问题基于一个错误的前提,即您可以通过合并两个PDF文件的二进制文件来生成合并的PDF文件。这适用于纯文本文件,例如(在某种程度上),但绝对不适用于PDF。答案仅解决了如何合并两个二进制数据流,而不是如何合并两个PDF文件。它回答了OP提出的问题,但实际上并没有解决他的问题。

byte[]使用MemoryStream构造函数时,在添加更多数据时内存流不会扩展。因此,stream1stream2都不够大。此外,该位置将从零开始,因此您使用stream2中的数据覆盖stream1

修复很简单:

var result = new MemoryStream();
using (var file1 = File.OpenRead(file1Path)) file1.CopyTo(result);
using (var file2 = File.OpenRead(file2Path)) file2.CopyTo(result);

另一种选择是创建自己的流类,它将是两个独立流的组合 - 如果您对可组合性感兴趣,那么这很有趣,但对于像这样简单的东西可能有点过分了:)

只是为了好玩,它看起来像这样:

public class DualStream : Stream
{
    private readonly Stream _first;
    private readonly Stream _second;

    public DualStream(Stream first, Stream second)
    {
        _first = first;
        _second = second;
    }

    public override bool CanRead => true;
    public override bool CanSeek => true;
    public override bool CanWrite => false;
    public override long Length => _first.Length + _second.Length;

    public override long Position
    {
        get { return _first.Position + _second.Position; }
        set { Seek(value, SeekOrigin.Begin); }
    }

    public override void Flush() { throw new NotImplementedException(); }

    public override int Read(byte[] buffer, int offset, int count)
    {
        var bytesRead = _first.Read(buffer, offset, count);

        if (bytesRead == count) return bytesRead;

        return bytesRead + _second.Read(buffer, offset + bytesRead, count - bytesRead);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        // To simplify, let's assume seek always works as if over one big MemoryStream
        long targetPosition;

        switch (origin)
        {
            case SeekOrigin.Begin: targetPosition = offset; break;
            case SeekOrigin.Current: targetPosition = Position + offset; break;
            case SeekOrigin.End: targetPosition = Length - offset; break;
            default: throw new NotSupportedException();
        }

        targetPosition = Math.Max(0, Math.Min(Length, targetPosition));

        var firstPosition = Math.Min(_first.Length, targetPosition);
        _first.Position = firstPosition;
        _second.Position = Math.Max(0, targetPosition - firstPosition);

        return Position;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _first.Dispose();
            _second.Dispose();
        }

        base.Dispose(disposing);
    }

    public override void SetLength(long value) 
      { throw new NotImplementedException(); }
    public override void Write(byte[] buffer, int offset, int count) 
      { throw new NotImplementedException(); }
}

主要的好处是,它意味着你不必分配不必要的内存缓冲区只是为了拥有一个组合流 - 它甚至可以直接与文件流一起使用,如果你敢:D和它&# 39;易于组合 - 您可以制作其他双流的双流,允许您将所需数量的流链接在一起 - 与IEnumerable.Concat几乎相同。