0

我有两个 RIFF 文件,我正在将块从一个文件复制到另一个文件。我使用的 RIFF 格式是:

  • 4 字节 ASCII 标识符
  • 4 字节整数帧块长度(以字节为单位)
  • 数据(给定长度)

我使用以下代码从源文件复制到目标文件。块被称为帧。

public void CopySegmentTo(VPCaptureSession captureSession, int StartFrame, int EndFrame) {
        //captures several frames from this session onto the end of another one.
        //binary-styles

        Console.WriteLine(" captureSession.captureStream.Position: " + captureSession.captureStream.Position);
        long lastCaptureDestPosition = 0;

        captureSession.captureStream.Seek(0, SeekOrigin.End);
        int chunkLength; long timestamp; char[] charTag;

        for (int f = StartFrame; f <= EndFrame; f++)
        {
            Console.WriteLine("-----");

            this.captureStream.Seek(FrameTimes.ElementAt(f).Item3, SeekOrigin.Begin);

            Console.WriteLine("FrameIndex in this.captureStream: " + FrameTimes.ElementAt(f).Item3);

            BinaryReader reader = new BinaryReader(this.captureStream);
            byte[] tag = reader.ReadBytes(Tags.TAG_SIZE);
            charTag = TagChunk.encode.GetChars(tag);
            chunkLength = reader.ReadInt32();

            BinaryWriter writer = new BinaryWriter(captureSession.captureStream);
            writer.Write(tag);
            writer.Write(chunkLength);
            this.captureStream.CopyTo(captureSession.captureStream, chunkLength);

            long CaptureDestDelta = captureSession.captureStream.Position - lastCaptureDestPosition;

            Console.WriteLine("Loading " + f + " between " + StartFrame + "&" + EndFrame 
                + ". chunkLength: " + chunkLength
                + " this.captureStream.Position: " + this.captureStream.Position
                + " captureSession.captureStream.Position: " + captureSession.captureStream.Position
                + " CaptureDestDelta: " + CaptureDestDelta
                + " Delta Factor: " + CaptureDestDelta/chunkLength);

            lastCaptureDestPosition = captureSession.captureStream.Position;

        }

    }

复制速度很慢,生成的文件似乎很大。以下是Console输出示例:

captureSession.captureStream.Position: 0
-----
FrameIndex in this.captureStream: 0
Loading 0 between 0&5. chunkLength: 266736 this.captureStream.Position: 121225207 
captureSession.captureStream.Position: 121225207 CaptureDestDelta: 121225207 
Delta Factor: 454
-----
FrameIndex in this.captureStream: 266744
Loading 1 between 0&5. chunkLength: 311398 this.captureStream.Position: 121225207 
captureSession.captureStream.Position: 242183670 CaptureDestDelta: 120958463 
Delta Factor: 388
-----
FrameIndex in this.captureStream: 578150
Loading 2 between 0&5. chunkLength: 356578 this.captureStream.Position: 121225207 
captureSession.captureStream.Position: 362830727 CaptureDestDelta: 120647057 
Delta Factor: 338
-----
FrameIndex in this.captureStream: 934736
Loading 3 between 0&5. chunkLength: 430445 this.captureStream.Position: 121225207 
captureSession.captureStream.Position: 483121198 CaptureDestDelta: 120290471 
Delta Factor: 279
-----
FrameIndex in this.captureStream: 1365189
Loading 4 between 0&5. chunkLength: 437468 this.captureStream.Position: 121225207 
captureSession.captureStream.Position: 602981216 CaptureDestDelta: 119860018 
Delta Factor: 273
-----
FrameIndex in this.captureStream: 1802665
Loading 5 between 0&5. chunkLength: 439870 this.captureStream.Position: 121225207 
captureSession.captureStream.Position: 722403758 CaptureDestDelta: 119422542 
Delta Factor: 271

肯定发生了一些奇怪的事情。这是我看到的主要内容:

  • captureSession.captureStream.PositionchunkLength比每次都进步很多。

  • this.captureStream.Position每次复制后似乎总是一样的。

让我知道是否还有更多我可以记录的内容。我真的被困在这里了。

4

2 回答 2

2

您有几个问题,主要问题是Stream.Copy您调用的方法复制了整个流(从当前位置)。第二个参数是缓冲区大小,而不是要复制的字节数。

此外,您正在为循环的每次迭代创建一个新的BinaryReader和一个新的。BinaryWriter这两个类都分配托管资源,并且在您使用完它们后应该被释放。不幸的是,disposing 也会关闭底层流。但是留下这些对象只是在某个时候乞求资源匮乏问题,尤其是当您开始复制文件的大部分时。

我建议你放弃BinaryReaderandBinaryWriter直接去溪流。

您可以通过使用Stream.Read读取数据来做到这一点,唯一的困难是读取数据int需要您读取 4 个字节,然后调用BitConverter.ToInt32转换为整数。您还可以使用该方法从源复制数据(即读入大字节 [] 缓冲区),然后使用Stream.Write.

如果您使用的是 .NET 4.5,您还有另一个选择。在开始循环之前,BinaryReader您可以在输入上打开 a并BinaryWriter在输出上打开 a 。.NET 4.5 引入了一个新的构造函数,可让您决定是否要在处理读取器/写入器后保持底层流打开。在您的代码中,它看起来像这样:

using (var reader = new BinaryReader(this.CaptureStream, Encoding.Default, true))
{
    using (var writer = new BinaryWriter(captureSession.captureStream, Encoding.Default, true))
    {
        for (int f = StartFrame; f <= EndFrame; f++)
        {
        }
    }
}

您仍然可以在输入流上进行搜索,并且阅读器会做正确的事情。虽然你可能想写reader.BaseStream.Seek(...).

然后,您可以使用BinaryReader.ReadInt32现有代码中的 to 读取,并使用BinaryReader.Read(byte[], int, int)BinaryWriter.Write(byte[], int32, int32)复制块数据。

(直到刚才我才意识到 .NET 4.5 最终解决了这个问题BinaryReaderBinaryWriter关闭了流。)

于 2013-07-22T20:23:10.330 回答
0

我误解了 bufferSize 中的含义Stream.CopyTo(Stream destination, int bufferSize)。我认为这是要复制的字节总数,而不仅仅是复制时要使用的缓冲区。对象中没有Stream仅复制特定字节数的功能。我通过更换解决了问题

this.captureStream.CopyTo(captureSession.captureStream, chunkLength);

writer.Write(reader.ReadBytes(chunkLength));
于 2013-07-22T20:18:25.050 回答