适用版本:NX 11及以前版本 (从NX12.0开始不适用)
一、概述
UG Part (*.prt)是一个复合文档,Windows系统里有很多常用的文件都是复合文档,比如Office的xls、doc等等。简单地说,复合文档就是在一个文件里可以内嵌入其他各种文档,不仅可以包含文本,还可以包括图形、电子表格数据、声音、视频图像以及其它信息。在UG Part (*.prt)文件里除了包括模型数据之外,还包括用于预览显示的图像和部件的属性等。
二、复合文档原理
复合文档的原理就像一个文件系统(文件系统:如 FAT 与 NTFS )。复合文档将数据分成许多流( Streams ),这些流又存储在不同的仓库( Storages )里。将复合文档想象成你的 D 盘, D 盘用的是 NTFS ( NT File System )格式,流就相当于 D 盘里的文件,仓库就相当于 D 盘里的文件夹。流和仓库的命名规则与文件系统相似,同一个仓库下的流及仓库不能重名,不同仓库下可以有同名的流。每个复合文档都有一个根仓库( root storage )。
三、功能说明
在C#中,System.IO.Packaging命名空间包含了用于封装OLE结构化存储访问的公开(pubic)的StorageInfo类和StreamInfo类,不幸的是,创建或打开文件所需的StorageRoot类是一个内部(internal)类,但是我们可以使用反射来访问StorageRoot类上的方法。下面的代码可以获取到UG Part(*.prt)文件的属性:
//需要引用 WindowsBase.dll
using System.IO.Packaging;
using System.Runtime.InteropServices;
namespace Bizca
{
public class PartAttributeCollection:System.Collections.Generic.IEnumerable<PartAttribute>
{
private readonly System.Collections.Generic.List<PartAttribute> _thePartAttributes;
public PartAttributeCollection(string partFile)
{
_thePartAttributes = new System.Collections.Generic.List<PartAttribute>();
if (!System.IO.File.Exists(partFile)) return;
if (StgIsStorageFile(partFile) != 0) return;
var storageRoot = GetStorageRoot(partFile);
var stream = storageRoot?.GetSubStorageInfo("part")?.GetStreamInfo("attrs")?.GetStream();
if (stream != null)
{
System.Xml.XmlDocument document = new System.Xml.XmlDocument();
document.Load(stream);
var nodeList = document.SelectNodes("/UgAttributes/Attribute");
if (nodeList != null)
for (int i = 0; i < nodeList.Count; i++)
_thePartAttributes.Add(new PartAttribute(nodeList[i]));
}
CloseStorageRoot(storageRoot);
}
public PartAttribute this[string title]
{
get
{
foreach (var partAttribute in _thePartAttributes)
{
if (string.Compare(partAttribute.Title, title, System.StringComparison.OrdinalIgnoreCase) == 0)
return partAttribute;
}
return null;
}
}
public System.Collections.Generic.IEnumerator<PartAttribute> GetEnumerator()
{
foreach (var partAttribute in _thePartAttributes)
{
yield return partAttribute;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 关闭复合文档
/// </summary>
/// <param name="storageRoot">The storage root.</param>
private static void CloseStorageRoot(StorageInfo storageRoot)
{
InvokeStorageRootMethod(storageRoot, "Close");
}
/// <summary>
/// 判断是否为复合文档
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <returns>System.Int32.</returns>
[DllImport("ole32.dll", CharSet = CharSet.Unicode)]
private static extern int StgIsStorageFile(string fileName);
/// <summary>
/// 取复合文档的根
/// </summary>
/// <param name="fileName">文件全路径</param>
/// <returns>StorageInfo.</returns>
/// <exception cref="System.InvalidOperationException"></exception>
private static StorageInfo GetStorageRoot(string fileName)
{
System.IO.Packaging.StorageInfo storageRoot = (StorageInfo)InvokeStorageRootMethod(null, "Open", fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
if (storageRoot == null)
{
throw new System.InvalidOperationException($"Unable to open \"{fileName}\" as a structured storage file.");
//Utilities.ThrowInvalidStateFmt("Unable to open \"{0}\" as a structured storage file.", fileName);
}
return storageRoot;
}
private static object InvokeStorageRootMethod(StorageInfo storageRoot, string methodName, params object[] methodArgs)
{
System.Type storageRootType = typeof(System.IO.Packaging.StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot", true, false);
object result = storageRootType.InvokeMember(methodName, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod, null, storageRoot, methodArgs);
return result;
}
}
public class PartAttribute
{
public PartAttribute(System.Xml.XmlNode node)
{
this.Owner = node.Attributes?["owner"]?.Value;
this.Title = node.Attributes?["title"]?.Value;
this.Value = node.Attributes?["value"]?.Value;
this.Version = node.Attributes?["version"]?.Value;
this.PdmBased = node.Attributes?["pdmBased"]?.Value;
this.Type = node.Attributes?["xsi:type"]?.Value;
this.Utf8Title = node.Attributes?["utf8title"]?.Value;
this.Utf8Value = node.Attributes?["utf8value"]?.Value;
}
public string Owner { get; }
public string Title { get; }
public string Value { get; }
public string Version { get; }
public string PdmBased { get; }
/// <summary>
/// BoolAttributeType IntegerAttributeType RealAttributeType TimeAttributeType StringAttributeType
/// </summary>
public string Type { get; }
public string Utf8Title { get; }
public string Utf8Value { get; }
}
}
三、总结
这种方式可以在不打开NX快速获取和编辑UG Part(*.prt)文件的各种信息。