مقدمه

سازمان‌هایی که قراردادها، صورت‌های مالی یا اسناد نظارتی را ذخیره می‌کنند، باید این فایل‌های PDF را در قالبی با درجه بایگانی – PDF/A نگهداری کنند. اگر حتی یک فایل بدون تطابق مورد نیاز عبور کند، حسابرسان ممکن است کل دسته را پرچم بزنند و پردازش هزینه‌بر می‌تواند ماه‌ها بعد فعال شود. تکیه بر بررسی‌های دستی به سرعت غیرعملی می‌شود وقتی که صدها فایل روزانه می‌آیند.

GroupDocs.Metadata برای .NET حدس و گمان را از بین می‌برد. با ارائه یک پرچم واضح IsPdfA و شمارش دقیق PdfFormat، کتابخانه در یک خط به شما می‌گوید آیا سند با هر سطح PDF/A سازگار است و اگر بله، دقیقاً به کدام نوع (مثلاً PDF/A‑1b، PDF/A‑2u) مطابقت دارد. در این آموزش می‌بینید چگونه این منطق را در یک برنامه کنسولی بکار بگیرید، از طریق یک وب API در دسترس قرار دهید و برای پردازش دسته‌ای مقیاس‌بندی کنید.

در پایان راهنما می‌توانید:

  • یک PDF را با کلاس Metadata بارگذاری کنید.
  • سازگاری PDF/A را با یک ویژگی Boolean تعیین کنید.
  • نسخه دقیق PDF/A را برای فایل‌های سازگار استخراج کنید.
  • بررسی را در جریان‌های کاری بزرگتر (کارهای دسته‌ای، APIها، توابع بدون سرور) یکپارچه کنید.

چرا تشخیص دقیق PDF/A حیاتی است

یک بررسی خودکار و قابل اعتماد به شما کمک می‌کند:

  • آمادگی برای حسابرسی: به ناظران نشان دهید که هر PDF ذخیره‌شده با استاندارد ISO 19005 مطابقت دارد.
  • حفظ صحت بصری: PDF/A تضمین می‌کند که قلم‌ها، رنگ‌ها و چیدمان در نمایشگرهای آینده حفظ شوند.
  • اتوماتیک‌سازی خطوط لوله ورود: فایل‌های غیرسازگار را پیش از رسیدن به سیستم مدیریت اسناد رد کنید.
  • اجتناب از هزینه‌های بازکاری: شناسایی زودهنگام از هزینه‌بر بودن بازاعتباردهی دسته‌ای در مراحل بعدی جلوگیری می‌کند.

پیش‌نیازها

  • .NET 6.0 یا بالاتر.
  • بسته GroupDocs.Metadata از NuGet (آخرین نسخه).
  • یک یا چند فایل PDF که می‌خواهید ارزیابی کنید.
  • (اختیاری) یک لایسنس موقت برای ارزیابی – می‌توانید از پورتال GroupDocs دریافت کنید.

نصب

یک پروژه کنسولی جدید ایجاد کنید و بسته را اضافه کنید:

dotnet new console -n DetectPdfA
cd DetectPdfA

dotnet add package GroupDocs.Metadata

گام 1 – مقداردهی اولیه موتور Metadata

ابتدا PDF را با کلاس Metadata باز می‌کنیم. سازنده به‌صورت خودکار فرمت فایل را تشخیص می‌دهد، بنابراین پارامتر اضافی لازم نیست.

using GroupDocs.Metadata;

string pdfPath = "sample.pdf";

// باز کردن سند – بلوک using تضمین می‌کند که دستگیره فایل آزاد شود.
using (Metadata metadata = new Metadata(pdfPath))
{
    // مراحل بعدی اینجا قرار می‌گیرد.
}

نکته کلیدی: عبارت using اطمینان می‌دهد که منابع بومی به‌سرعت آزاد شوند و از نشت دستگیره‌های فایل در سرویس‌های طولانی‌مدت جلوگیری می‌کند.

گام 2 – دریافت بسته ریشه‌ای مخصوص PDF

GroupDocs.Metadata یک شی ریشه‌ای به‌صورت strongly‑typed برای هر فرمت فراهم می‌کند. برای PDF‌ها ما PdfRootPackage را درخواست می‌کنیم که شامل اطلاعات FileType مورد نیاز است.

using GroupDocs.Metadata.Formats.Pdf;

// داخل بلوک using از گام 1
var root = metadata.GetRootPackage<PdfRootPackage>();

root.FileType دو ویژگی مهم دارد:

  • IsPdfAtrue اگر سند با هر سطح PDF/A سازگار باشد.
  • PdfFormat – یک enum مانند PdfA1b، PdfA2u و غیره که نسخه دقیق را نشان می‌دهد.

گام 3 – انجام بررسی سازگاری

حالا پرچم را می‌خوانیم و در صورت لزوم، نوع دقیق PDF/A را خروجی می‌دهیم.

if (root.FileType.IsPdfA)
{
    // سند سازگار است – نسخه دقیق را گزارش می‌کنیم.
    Console.WriteLine($"✅ PDF/A compliant – version: {root.FileType.PdfFormat}");
}
else
{
    // سند با الزامات PDF/A مطابقت ندارد.
    Console.WriteLine("❌ The document is NOT PDF/A compliant.");
}

آنچه می‌بینید:

  • یک Boolean ساده (IsPdfA) پاسخ فوری «برو/نه‌رو» را می‌دهد.
  • وقتی مقدار true باشد، PdfFormat سطح دقیق تطبیق را فراهم می‌کند که می‌توانید در لاگ‌ها، پایگاه‌داده‌ها یا گزارش‌های حسابرسی ذخیره کنید.

مثال کامل قابل اجرا

ترکیب سه گام بالا یک برنامه فشرده و قابل کپی‑پست می‌شود:

using System;
using GroupDocs.Metadata;
using GroupDocs.Metadata.Formats.Pdf;

class Program
{
    static void Main(string[] args)
    {
        string pdfPath = "sample.pdf";

        using (Metadata metadata = new Metadata(pdfPath))
        {
            var root = metadata.GetRootPackage<PdfRootPackage>();

            if (root.FileType.IsPdfA)
            {
                Console.WriteLine($"✅ PDF/A compliant – version: {root.FileType.PdfFormat}");
            }
            else
            {
                Console.WriteLine("❌ The document is NOT PDF/A compliant.");
            }
        }
    }
}

برنامه را با dotnet run اجرا کنید. خروجی نمونه برای یک فایل سازگار می‌تواند به این شکل باشد:

✅ PDF/A compliant – version: PdfA2u

و برای یک فایل غیرسازگار:

❌ The document is NOT PDF/A compliant.

کاربردهای دنیای واقعی

1. خطوط لوله بایگانی خودکار – یک پوشه‌ی ورودی را اسکن کنید، هر PDF را با قطعه کد بالا اعتبارسنجی کنید و فقط فایل‌های سازگار را به لایه ذخیره‌سازی طولانی‌مدت منتقل کنید.

2. اعتبارسنجی بارگذاری برای یک پورتال وب – همان منطق را در یک کنترلر ASP.NET Core بپیچید (کد نمونه اختیاری در زیر) تا بارگذاری‌های غیر‑PDF/A را پیش از ذخیره‌سازی رد کنید.

3. بررسی سازگاری بدون سرور – متد را به‌عنوان یک Azure Function که هنگام ایجاد Blob فعال می‌شود، مستقر کنید و یک payload JSON با وضعیت سازگاری برگردانید.

// Payload حداقلی Azure Function (بخش استخراج)
var result = new
{
    file = file.FileName,
    isPdfA = root.FileType.IsPdfA,
    format = root.FileType.IsPdfA ? root.FileType.PdfFormat.ToString() : null
};

بهترین شیوه‌ها و نکات

  • مسیر را ابتدا اعتبارسنجی کنید – از Path.GetFullPath استفاده کنید و وجود فایل را پیش از ساخت Metadata بررسی کنید تا از FileNotFoundException جلوگیری شود.
  • کتابخانه را به‌روز نگه دارید – نسخه‌های جدیدتر تشخیص فرمت را بهبود می‌بخشند و باگ‌های لبه‌ای را رفع می‌کنند.
  • به‌سرعت Dispose کنید – الگوی using که در تمام مثال‌ها نشان داده شد، تضمین می‌کند منابع بومی آزاد شوند.
  • استثناها را مدیریت کنید – سازنده را در try/catch بپیچید و MetadataException را برای PDFهای خراب لاگ کنید.
  • برای دسته‌های بزرگ موازی‌سازی کنید – یک نمونه Metadata جداگانه برای هر فایل داخل Parallel.ForEach ایجاد کنید؛ API زمانی که نمونه‌ها به‌اشتراک گذاشته نشوند، thread‑safe است.

عیب‌یابی مشکلات رایج

مشکل: root.FileType.PdfFormat مقدار null برمی‌گرداند در حالی که IsPdfA برابر true است.

  • راه‌حل: اطمینان حاصل کنید که از GroupDocs.Metadata v23.6+ استفاده می‌کنید که در آن enum به‌طور کامل پر می‌شود. به‌روزرسانی بسته NuGet معمولاً این مشکل را رفع می‌کند.

مشکل: برنامه با FileFormatException هنگام مواجهه با یک PDF خراب کرش می‌کند.

  • راه‌حل: فراخوانی new Metadata(pdfPath) را در try/catch بپیچید، نام فایل را لاگ کنید و در سناریوهای دسته‌ای آن فایل را نادیده بگیرید.

مشکل: مصرف حافظه زیاد هنگام پردازش PDFهای چند گیگابایتی.

  • راه‌حل: حالت استریمینگ را فعال کنید با ساخت Metadata با یک FileStream و تنظیم پرچم enableStreaming به true (مثلاً new Metadata(stream, true)).

منابع اضافی