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

如何在C#的OPC UA服务器中创建可用的File对象?

解决OPC UA服务器中File对象无法正常工作的问题

你当前的代码仅创建了FileState的基础节点框架,但OPC UA的FileType需要绑定实际文件操作逻辑、初始化核心属性,否则会返回BadImplementation和BadAttributeIdInvalid错误。以下是需要补充的关键实现:

1. 初始化FileType的核心属性

FileState默认未设置Size、Writable、OpenCount等必填属性的取值或回调,客户端读取时会返回属性无效错误。需手动初始化这些属性:

// 初始化文件大小属性
file.Size = new PropertyState<long>(file)
{
    Value = 0,
    AccessLevel = AccessLevels.CurrentRead,
    UserAccessLevel = AccessLevels.CurrentRead
};

// 初始化可写状态属性
file.Writable = new PropertyState<bool>(file)
{
    Value = true,
    AccessLevel = AccessLevels.CurrentRead,
    UserAccessLevel = AccessLevels.CurrentRead
};

// 初始化打开计数属性
file.OpenCount = new PropertyState<ushort>(file)
{
    Value = 0,
    AccessLevel = AccessLevels.CurrentRead,
    UserAccessLevel = AccessLevels.CurrentRead
};

2. 实现文件操作的方法回调

OPC UA的FileType定义了Open/Close/Read/Write等方法,必须绑定实际文件操作逻辑才能让客户端正常交互:

绑定Open方法

file.OpenMethod = new MethodState(file)
{
    OnCall = (context, inputArguments, outputArguments) =>
    {
        // 替换为你的本地文件路径
        Stream fileStream = new FileStream(@"C:\OPC_Files\FileName.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
        // 将文件流存入节点上下文,供后续读写使用
        context.Node.SetContext(fileStream);
        // 更新打开计数
        file.OpenCount.Value++;
        file.OpenCount.ClearChangeMasks(context, true);
        return StatusCodes.Good;
    }
};

绑定Close方法

file.CloseMethod = new MethodState(file)
{
    OnCall = (context, inputArguments, outputArguments) =>
    {
        Stream fileStream = context.Node.GetContext<Stream>();
        fileStream?.Close();
        fileStream?.Dispose();
        context.Node.SetContext(null);
        // 更新打开计数
        file.OpenCount.Value--;
        file.OpenCount.ClearChangeMasks(context, true);
        return StatusCodes.Good;
    }
};

绑定Read方法

file.ReadMethod = new MethodState(file)
{
    OnCall = (context, inputArguments, outputArguments) =>
    {
        Stream fileStream = context.Node.GetContext<Stream>();
        if (fileStream == null) return StatusCodes.BadNotOpen;
        
        int readLength = (int)inputArguments[0];
        byte[] buffer = new byte[readLength];
        int actualRead = fileStream.Read(buffer, 0, readLength);
        outputArguments[0] = buffer.Take(actualRead).ToArray();
        return StatusCodes.Good;
    }
};

绑定Write方法

file.WriteMethod = new MethodState(file)
{
    OnCall = (context, inputArguments, outputArguments) =>
    {
        Stream fileStream = context.Node.GetContext<Stream>();
        if (fileStream == null) return StatusCodes.BadNotOpen;
        
        byte[] writeData = (byte[])inputArguments[0];
        fileStream.Write(writeData, 0, writeData.Length);
        // 更新文件大小属性
        file.Size.Value = fileStream.Length;
        file.Size.ClearChangeMasks(context, true);
        return StatusCodes.Good;
    }
};

3. 修正NodeId设置

你当前使用的ObjectIds.FileDirectoryType_FileName_Placeholder是标准占位符ID,需替换为自定义的唯一NodeId,避免冲突:

NodeId = new NodeId("Custom_FileName", NamespaceIndex),
// 或使用GUID生成唯一ID:NodeId = new NodeId(Guid.NewGuid(), NamespaceIndex)

4. 配置正确的访问权限

确保节点权限允许客户端进行读写和方法调用:

file.RolePermissions = new List<RolePermissionType>
{
    new RolePermissionType 
    { 
        RoleId = ObjectIds.Anonymous, 
        Permissions = PermissionType.Read | PermissionType.Write | PermissionType.Call 
    }
};

内容的提问来源于stack exchange,提问作者Bruno Luís

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:35:19