从文件属性的自定义选项卡导出元数据以获取子文件夹中的文件列表

Export Metadata from a Custom Tab from file properties for a list of files in sub folders

问题:

在我的 Windows 文件服务器上,我有大约 1,000,000 个 SolidWorks 文件,这些文件在自定义选项卡(见下图)下的文件属性中具有元数据,我想将其导出到单个 CSV 文件。

这些文件位于文件夹的子树中,并与其他文件类型混合。

解决方法:

只需要一个脚本来定位文件夹子树中的特定文件类型(扩展名),它将元数据从自定义选项卡导出到 CSV 文件,然后我可以在其中清理数据并将数据导入SQL 数据库。

我不确定实现此目标的最佳方法,我一直在考虑 PowerShell,如果能提供任何帮助,我们将不胜感激。

如果您使用 C# 或 Visual Basic 等 .NET 语言,则可以使用 SolidWorks API 和 Document Manager 库(您需要获得许可证,客户订阅后免费Portal) 在不打开文件的情况下提取此信息。这是相当快的。至于只查看某些文件,.NET 很简单 IO.Path.GetExtension.

下面是我认为您正在寻找的工作示例。

您将需要 Document Manager dll,它位于 SolidWorks API SDK 中,包含在安装介质中。然后你可以引用SolidWorks.Interop.swdocumentmgr.dll.

您还需要一个 Document Manager 序列号,您可以通过 SolidWorks 客户门户网站免费申请 SolidWorks 订阅。获得该编号后,将下面的 lic 字符串值替换为整个序列号,用引号括起来。

要定义要从 SolidWorks 文件中读取的自定义属性,只需更改列表 propertiesToRead 以包含您需要检索的任何值。这些不区分大小写。

你你运行这个,会提示你输入目录路径。这也是创建 Output.csv 文件的地方。

底部是示例结果的屏幕截图。

using SolidWorks.Interop.swdocumentmgr;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace WriteProperties
{
    class Program
    {
        static ISwDMApplication4 docManager;
        static List<string> propertiesToRead = new List<string>() { "Number", "Description", "Revision", "Material", "Finish", "Weight" };
        const string lic = "YOU CAN GET THIS NUMBER FROM THE CUSTOMER PORTAL WITH YOUR SOLIDWORKS SUBSCRIPTION AT NO COST";

        static char[] charactersToQuote = { ',', '"', '\n' };
        const string QUOTE = "\"";
        const string QUOTEFORMATTED = "\"\"";


        static void Main(string[] args)
        {
            string directoryPath = GetDirectory(args);

            if (string.IsNullOrEmpty(directoryPath)) return;

            if (!LoadDocManager()) return;

            string outputPath = Path.Combine(directoryPath, "Output.csv");

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("File Name," + string.Join(",", propertiesToRead));

            int counter = 0;

            foreach (string filePath in Directory.EnumerateFiles(directoryPath, "*.sld*", SearchOption.AllDirectories))
            {
                SwDMDocument21 dmDocument = GetDocument(filePath);
                if (dmDocument == null) continue;

                WriteProperties(sb, dmDocument, filePath);
                counter++;
            }

            File.WriteAllText(outputPath, sb.ToString());

            Console.WriteLine("{0} files read and saved to {1}", counter, outputPath);
            Console.ReadLine();
        }

        static string GetDirectory(string[] args)
        {
            if (args != null && args.Count() > 0 && Directory.Exists(args[0])) return args[0];

            Console.WriteLine("Directory to read:");
            string filePath = Console.ReadLine();

            if (Directory.Exists(filePath)) return filePath;

            Console.WriteLine("Directory does not exists: {0}", filePath);
            return string.Empty;
        }

        static bool LoadDocManager()
        {
            if (docManager != null) return true;

            try
            {
                SwDMClassFactory factory = new SwDMClassFactory();
                if (factory == null) throw new NullReferenceException(nameof(SwDMClassFactory));

                docManager = (SwDMApplication4)factory.GetApplication(lic);
                if (docManager == null) throw new NullReferenceException(nameof(SwDMApplication4));

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Document Manager failed to load: {0}", ex.Message);
                Console.ReadLine();
                return false;
            }
        }

        static SwDMDocument21 GetDocument(string filePath)
        {
            SwDmDocumentType documentType = GetDocType(filePath);
            if (documentType == SwDmDocumentType.swDmDocumentUnknown) return null;

            SwDmDocumentOpenError result = SwDmDocumentOpenError.swDmDocumentOpenErrorNone;
            SwDMDocument21 dmDocument = (SwDMDocument21)docManager.GetDocument(filePath, documentType, true, out result);

            if (result == SwDmDocumentOpenError.swDmDocumentOpenErrorNone || result == SwDmDocumentOpenError.swDmDocumentOpenErrorFileReadOnly) return dmDocument;

            if (dmDocument != null) dmDocument.CloseDoc();

            return null;
        }

        static SwDmDocumentType GetDocType(string filePath)
        {
            if (filePath.Contains("~$")) return SwDmDocumentType.swDmDocumentUnknown;

            switch (Path.GetExtension(filePath).ToLower())
            {
                case ".sldprt": return SwDmDocumentType.swDmDocumentPart;
                case ".sldasm": return SwDmDocumentType.swDmDocumentAssembly;
                case ".slddrw": return SwDmDocumentType.swDmDocumentDrawing;
                default: return SwDmDocumentType.swDmDocumentUnknown;
            }
        }

        static void WriteProperties(StringBuilder sb, SwDMDocument21 dmDocument, string filePath)
        {
            Console.WriteLine("Reading {0}", filePath);

            List<string> propertiesInFile = new List<string>();

            if (dmDocument.GetCustomPropertyCount() > 0) propertiesInFile.AddRange(dmDocument.GetCustomPropertyNames());

            string csvLine = filePath;

            foreach (string property in propertiesToRead)
            {
                string propertyValue = "";

                if (propertiesInFile.Any(s => string.Compare(s, property, true) == 0))
                {
                    SwDmCustomInfoType propertyType = SwDmCustomInfoType.swDmCustomInfoText;

                    string resolvedValue;

                    propertyValue = dmDocument.GetCustomPropertyValues(property, out propertyType, out resolvedValue);
                }

                csvLine = csvLine + "," + FixChars(propertyValue);
            }

            sb.AppendLine(csvLine);

            dmDocument.CloseDoc();
        }

        static string FixChars(string s)
        {
            if (s.Contains(QUOTE)) s = s.Replace(QUOTE, QUOTEFORMATTED);

            if (s.IndexOfAny(charactersToQuote) > -1) s = QUOTE + s + QUOTE;

            return s;
        }

    }
}

这是一个示例输出