اكتشاف الصيغ المدعومة في Java – دليل الاكتشاف الكامل

المقدمة

هل سبق لك أن حاولت معالجة مستند في Java ثم واجهت مشكلة لأن المكتبة التي تستخدمها لا تدعم هذا الصيغة المحددة؟ لست وحدك. توافق صيغ الملفات هو أحد تلك اللحظات المفاجئة التي يمكن أن تعرقل مشروعًا أسرع مما يمكنك قول UnsupportedFileException.

معرفة كيفية اكتشاف الصيغ المدعومة في Java أمر أساسي لبناء أنظمة معالجة مستندات قوية. سواء كنت تبني منصة إدارة مستندات، أو خدمة تحويل ملفات، أو تحتاج فقط إلى التحقق من تحميل المستندات في Java، فإن اكتشاف الصيغ برمجيًا يحفظك من مفاجآت وقت التشغيل ويمنع استياء المستخدمين.

في هذا الدليل، ستكتشف:

  • كيفية اكتشاف صيغ الملفات المدعومة برمجيًا في Java
  • تنفيذ عملي باستخدام GroupDocs.Comparison للـ Java
  • أنماط دمج واقعية لتطبيقات المؤسسات
  • حلول استكشاف الأخطاء للمشكلات الشائعة في الإعداد
  • نصائح تحسين الأداء لبيئات الإنتاج

إجابات سريعة

  • ما هي الطريقة الأساسية لسرد الصيغ؟ FileType.getSupportedFileTypes() تُرجع جميع الأنواع المدعومة.
  • هل أحتاج إلى ترخيص لاستخدام الـ API؟ نعم، يلزم الحصول على نسخة تجريبية مجانية أو ترخيص مؤقت للتطوير.
  • هل يمكنني تخزين قائمة الصيغ في الذاكرة المؤقتة؟ بالتأكيد—التخزين المؤقت يحسن الأداء ويقلل الحمل.
  • هل اكتشاف الصيغ آمن للاستخدام في بيئات متعددة الخيوط؟ نعم، API الخاص بـ GroupDocs آمن للاستخدام في بيئات متعددة الخيوط، لكن يجب أن تتعامل مخازن الذاكرة المؤقتة الخاصة بك مع التزامن.
  • هل ستتغير القائمة مع تحديثات المكتبة؟ قد تضيف الإصدارات الجديدة صيغًا؛ لذا يُفضَّل إعادة التخزين المؤقت بعد الترقيات.

لماذا يُعد اكتشاف صيغ الملفات مهمًا في تطبيقات Java

التكلفة الخفية لافتراضات الصيغ

تخيل هذا: تطبيقك يقبل تحميلات الملفات بثقة، يعالجها عبر خط أنابيب المستندات، ثم—يتعطل. لم تكن صيغة الملف مدعومة، لكنك اكتشفت ذلك فقط بعد إهدار موارد المعالجة وتقديم تجربة مستخدم سيئة.

سيناريوهات شائعة حيث ينقذ اكتشاف الصيغ الموقف:

  • التحقق من التحميل: فحص التوافق قبل تخزين الملفات
  • المعالجة الدفعية: تخطي الملفات غير المدعومة بدلاً من الفشل الكامل
  • دمج الـ API: تقديم رسائل خطأ واضحة حول قيود الصيغ
  • تخطيط الموارد: تقدير متطلبات المعالجة بناءً على أنواع الملفات
  • تجربة المستخدم: عرض الصيغ المدعومة في أدوات اختيار الملفات

الأثر التجاري

اكتشاف الصيغ الذكي ليس مجرد ميزة تقنية—إنه يؤثر مباشرة على ربحيتك:

  • تقليل تذاكر الدعم: يعرف المستخدمون مسبقًا ما يعمل
  • تحسين استغلال الموارد: معالجة الملفات المتوافقة فقط
  • رفع رضا المستخدم: ردود فعل واضحة حول توافق الصيغ
  • دورات تطوير أسرع: اكتشاف مشكلات الصيغ مبكرًا في الاختبار

المتطلبات المسبقة وإعداد البيئة

قبل أن ننتقل إلى التنفيذ، تأكد من أن لديك كل ما تحتاجه.

ما ستحتاجه

بيئة التطوير:

  • مجموعة تطوير جافا (JDK) 8 أو أعلى
  • Maven أو Gradle لإدارة الاعتمادات
  • بيئة تطوير متكاملة من اختيارك (IntelliJ IDEA، Eclipse، VS Code)

المتطلبات المعرفية:

  • مفاهيم برمجة Java الأساسية
  • الإلمام بهيكل مشروع Maven/Gradle
  • فهم معالجة الاستثناءات في Java

اعتمادات المكتبة:

  • GroupDocs.Comparison للـ Java (سنوضح لك كيفية إضافتها)

لا تقلق إذا لم تكن على دراية بـ GroupDocs مسبقًا—سنمشيك خطوة بخطوة.

إعداد GroupDocs.Comparison للـ Java

لماذا GroupDocs.Comparison؟

من بين مكتبات معالجة المستندات في Java، تبرز GroupDocs.Comparison بدعمها الشامل للصيغ وواجهة برمجة تطبيقات بسيطة. فهي تتعامل مع كل شيء من المستندات المكتبية الشائعة إلى الصيغ المتخصصة مثل رسومات CAD وملفات البريد الإلكتروني.

تثبيت عبر Maven

أضف هذا المستودع والاعتماد إلى ملف pom.xml الخاص بك:

<repositories>
   <repository>
      <id>repository.groupdocs.com</id>
      <name>GroupDocs Repository</name>
      <url>https://releases.groupdocs.com/comparison/java/</url>
   </repository>
</repositories>

<dependencies>
   <dependency>
      <groupId>com.groupdocs</groupId>
      <artifactId>groupdocs-comparison</artifactId>
      <version>25.2</version>
   </dependency>
</dependencies>

إعداد عبر Gradle

لمستخدمي Gradle، أضف ما يلي إلى ملف build.gradle:

repositories {
    maven {
        url 'https://releases.groupdocs.com/comparison/java/'
    }
}

dependencies {
    implementation 'com.groupdocs:groupdocs-comparison:25.2'
}

خيارات تكوين الترخيص

للتطوير:

  • نسخة تجريبية مجانية: مثالية للاختبار والتقييم
  • ترخيص مؤقت: الحصول على وصول كامل خلال مرحلة التطوير

للإنتاج:

  • ترخيص تجاري: مطلوب للنشر في بيئات الإنتاج

نصيحة احترافية: ابدأ بالنسخة التجريبية للتحقق من أن المكتبة تلبي احتياجاتك، ثم ارتقِ إلى ترخيص مؤقت للحصول على وصول كامل أثناء التطوير.

كيفية اكتشاف الصيغ المدعومة في Java

التنفيذ الأساسي

إليك كيفية استرجاع جميع صيغ الملفات المدعومة برمجيًا باستخدام GroupDocs.Comparison:

import com.groupdocs.comparison.result.FileType;

// Retrieve the iterable collection of supported file types
Iterable<FileType> fileTypes = FileType.getSupportedFileTypes();

// Iterate over each file type in the collection
for (FileType fileType : fileTypes) {
    // Print out the file type to demonstrate retrieval
    System.out.println(fileType);
}

// Indicate successful retrieval of supported file types
System.out.println("\nSupported file types retrieved successfully.");

فهم الكود

ما يحدث هنا:

  1. FileType.getSupportedFileTypes() تُرجع مجموعة قابلة للتكرار تحتوي على جميع الصيغ المدعومة.
  2. كل كائن FileType يحتوي على بيانات تعريفية حول قدرات الصيغة.
  3. الحلقة البسيطة توضح كيفية الوصول إلى هذه المعلومات برمجيًا.

الفوائد الرئيسية لهذا النهج:

  • اكتشاف وقت التشغيل – لا قوائم صيغ ثابتة تحتاج صيانة.
  • توافق الإصدارات – يعكس دائمًا قدرات نسخة المكتبة التي تستخدمها.
  • التحقق الديناميكي – يمكنك بناء فحوصات الصيغ مباشرة داخل منطق تطبيقك.

تنفيذ محسّن مع التصفية

في التطبيقات الواقعية، غالبًا ما تحتاج إلى تصفية أو تصنيف الصيغ:

import com.groupdocs.comparison.result.FileType;
import java.util.*;

public class FormatDetector {
    
    public static Map<String, List<String>> categorizeFormats() {
        Map<String, List<String>> categories = new HashMap<>();
        categories.put("Documents", new ArrayList<>());
        categories.put("Spreadsheets", new ArrayList<>());
        categories.put("Presentations", new ArrayList<>());
        categories.put("Images", new ArrayList<>());
        categories.put("Other", new ArrayList<>());
        
        Iterable<FileType> fileTypes = FileType.getSupportedFileTypes();
        
        for (FileType fileType : fileTypes) {
            String extension = fileType.getExtension().toLowerCase();
            String category = determineCategory(extension);
            categories.get(category).add(extension);
        }
        
        return categories;
    }
    
    private static String determineCategory(String extension) {
        if (extension.matches("\\.(doc|docx|pdf|txt|rtf)")) {
            return "Documents";
        } else if (extension.matches("\\.(xls|xlsx|csv)")) {
            return "Spreadsheets";
        } else if (extension.matches("\\.(ppt|pptx)")) {
            return "Presentations";
        } else if (extension.matches("\\.(jpg|jpeg|png|gif|bmp)")) {
            return "Images";
        }
        return "Other";
    }
}

مشكلات الإعداد الشائعة وحلولها

المشكلة 1: مشاكل في حل الاعتمادات

العرض: لا يستطيع Maven/Gradle العثور على مستودع GroupDocs أو الحزم.

الحل:

  • تأكد من أن اتصال الإنترنت يسمح بالوصول إلى المستودعات الخارجية.
  • تحقق من أن عنوان URL للمستودع مطابق تمامًا لما هو مذكور.
  • في بيئات الشركات، قد تحتاج إلى إضافة المستودع إلى Nexus/Artifactory الخاص بك.

إصلاح سريع:

<!-- Add to Maven settings.xml if repository access is restricted -->
<mirrors>
    <mirror>
        <id>central-proxy</id>
        <mirrorOf>*</mirrorOf>
        <url>http://your-corporate-nexus/repository/maven-public/</url>
    </mirror>
</mirrors>

المشكلة 2: أخطاء في التحقق من الترخيص

العرض: التطبيق يعمل لكن يظهر تحذيرات أو قيود ترخيص.

الحل:

  • تأكد من أن ملف الترخيص موجود في مسار الـ classpath.
  • تحقق من أن الترخيص لم ينتهِ صلاحيته.
  • افحص ما إذا كان الترخيص يغطي بيئة النشر (dev/staging/prod).

مثال كود لتحميل الترخيص:

// Load license at application startup
License license = new License();
license.setLicense("path/to/GroupDocs.Comparison.lic");

المشكلة 3: استثناء ClassNotFoundException وقت التشغيل

العرض: الكود يُترجم لكن يفشل وقت التشغيل بسبب فقدان فئات.

الأسباب الشائعة:

  • تعارضات الاعتمادات مع مكتبات أخرى.
  • اعتماديات متداخلة مفقودة.
  • عدم توافق نسخة Java المستخدمة.

خطوات التشخيص:

  1. افحص شجرة الاعتمادات: mvn dependency:tree.
  2. تحقق من توافق نسخة Java.
  3. استبعد الاعتمادات المتداخلة المتضاربة إذا لزم الأمر.

المشكلة 4: مشاكل أداء مع قوائم الصيغ الكبيرة

العرض: استدعاء getSupportedFileTypes() يستغرق وقتًا أطول من المتوقع.

الحل: خزن النتائج في الذاكرة المؤقتة لأن الصيغ المدعومة لا تتغير أثناء تشغيل التطبيق:

public class FormatCache {
    private static volatile List<FileType> cachedFormats;
    
    public static List<FileType> getSupportedFormats() {
        if (cachedFormats == null) {
            synchronized (FormatCache.class) {
                if (cachedFormats == null) {
                    cachedFormats = new ArrayList<>();
                    FileType.getSupportedFileTypes().forEach(cachedFormats::add);
                }
            }
        }
        return cachedFormats;
    }
}

أنماط الدمج لتطبيقات العالم الحقيقي

النمط 1: التحقق قبل التحميل

مثالي لتطبيقات الويب التي تريد التحقق من صيغة الملف في Java قبل التحميل:

public class FileUploadValidator {
    
    private static final Set<String> SUPPORTED_EXTENSIONS = 
        getSupportedExtensions();
    
    public boolean isSupported(String filename) {
        String extension = getExtension(filename).toLowerCase();
        return SUPPORTED_EXTENSIONS.contains(extension);
    }
    
    private static Set<String> getSupportedExtensions() {
        Set<String> extensions = new HashSet<>();
        FileType.getSupportedFileTypes().forEach(
            type -> extensions.add(type.getExtension().toLowerCase())
        );
        return extensions;
    }
    
    private String getExtension(String filename) {
        int lastDot = filename.lastIndexOf('.');
        return lastDot > 0 ? filename.substring(lastDot) : "";
    }
}

النمط 2: المعالجة الدفعية مع تصفية الصيغ

عند الحاجة إلى معالجة ملفات دفعية، يتخطى هذا النمط الملفات غير المدعومة بأناقة:

public class BatchProcessor {
    
    public ProcessingResult processBatch(List<File> files) {
        Map<String, List<File>> categorized = categorizeFiles(files);
        
        ProcessingResult result = new ProcessingResult();
        result.setProcessedFiles(processSupported(categorized.get("supported")));
        result.setSkippedFiles(categorized.get("unsupported"));
        
        return result;
    }
    
    private Map<String, List<File>> categorizeFiles(List<File> files) {
        Set<String> supportedExts = getSupportedExtensions();
        
        return files.stream().collect(
            Collectors.groupingBy(file -> 
                supportedExts.contains(getExtension(file.getName())) 
                    ? "supported" : "unsupported"
            )
        );
    }
}

النمط 3: واجهة API REST لمعلومات الصيغ

اعرض نقطة نهاية قائمة صيغ الملفات المدعومة لتطبيقات العملاء:

@RestController
@RequestMapping("/api/formats")
public class FormatController {
    
    @GetMapping("/supported")
    public ResponseEntity<List<FormatInfo>> getSupportedFormats() {
        List<FormatInfo> formats = new ArrayList<>();
        
        FileType.getSupportedFileTypes().forEach(type -> {
            formats.add(new FormatInfo(
                type.getExtension(),
                type.getFileFormat(),
                determineDescription(type)
            ));
        });
        
        return ResponseEntity.ok(formats);
    }
    
    @GetMapping("/check/{extension}")
    public ResponseEntity<SupportInfo> checkFormat(@PathVariable String extension) {
        boolean supported = isFormatSupported(extension);
        return ResponseEntity.ok(new SupportInfo(extension, supported));
    }
}

أفضل الممارسات للاستخدام في الإنتاج

إدارة الذاكرة

التخزين المؤقت بحكمة: قوائم الصيغ لا تتغير أثناء التشغيل، لذا خزنها مؤقتًا:

// Good: Initialize once, use many times
private static final List<FileType> SUPPORTED_FORMATS = 
    StreamSupport.stream(FileType.getSupportedFileTypes().spliterator(), false)
                 .collect(Collectors.toList());

// Avoid: Calling getSupportedFileTypes() repeatedly

معالجة الأخطاء

التدهور السلس: احرص دائمًا على وجود حلول بديلة عندما يفشل اكتشاف الصيغ:

public boolean isFormatSupported(String filename) {
    try {
        String extension = getExtension(filename);
        return SUPPORTED_FORMATS.stream()
            .anyMatch(type -> type.getExtension().equalsIgnoreCase(extension));
    } catch (Exception e) {
        // Log the error but don't fail the operation
        logger.warn("Format check failed for: " + filename, e);
        return false; // Conservative approach
    }
}

تحسين الأداء

التهيئة الكسولة: لا تقم بتحميل معلومات الصيغ إلا عند الحاجة:

public class LazyFormatChecker {
    private volatile boolean initialized = false;
    private Set<String> supportedExtensions;
    
    public boolean isSupported(String extension) {
        ensureInitialized();
        return supportedExtensions.contains(extension.toLowerCase());
    }
    
    private void ensureInitialized() {
        if (!initialized) {
            synchronized (this) {
                if (!initialized) {
                    loadSupportedExtensions();
                    initialized = true;
                }
            }
        }
    }
}

إدارة التكوين

خارج الصيغ من الكود: استخدم ملفات تكوين لتحديد سياسات الصيغ:

# application.yml
document-processing:
  allowed-formats:
    - pdf
    - docx
    - xlsx
  max-file-size: 10MB
  validation-mode: strict

حالات الاستخدام المتقدمة والتطبيقات

إدارة المستندات المؤسسية

سيناريو: منظمة كبيرة تحتاج إلى معالجة أنواع ملفات غير مدعومة عبر أقسام مختلفة مع متطلبات صيغ متباينة.

نهج التنفيذ:

  • قوائم مسموح بها حسب القسم
  • تقارير صيغ آلية وفحص امتثال
  • دمج مع أنظمة إدارة دورة حياة المستندات

دمج التخزين السحابي

سيناريو: تطبيق SaaS يزامن ملفات من مزودي تخزين سحابي مختلفين.

اعتبارات رئيسية:

  • توافق الصيغ عبر أنظمة التخزين المختلفة
  • تحسين عرض النطاق الترددي عبر تصفية الصيغ غير المدعومة مبكرًا
  • إشعارات للمستخدمين حول الملفات غير المدعومة أثناء المزامنة

أنظمة سير العمل الآلية

سيناريو: أتمتة عمليات الأعمال التي توجه المستندات بناءً على الصيغة والمحتوى.

فوائد التنفيذ:

  • توجيه ذكي بناءً على قدرات الصيغ
  • تحويل الصيغ تلقائيًا عندما يكون ذلك ممكنًا
  • تحسين سير العمل عبر معالجة واعية للصيغ

اعتبارات الأداء والتحسين

تحسين استهلاك الذاكرة

التحدي: تحميل جميع معلومات الصيغ المدعومة قد يستهلك ذاكرة غير ضرورية في بيئات محدودة الذاكرة.

الحلول:

  1. التحميل الكسول – تحميل معلومات الصيغ فقط عند الحاجة.
  2. التخزين المؤقت الانتقائي – خزن مؤقتًا الصيغ ذات الصلة بحالتك.
  3. المراجع الضعيفة – السماح بجمع القمامة عندما تكون الذاكرة ضيقة.

نصائح أداء المعالج (CPU)

التحقق الفعال من الصيغ:

  • استخدم HashSet للحصول على أداء بحث O(1) بدلاً من البحث الخطي.
  • حضّر أنماط regex مسبقًا للتحقق من الصيغ.
  • فكر في استخدام الـ parallel streams للعمليات الدفعية الكبيرة.
// Efficient format validation
private static final Set<String> SUPPORTED_EXTENSIONS = 
    Collections.unmodifiableSet(loadSupportedExtensions());

public boolean isSupported(String extension) {
    return SUPPORTED_EXTENSIONS.contains(extension.toLowerCase());
}

اعتبارات التوسع

لتطبيقات ذات معدل مرور عالي:

  • ابدأ بتهيئة معلومات الصيغ عند تشغيل التطبيق.
  • استخدم تجميع الاتصالات إذا كنت تتكامل مع خدمات اكتشاف صيغ خارجية.
  • فكر في استخدام مخازن موزعة (Redis، Hazelcast) للبيئات العنقودية.

استكشاف المشكلات الشائعة وقت التشغيل

المشكلة: نتائج اكتشاف صيغ غير متسقة

الأعراض: نفس امتداد الملف يُعيد أحيانًا حالة دعم مختلفة.

الأسباب الجذرية:

  • اختلاف إصدارات المكتبة بين مثيلات التطبيق.
  • قيود الترخيص التي تؤثر على الصيغ المتاحة.
  • تعارضات classpath مع مكتبات معالجة مستندات أخرى.

نهج التشخيص:

  1. سجّل نسخة المكتبة المستخدمة بدقة.
  2. تحقق من حالة الترخيص وتغطيته.
  3. افحص وجود JARs مكررة في classpath.

المشكلة: تدهور الأداء مع مرور الوقت

الأعراض: يصبح اكتشاف الصيغ أبطأ كلما طالت مدة تشغيل التطبيق.

الأسباب الشائعة:

  • تسربات ذاكرة في آليات التخزين المؤقت للصيغ.
  • نمو داخلي للمخازن دون عملية تنظيف.
  • تنافس الموارد مع مكونات تطبيق أخرى.

الحلول:

  • نفّذ سياسات إخلاء ذاكرة مناسبة للمخزن المؤقت.
  • راقب أنماط استهلاك الذاكرة.
  • استخدم أدوات التحليل لتحديد نقاط الاختناق.

المشكلة: فشل اكتشاف الصيغ بصمت

الأعراض: لا تُطرح استثناءات، لكن دعم الصيغ يبدو غير مكتمل.

خطوات التحقيق:

  1. فعّل سجل التصحيح (debug logging) لمكونات GroupDocs.
  2. تأكد من أن تهيئة المكتبة اكتملت بنجاح.
  3. افحص وجود قيود ترخيص على صيغ معينة.

الخاتمة والخطوات التالية

فهم وتنفيذ اكتشاف الصيغ المدعومة في Java ليس مجرد كتابة كود—إنه بناء تطبيقات مرنة وموجهة للمستخدم تتعامل بذكاء مع مشهد صيغ الملفات الفوضوي في العالم الحقيقي.

النقاط الرئيسية من هذا الدليل:

  • اكتشاف الصيغ برمجيًا يمنع المفاجآت وقت التشغيل ويحسن تجربة المستخدم.
  • الإعداد والتكوين الصحيح يوفر ساعات من وقت تصحيح الأخطاء الشائعة.
  • التخزين المؤقت الذكي وتحسين الأداء يضمن قابلية توسعة تطبيقك.
  • معالجة الأخطاء القوية تحافظ على استقرار التطبيق حتى عند حدوث مشاكل.

خطواتك التالية:

  1. نفّذ اكتشاف الصيغ الأساسي في مشروعك الحالي باستخدام مثال الكود الأساسي.
  2. أضف معالجة أخطاء شاملة لالتقاط الحالات الحدية بسلاسة.
  3. حسّن الأداء لحالتك الخاصة باستخدام أنماط التخزين المؤقت التي تم مناقشتها.
  4. اختر نمط دمج (التحقق قبل التحميل، المعالجة الدفعية، أو API REST) الذي يناسب بنية تطبيقك.

هل ترغب في التعمق أكثر؟ استكشف الميزات المتقدمة في GroupDocs.Comparison مثل خيارات المقارنة الخاصة بالصيغ، استخراج البيانات الوصفية، وإمكانيات المعالجة الدفعية لبناء تدفقات عمل معالجة مستندات أقوى.

الأسئلة المتكررة

س: ماذا يحدث إذا حاولت معالجة صيغة ملف غير مدعومة؟
ج: ستُطلق GroupDocs.Comparison استثناءً. يتيح لك التحقق المسبق باستخدام getSupportedFileTypes() التقاط مشكلات التوافق قبل بدء المعالجة.

س: هل تتغير قائمة الصيغ المدعومة بين إصدارات المكتبة؟
ج: نعم، عادةً ما تضيف الإصدارات الأحدث دعمًا لصيغ إضافية. تحقق دائمًا من ملاحظات الإصدار عند الترقية، وفكّر في إعادة تخزين الصيغ المدعومة بعد التحديثات.

س: هل يمكنني توسيع المكتبة لدعم صيغ إضافية؟
ج: مجموعة الصيغ المدعومة في GroupDocs.Comparison ثابتة. إذا احتجت صيغًا إضافية، فكر في استخدامها جنبًا إلى جنب مع مكتبات متخصصة أخرى أو تواصل مع GroupDocs بشأن دعم صيغ مخصص.

س: ما مقدار الذاكرة التي يستهلكها اكتشاف الصيغ؟
ج: البصمة الذاكرية قليلة—عادةً بضعة كيلوبايت فقط لبيانات تعريف الصيغ. الاعتبار الأكبر هو كيفية تخزينك واستخدامك لهذه المعلومات في تطبيقك.

س: هل اكتشاف الصيغ آمن للاستخدام في بيئات متعددة الخيوط؟
ج: نعم، FileType.getSupportedFileTypes() آمن للاستخدام في بيئات متعددة الخيوط. ومع ذلك، إذا نفذت آلية تخزين مؤقت خاصة بك، تأكد من معالجة الوصول المتزامن بشكل صحيح.

س: ما هو تأثير الأداء عند فحص دعم الصيغ؟
ج: مع التخزين المؤقت المناسب، يصبح فحص الصيغ عملية بحث O(1) تقريبًا. الاستدعاء الأول لـ getSupportedFileTypes() يتطلب بعض الجهد، لكن الفحوصات اللاحقة سريعة جدًا.

موارد إضافية

الوثائق:

البدء:

المجتمع والدعم:


آخر تحديث: 2026-03-08
تم الاختبار مع: GroupDocs.Comparison 25.2 للـ Java
المؤلف: GroupDocs