💡 مثال کامل قابل اجرا در گیت‌هاب موجود است:
remove-pii-from-office-metadata-java

چالش انطباق: چرا بررسی دستی متادیتا در مقیاس بزرگ شکست می‌خورد

یک تیم سوابق ۲۰۰ سند را به حسابرس خارجی می‌فرستد. کسی تمام صفحات را خوانده است. هیچ‌کس خصوصیات را نخوانده است، در حالی که همان خصوصیات جایی هستند که داده‌های شخصی قرار دارند: تحلیل‌گر در Author، تحلیل‌گر دوم در LastSavedBy، سرپرست بخش در Manager، شرکت تابعه در Company، زمان‌مهر LastPrinted از شب قبل مهلت، و بر روی هر چیزی که از طریق SharePoint عبور کرده باشد، شناسه تأیید‌کننده و مسیر گردش کار.

پاک‌سازی متادیتا یک جریان کاری GroupDocs.Metadata برای Java است که آن خصوصیات حاوی هویت را از فایل‌های Word، Excel و PowerPoint حذف می‌کند و سپس نتیجه را می‌خواند تا هر چیزی که باقی مانده را گزارش دهد. این مقاله جریان کاری را همان‌گونه که یک تیم انطباق آن را می‌سازد، مرور می‌کند: چه گروه‌های خصوصیتی وجود دارند، کدام قانون حذف برای هر یک مناسب است، چه زمانی یک پاک‌سازی کامل جایگزین حذف هدفمند می‌شود، و چرا تأیید باید در همان کار باشد نه در یک فهرست چک.

مشکل مقیاس این نیست که حذف سخت است. مشکل این است که بررسی دستی رکوردی تولید نمی‌کند. حسابرسی که می‌پرسد «کدام فیلدها از این فایل حذف شدند و کی؟» به عددی نیاز دارد، و دیالوگ خصوصیات هیچ عددی ارائه نمی‌دهد.

چرا ابزارهای عمومی پاک‌سازی در اینجا کار نمی‌کنند

دیالوگ خصوصیات ویندوز یک فایل را در هر بار و تنها زیرمجموعه‌ای از فیلدها را ویرایش می‌کند. Document Inspector آفیس به‌صورت تعاملی اجرا می‌شود، بنابراین برای یک کار شبانه مناسب نیست. هر دو بخش‌های سفارشی OOXML را دست‌نخورده می‌گذارند و هیچ‌کدام خروجی‌ای که یک خط لوله بتواند دوباره بخواند، تولید نمی‌کنند.

تیم‌هایی که یک سطح پایین‌تر می‌روند و docProps/core.xml و docProps/custom.xml را مستقیماً ویرایش می‌کنند، بار نگهداری را بر عهده می‌گیرند: یک عبارت XPath برای هر فیلد، برای هر قالب، که هر بار که برنامه تولیدکننده نامی را تغییر می‌دهد باید بازبینی شود. این کار همچنین سؤال طبقه‌بندی را اشتباه می‌گیرد. نام‌های خصوصیت در بسته‌ها متفاوت هستند، بنابراین فهرست نام‌ها به‌صورت ساکن قدیمی می‌شود و قانونی که دیگر منطبق نیست، همانند فایلی که قبلاً تمیز بوده به نظر می‌رسد.

راه‌حل: GroupDocs.Metadata در یک جریان کاری سوابق

GroupDocs.Metadata برای Java همه چیز را از طریق یک موتور جستجوی خصوصیت می‌گذرد. یک شیء Specification تصمیم می‌گیرد کدام خصوصیت‌ها مطابقت دارند، removeProperties هر مطابقت را حذف می‌کند و تعداد موارد تحت تأثیر را برمی‌گرداند، و findProperties همان پیش‌شرط را به‌صورت فقط‑خواندنی اجرا می‌کند. خصوصیت‌ها برچسب دارند، بنابراین Tags.getPerson().getCreator() فیلدهای سبک نویسنده را صرف‌نظر از قالب یا بسته‌ای که از آن آمده‌اند شناسایی می‌کند.

در Java بارگذاری لامبدا برای removeProperties وجود ندارد، که در اینجا یک مزیت است: هر قانون یک شیء است و اشیاء قابل استفاده مجددند. همان نمونه Specification که یک گروه را پاک می‌کند می‌تواند به اسکن تأیید داده شود، بنابراین بررسی نمی‌تواند از پاک‌سازی‌ای که باید تست کند، دور شود.

پیاده‌سازی گام به گام خط لوله پاک‌سازی

گام ۱ – پاک‌سازی گروه هویت بر اساس برچسب

چهار مشخصه برچسبی که با .or(...) ترکیب شده‌اند، نویسنده، ویرایشگر، مدیر و شرکت را پوشش می‌دهند. چیز دیگری جابه‌جا نمی‌شود، بنابراین Title، Subject و Keywords برای ایندکس سوابق در دسترس می‌مانند.

try (Metadata metadata = new Metadata(inputPath)) {
    if (metadata.getFileFormat() == FileFormat.Unknown) return 0;
    int affected = metadata.removeProperties(
            new ContainsTagSpecification(Tags.getPerson().getCreator())
                .or(new ContainsTagSpecification(Tags.getPerson().getEditor()))
                .or(new ContainsTagSpecification(Tags.getPerson().getManager()))
                .or(new ContainsTagSpecification(Tags.getCorporate().getCompany())));
    metadata.save(outputPath);
    return affected;
}

حفاظت FileFormat.Unknown مهم‌تر از آنچه به نظر می‌رسد است. بدون آن، فایلی که قابل خواندن نیست صفر حذف برمی‌گرداند، که فراخواننده نمی‌تواند آن را از سندی که از ابتدا تمیز بوده تشخیص دهد.

گام ۲ – پاک‌سازی خانواده‌های فیلد بر اساس نام

رشته‌های نظرات، شمارنده‌های بازبینی و فیلدهای سرور برچسب ندارند، بنابراین بر اساس نام مطابقت می‌شوند. یک زیرکلاس کوچک Specification یک لیست متغیر از زیررشته‌ها می‌گیرد که به یک کلاس اجازه می‌دهد سه عبور مختلف را پوشش دهد:

public class NameContainsSpec extends Specification {
    private final String[] needles;

    public NameContainsSpec(String... needles) {
        this.needles = needles;
    }

    @Override
    public boolean isSatisfiedBy(MetadataProperty candidate) {
        String name = candidate.getName();
        if (name == null) return false;
        for (String n : needles) {
            if (name.contains(n)) return true;
        }
        return false;
    }
}

خط زمانی ویرایش گروهی است که تیم‌های انطباق بیشتر به آن اهمیت می‌دهند، زیرا تعداد بازبینی‌ها و تاریخ چاپ آخر توصیف می‌کند که سند چگونه تولید شده است:

try (Metadata metadata = new Metadata(inputPath)) {
    if (metadata.getFileFormat() == FileFormat.Unknown) return 0;
    int affected = metadata.removeProperties(new NameContainsSpec(
            "Revision", "TrackedChange", "LastPrinted", "TotalEditingTime", "EditTime"));
    metadata.save(outputPath);
    return affected;
}

عبور نظرات و عبور SharePoint همان فراخوانی با لیست‌های زیررشته متفاوت هستند: Comment, Reviewer, Reviewed برای ردپای بازبینی، و Server, Workflow, Approver, ContentType, Template برای فیلدهای سرور‑سند.

گام ۳ – پاک‌سازی در مرز خروج

وقتی فایلی سازمان را ترک می‌کند، انتخاب‌پذیری دیگر اهمیتی ندارد. یک فراخوانی تمام بسته‌های متادیتا که کتابخانه شناسایی می‌کند، از جمله بخش‌های سفارشی OOXML که هیچ پیش‌شرط هدفمندی به آن‌ها نگاه نمی‌کند، را پاک می‌کند:

try (Metadata metadata = new Metadata(inputPath)) {
    if (metadata.getFileFormat() == FileFormat.Unknown) return 0;
    int affected = metadata.sanitize();
    metadata.save(outputPath);
    return affected;
}

گام ۴ – تأیید و طبقه‌بندی آنچه باقی مانده است

اسکن ترکیبی تمام قوانین را از طریق findProperties اجرا می‌کند و نتایج را به دو لیست تقسیم می‌کند. مقادیر خالی و شمارنده‌های صفر نادیده گرفته می‌شوند، و ورودی‌هایی که نامشان با Comment، Revision یا Inspection شروع می‌شود، در واقع پوشش محتوا هستند نه متادیتا:

String value = "";
if (p.getValue() != null && p.getValue().getRawValue() != null) {
    value = String.valueOf(p.getValue().getRawValue());
}
if (value.isEmpty() || value.equals("0") || value.equals("0.0")) continue;
String entry = p.getName() + "=" + value;
String name = p.getName() == null ? "" : p.getName();
if (name.startsWith("Comment") || name.startsWith("Revision")
        || name.startsWith("Inspection")) {
    report.contentLevelLeaks.add(entry);
} else {
    report.metadataLeaks.add(entry);
}

تقسیم‌بندی همان چیزی است که سیگنال پاس/فیل را صادقانه نگه می‌دارد. نشت‌های متادیتا باید خالی باشند. نشت‌های سطح محتوا اطلاعاتی می‌مانند، زیرا نظرات Word و نویسندگان تغییرات ردیابی‌شده در داخل word/document.xml قرار دارند و یک کتابخانه متادیتا آن‌ها را بدون ویرایش گزارش می‌کند؛ حذف آن‌ها نیاز به کتابخانه ویرایش محتوا مانند Aspose.Words دارد.

چه زمانی عبور هدفمند بهتر از پاک‌سازی کامل است؟

هر زمان که سند هنوز در حال کار باشد. فایلی که بین بازبینی‌کنندگان گردش می‌کند به Title، Subject و Keywords برای جستجو و طبقه‌بندی سوابق نیاز دارد و sanitize() هر سه را حذف می‌کند. عبور هویت و عبور نظرات را در طول همکاری اجرا کنید، فیلدهای توصیفی را نگه دارید، و پاک‌سازی کامل را برای لحظه‌ای که فایل به طرف خارجی می‌رسد ذخیره کنید.

جریان کاری واقعی: یک کار صادرات برای حسابرس خارجی

تصور کنید یک کار شبانه. این کار فهرستی از شناسه‌های سند را می‌خواند، هر فایل را به مسیر موقت کپی می‌کند، عبور هویت و عبور سرور را اعمال می‌کند، sanitize() را بر هر چیزی که علامت‌گذاری شده است که سازمان را ترک می‌کند فراخوانی می‌کند، سپس بررسی نشت را بر روی نسخه ذخیره‌شده اجرا می‌کند. هر گام تعداد موارد تحت تأثیر خود را به یک خط لاگ برای هر فایل اضافه می‌کند و لیست نشت متادیتای غیرخالی کار را شکست می‌دهد نه اینکه فقط هشدار ثبت کند.

یک بار بعد از ظهر را صرف نسخه‌ای از این کار کردم که صفر حذف را برای ۴۰ فایل گزارش می‌داد و شبیه یک دسته تمیز به نظر می‌رسید. پوشه ورودی شامل باینری‌های .doc قدیمی بود، محافظ فرمت در هر یک از آن‌ها زودتر بازمی‌گردید و هیچ‌چیزی در لاگ «چیزی برای حذف نیست» را از «چیزی خوانده نشد» متمایز نمی‌کرد. ثبت فرمت همراه با شمارش مشکل را حل کرد.

تأثیر تجاری: این چه تغییری ایجاد می‌کند

جنبه بررسی دستی خط لوله GroupDocs.Metadata
پوشش فیلدهای قابل مشاهده در دیالوگ خصوصیات تمام بسته‌هایی که کتابخانه شناسایی می‌کند، از جمله بخش‌های سفارشی OOXML
ثبت کار یادداشت‌ها، اگر کسی آنها را نوشته باشد تعداد موارد تحت تأثیر برای هر فایل و هر گروه خصوصیت
قابلیت تکرار به شخص انجام‌دهنده بستگی دارد یک مشخصه برای هر قانون، به‌صورت یکسان بر روی هر فایل اعمال می‌شود
تأیید باز کردن مجدد فایل و بررسی اسکن findProperties با طبقه‌بندی دو‌طرفه
مقیاس یک فایل در هر بار همان شش عملیات به‌صورت حلقه‌ای بر روی پوشه خروجی اجرا می‌شوند

سایر سناریوهایی که GroupDocs.Metadata در آن‌ها مناسب است

همین موتور خصوصیت هم می‌خواند و هم حذف می‌کند. مقایسه متادیتا بین دو نسخه از یک سند نشان می‌دهد که چه تغییراتی در یک دور ویرایش رخ داده است، که برای اختلافات مالکیت و شناسایی فایلی که خارج از فرآیند دوباره نویسنده شده مفید است. کار با برچسب‌های متادیتا به‌جای نام‌ها است که هر دو حالت را در قالب‌های DOCX، XLSX، PPTX، PDF و تصاویر قابل حمل می‌کند.

شروع کار با GroupDocs.Metadata برای Java

مخزن Java گروه‌داکس را به pom.xml اضافه کنید و به com.groupdocs:groupdocs-metadata وابسته شوید. کتابخانه در حالت ارزیابی بدون لایسنس اجرا می‌شود، که برای اجرای تمام شش عملیات بر روی یک نمونه DOCX و مشاهده شمارش‌ها کافی است. با عبور هویت شروع کنید، عبورهای خانواده فیلد را بر حسب نیاز منبع سند اضافه کنید، و بررسی نشت را پیش از ورود به تولید وصل کنید.

منابع