西门子TIA Portal V15备份文件被占用问题及替代方案咨询
问题描述
我正在开发一款工具,实现TIA Portal用户点击下载预览窗口的“确认”后,自动备份PLC项目文件夹的功能。目前遇到的问题:
- 在TIA Portal V17上测试正常,但V15及以下版本会报错:
This file is being used by another process, so that process cannot access it - 推测原因:西门子从V17开始优化了文件打开模式,使用
File_SHAREREAD允许只读访问,而旧版本独占文件锁导致无法复制
现有实现代码
public void Siemens(TempChangeReasonModel UserClickModel, SqlSugar.SqlSugarScope db) { try { var date = DateTime.Now; var programBackupModel = db.Queryable<PlcBackupConfigurationModel>().First(); if (programBackupModel == null) { return; } if (string.IsNullOrWhiteSpace(UserClickModel.mqttRespones.path)) { throw new Exception($"simens not get path"); } var pathIndex = UserClickModel.mqttRespones.path.IndexOf("-"); string path = ""; if (pathIndex != -1) { path = UserClickModel.mqttRespones.path.Substring(pathIndex + 1).Trim(); } var lastIndex = path.LastIndexOf("\\"); if (lastIndex != -1) { path = path.Substring(0, lastIndex); } var isCopy = false; if (!Directory.Exists(programBackupModel.LocalBackupPath)) { Directory.CreateDirectory(programBackupModel.LocalBackupPath); isCopy = true; } else { var lastDir = FileCommon.GetLastDir(programBackupModel.LocalBackupPath); if (string.IsNullOrWhiteSpace(lastDir)) { isCopy = true; } else { var oldfileList = new List<FileInfo>(); var newfileList = new List<FileInfo>(); var suffixs = new List<string> { "*.ap14", "*.ap15", "*.ap16", "*.ap17", "*.ap18", }; foreach (var item in suffixs) { oldfileList.AddRange(FileCommon.PathConvertFile(Directory.GetFiles(lastDir, item, SearchOption.AllDirectories).ToList())); newfileList.AddRange(FileCommon.PathConvertFile(Directory.GetFiles(path, item, SearchOption.AllDirectories).ToList())); } if (oldfileList.Count == 0 || newfileList.Count == 0) { isCopy = true; } else { foreach (var item in oldfileList) { var file1 = newfileList.Where(x => x.Extension == item.Extension).First(); if (file1.Length != item.Length || file1.LastWriteTime != item.LastWriteTime) { isCopy = true; break; } } } } } string filePath = ""; ProgramBackupBll backupBll = new ProgramBackupBll(); if (isCopy) { var s = new DirectoryInfo(path); filePath = backupBll.Copy(s, programBackupModel.LocalBackupPath, UserClickModel.ResId, "PLC", UserClickModel.ProgramName, date); backupBll.DeleteDirectory(programBackupModel.LocalBackupPath); } else { sysLogBll.InsertLog($"simens not backup,GUID:{UserClickModel.Id}", SysLogType.Info); } backupBll.AddLog(programBackupModel, db, filePath, UserClickModel, date); } catch (Exception ex) { sysLogBll.InsertLog($"GUID:{UserClickModel.Id},error:" + ex.Message); } }
替代备份方案
针对TIA Portal旧版本的文件独占问题,可以尝试以下几种方法:
1. 利用TIA Portal开放API实现备份
西门子提供了TIA Portal的.NET API(Siemens.Engineering命名空间),可以直接调用官方接口导出项目备份,完全避开文件系统层面的锁问题,兼容所有支持API的TIA版本。
关键代码示例:
using Siemens.Engineering; using Siemens.Engineering.HW; using Siemens.Engineering.SW; public void BackupViaTiaApi(string projectPath, string backupPath) { using (var tiaPortal = new TiaPortal()) { var project = tiaPortal.Projects.Open(projectPath); // 导出项目为归档文件(支持带依赖项导出) project.Export(backupPath, ExportOptions.WithDependencies); project.Close(); } }
注意:需要引用对应TIA版本的API程序集,且工具运行时TIA Portal需处于已打开目标项目的状态。
2. 延迟备份策略
如果无法使用API,可在用户点击“确认”后延迟一段时间再执行复制操作——TIA Portal完成下载后会逐步释放文件锁,设置10-30秒的延迟(可根据项目大小调整),再尝试复制文件夹。
实现方式(异步延迟避免阻塞主线程):
if (isCopy) { await Task.Delay(TimeSpan.FromSeconds(15)); // 延迟15秒执行复制 var s = new DirectoryInfo(path); filePath = backupBll.Copy(s, programBackupModel.LocalBackupPath, UserClickModel.ResId, "PLC", UserClickModel.ProgramName, date); backupBll.DeleteDirectory(programBackupModel.LocalBackupPath); }
缺点:可靠性依赖延迟时间设置,可能因系统性能、项目大小出现偏差。
3. 自定义文件复制方法绕过独占锁
使用Windows API的CreateFile函数,指定全共享权限打开文件,再读取内容完成复制,绕过默认的文件复制锁限制。
封装的自定义复制方法示例:
using System.ComponentModel; using System.Runtime.InteropServices; using System.IO; [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); public void CopyFileWithShare(string source, string destination) { const uint GENERIC_READ = 0x80000000; const uint FILE_SHARE_ALL = 0x00000007; const uint OPEN_EXISTING = 3; var sourceHandle = CreateFile(source, GENERIC_READ, FILE_SHARE_ALL, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); if (sourceHandle == IntPtr.Zero) throw new Win32Exception(); using (var sourceStream = new FileStream(sourceHandle, FileAccess.Read)) using (var destStream = new FileStream(destination, FileMode.Create, FileAccess.Write)) { sourceStream.CopyTo(destStream); } }
优势:直接操作文件句柄,绕过部分独占锁;缺点:需要处理复杂的权限和异常情况,无法绕过所有类型的文件锁。
内容的提问来源于stack exchange,提问作者jindeus ye
相关产品推荐
相关产品推荐

