You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Delphi中创建的文件流作为参数传递给C#方法

跨语言传递文件流实现方案

因为Delphi和C#的原生Stream类型不能直接兼容,以下提供两种落地性强的实现方案,可根据你的文件大小选择:

方案1:传递字节缓冲区(适合小文件场景,代码最简洁)

核心逻辑是在Delphi侧把文件流全量读取为字节数组,利用COM互操作的自动封送能力直接传递给C#,不需要额外的类型适配。

C#端代码修改

public class Baz
{
    public void Bar(byte[] streamContent)
    {
        // 字节数组转C#原生Stream即可使用
        using var stream = new MemoryStream(streamContent);
        // 此处编写你的流处理逻辑
    }
}

Delphi端代码修改

procedure TForm1.Button1Click(Sender: TObject);
var
    FileStream: TFileStream;
    ContentBytes: TBytes;
    Baz : TBaz;
begin
    Baz := TBaz.Create(Self);
    // 读取目标文件到字节数组
    FileStream := TFileStream.Create('替换为你的文件实际路径', fmOpenRead or fmShareDenyWrite);
    try
        SetLength(ContentBytes, FileStream.Size);
        FileStream.ReadBuffer(ContentBytes[0], FileStream.Size);
        // 直接传入字节数组调用C#方法
        Baz.Bar(ContentBytes);
    finally
        FileStream.Free;
        Baz.Free;
    end;
end;

方案2:传递标准IStream接口(适合大文件场景,无内存冗余)

如果你的文件体积较大(比如超过500MB),用方案1会产生双倍内存占用,此时用Windows标准COM接口IStream更合适,不需要全量复制文件内容,直接共享流操作接口。

C#端代码修改

using System.Runtime.InteropServices.ComTypes;

public class Baz
{
    public void Bar(IStream stream)
    {
        // 可以直接操作IStream,也可以包装为C#原生Stream使用
        using var dotNetStream = new InteropStream(stream);
        // 此处编写你的流处理逻辑
    }
}

// 通用IStream转.NET原生Stream的包装类,可直接复用
public class InteropStream : Stream
{
    private readonly IStream _comStream;
    public InteropStream(IStream comStream) => _comStream = comStream ?? throw new ArgumentNullException(nameof(comStream));

    public override int Read(byte[] buffer, int offset, int count)
    {
        byte[] tmp = buffer;
        if (offset != 0) tmp = new byte[count];
        int bytesRead;
        _comStream.Read(tmp, count, out bytesRead);
        if (offset != 0) Array.Copy(tmp, 0, buffer, offset, bytesRead);
        return bytesRead;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        byte[] tmp = buffer;
        if (offset != 0)
        {
            tmp = new byte[count];
            Array.Copy(buffer, offset, tmp, 0, count);
        }
        _comStream.Write(tmp, count, IntPtr.Zero);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        _comStream.Seek(offset, (int)origin, out var newPos);
        return newPos;
    }

    public override void SetLength(long value) => _comStream.SetSize(value);
    public override void Flush() => _comStream.Commit(0);
    public override bool CanRead => true;
    public override bool CanSeek => true;
    public override bool CanWrite => true;
    public override long Length
    {
        get
        {
            STATSTG stat;
            _comStream.Stat(out stat, 1);
            return stat.cbSize;
        }
    }
    public override long Position
    {
        get => Seek(0, SeekOrigin.Current);
        set => Seek(value, SeekOrigin.Begin);
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing) Marshal.ReleaseComObject(_comStream);
        base.Dispose(disposing);
    }
}

Delphi端代码修改

uses
  Winapi.ActiveX; // 需引用该单元获取IStream和TStreamAdapter定义

procedure TForm1.Button1Click(Sender: TObject);
var
    FileStream: TFileStream;
    ComStream: IStream;
    Baz : TBaz;
begin
    Baz := TBaz.Create(Self);
    FileStream := TFileStream.Create('替换为你的大文件实际路径', fmOpenRead or fmShareDenyWrite);
    try
        // 将Delphi原生TStream包装为标准COM IStream接口
        ComStream := TStreamAdapter.Create(FileStream, soReference);
        // 直接传入IStream调用C#方法
        Baz.Bar(ComStream);
    finally
        ComStream := nil; // 释放COM接口引用
        FileStream.Free;
        Baz.Free;
    end;
end;

注意事项

  • 两种方案都兼容COM互操作和UnmanagedExports暴露的C# DLL,不需要额外配置
  • 小于100MB的文件优先选择方案1,实现成本最低
  • 大于100MB的文件优先选择方案2,内存占用更低、性能更好

内容的提问来源于stack exchange,提问作者Maik Hasler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 07:27:03