如果你正在用C#做NXOpen二次开发,文件操作绝对是绕不开的基础功。我见过不少开发者把打开、保存这些操作写得支离破碎,结果项目越做越大,代码越来越难维护。今天咱们就来彻底解决这个问题,把零散的操作封装成一套健壮的工具类。
先说说为什么需要封装。想象一下你每天要开10次冰箱门,如果每次都要思考"门把手在哪"、"用多大力气",效率肯定低。NXOpen的文件操作也是同理,封装好的工具类就像给冰箱装了自动门,一按按钮就完事。在实际项目中,我遇到过文件路径含特殊字符导致崩溃、重复打开同一文件浪费内存、未保存直接关闭丢失数据等问题,这些都是我们要在封装时解决的。
核心操作其实就四个:打开、保存、另存为、关闭。但每个操作背后都有不少细节:
下面这段代码展示了最基本的打开操作,后面我们会逐步完善它:
csharp复制public static Part OpenPrt(string fullpath) {
PartLoadStatus status;
Part part = (Part)Session.GetSession().Parts.OpenDisplay(fullpath, out status);
return part;
}
直接使用OpenDisplay虽然简单,但会遇到重复加载的问题。我做过测试,同一个1MB的部件文件重复打开10次,内存占用会增加近8MB。更糟的是,这些重复实例可能引发后续操作混乱。正确的做法是先检查文件是否已加载:
csharp复制if (theUfSession.Part.IsLoaded(fullpath) == 0) {
// 全新加载逻辑
part = (Part)Session.GetSession().Parts.OpenDisplay(fullpath, out status);
} else {
// 获取已加载实例
Tag tag = theUfSession.Part.AskPartTag(fullpath);
part = Tag2NXObject<Part>(tag);
Session.GetSession().Parts.SetDisplay(part, true, true, out status);
}
这里有几个关键点:
实际项目中我遇到过各种奇葩问题:文件被占用、路径不存在、权限不足等等。完善的异常处理能让你的代码更健壮:
csharp复制try {
if (!File.Exists(fullpath))
throw new FileNotFoundException("文件不存在", fullpath);
if (theUfSession.Part.IsLoaded(fullpath) == 0) {
// 加载代码...
} else {
// 重用代码...
}
} catch (NXException ex) {
Logger.Error($"NX异常:{ex.Message}");
throw;
} catch (Exception ex) {
Logger.Error($"系统异常:{ex.Message}");
throw;
}
性能方面,我建议添加这两个优化:
保存看似简单,但隐藏着不少坑。这是我早期写的一个版本:
csharp复制public static void SavePrt(string fullpath) {
Tag part_tag = theUfSession.Part.AskPartTag(fullpath);
theUfSession.Part.SetDisplayPart(part_tag);
theUfSession.Part.Save();
}
这个实现有三个问题:
改进后的版本增加了状态检查和异常处理:
csharp复制public static bool SafeSave(string fullpath) {
if (theUfSession.Part.IsLoaded(fullpath) <= 0)
return false;
try {
Tag part_tag = theUfSession.Part.AskPartTag(fullpath);
Part part = Tag2NXObject<Part>(part_tag);
if (part.IsWriteable) {
part.Save();
return true;
} else {
Logger.Warning("文件只读,保存失败");
return false;
}
} catch (Exception ex) {
Logger.Error($"保存失败:{ex.Message}");
return false;
}
}
实际项目中,我还遇到过这些特殊情况需要处理:
NXOpen的SaveAs方法用起来很简单:
csharp复制theUfSession.Part.SaveAs(fullpath);
但实际项目中需要考虑更多:
这是我项目中使用的增强版本:
csharp复制public static bool SmartSaveAs(string sourcePath, string targetPath, bool overwrite = false) {
if (!File.Exists(sourcePath)) return false;
try {
if (File.Exists(targetPath)) {
if (!overwrite) {
Logger.Warning("目标文件已存在");
return false;
}
File.SetAttributes(targetPath, FileAttributes.Normal);
}
var part = OpenPrt(sourcePath);
part.SaveAs(targetPath);
// 处理关联文件
foreach (var refFile in part.GetReferenceSets()) {
// 处理逻辑...
}
return true;
} catch (Exception ex) {
Logger.Error($"另存失败:{ex.Message}");
return false;
}
}
直接关闭部件很简单:
csharp复制part.Close(BasePart.CloseWholeTree.False, BasePart.CloseModified.Discard, null);
但这样会丢失所有修改,好的做法是让用户选择:
csharp复制public static void CloseWithPrompt(Part part) {
if (part.IsModified) {
var result = MessageBox.Show("是否保存修改?", "提示", MessageBoxButtons.YesNoCancel);
switch (result) {
case DialogResult.Yes:
part.Save();
break;
case DialogResult.Cancel:
return;
}
}
part.Close(BasePart.CloseWholeTree.True, BasePart.CloseModified.Discard, null);
}
处理装配体时,我推荐使用树形关闭:
csharp复制part.Close(BasePart.CloseWholeTree.True,
BasePart.CloseModified.UseResponses,
new PartCloseResponses {
{part, PartCloseResponse.SaveAndClose}
});
这样可以确保关联文件也被正确处理,避免内存泄漏。
现在我们把所有功能整合成一个FileUtility工具类:
csharp复制public static class NXFileUtility {
private static readonly UFSession theUfSession = UFSession.GetUFSession();
public static Part OpenPart(string path) {
// 实现细节...
}
public static bool SavePart(Part part) {
// 实现细节...
}
public static bool SaveAsPart(Part part, string newPath) {
// 实现细节...
}
public static void ClosePart(Part part, CloseBehavior behavior) {
// 实现细节...
}
public enum CloseBehavior {
Save,
Discard,
Prompt
}
}
使用示例:
csharp复制var part = NXFileUtility.OpenPart(@"C:\demo.prt");
// 各种操作...
NXFileUtility.SavePart(part);
NXFileUtility.ClosePart(part, CloseBehavior.Save);
完善的错误处理能让你的代码更专业:
csharp复制public static Part SafeOpen(string path) {
try {
if (!IsValidPath(path))
throw new ArgumentException("无效路径");
return OpenPart(path);
} catch (NXException nxEx) {
Logger.Error($"NX错误:{nxEx.ErrorCode}-{nxEx.Message}");
throw;
} catch (IOException ioEx) {
Logger.Error($"IO错误:{ioEx.Message}");
throw;
} catch (Exception ex) {
Logger.Error($"未知错误:{ex.Message}");
throw;
}
}
建议记录这些关键信息:
经过多次性能测试,我总结了这些优化建议:
这里有个内存优化的示例:
csharp复制public static void ProcessLargeAssembly(string mainPath) {
using (var transaction = Session.GetSession().NewTransaction()) {
var mainPart = OpenPart(mainPath);
foreach (var component in mainPart.ComponentAssembly.RootComponent.GetChildren()) {
// 处理逻辑...
GC.Collect(); // 手动触发垃圾回收
}
transaction.Commit();
}
}
记得在完成操作后及时关闭文件和释放资源,这是很多开发者容易忽视的地方。我在一个项目中就遇到过因为未及时关闭数百个小部件导致NX崩溃的情况。