Cuma Günlerimi Yiyen Şey
Her Cuma öğleden sonra, yaklaşık bir yıl boyunca aynı küçük ritüelim vardı. Bir sözleşme üç dosya olarak gelirdi — Word’de ana anlaşma, Excel’de fiyat ekleri ve bir PDF olarak ortak şartnamesi — ve bunları tek temiz bir PDF olarak teslim etmem gerekiyordu. Zor bir şey değildi. Word’ü aç, PDF olarak dışa aktar. Excel’i aç, PDF olarak dışa aktar. Ücretsiz bir PDF birleştirici uygulaması aç, üç dosyayı sürükle, sıralamayı kontrol et, kaydet.
Bu yaklaşık sekiz dakika sürerdi. Bunu haftada on beş sözleşme ile çarparsak, fare hareketiyle iki saat kaybetmiş oluruz. Daha da kötüsü, birkaç hafta arayla birisi ekleri birinci sayfada olan bir bağlayıcı gönderirdi çünkü dosya adları birleştirici uygulamada alfabetik olarak sıralanmıştı.
Eğer bu size tanıdık geliyorsa, bu yazının geri kalanı ritüeli kodla değiştirdiğim öğleden sonrayı anlatıyor.
Gerçek maliyet zaman değil — elli sözleşmeden birinde sayfalar yanlış sırada gelir ve kimse fark etmez, müşteri yanlış sürümü imzalayana kadar.
Aslında Ne İstiyordum
“Şık bir belge iş akışı” değil. Sadece üç şey:
- Bir metoda dosya listesi ver (herhangi bir DOCX, XLSX, PDF karışımı) ve bir PDF al.
- Aynı mantığı bir klasöre uygula ve dosya listesini kendisi bulsun.
- Tamamlanmış bağlayıcıdan bir sayfa aralığını, tüm birleştirmeyi yeniden yapmadan çıkar.
Bu işin tamamı bu. Kütüphane bu üç şeyi temiz bir şekilde yapamıyorsa, bunu duymak istemiyorum.
Kurulum
- .NET 6.0 veya üzeri
- GroupDocs.Merger for .NET 24.10+ (geçici bir lisans alın böylece değerlendirme filigranı göndermezsiniz)
- Normalde elle birleştirdiğiniz belgelerin karışımıyla bir klasör
dotnet add package GroupDocs.Merger
Bu kadar bağımlılık. Harici bir dönüştürücü, başsız Office kurulumu, üstte bir PDF‑manipülasyon kütüphanesi yok.
Adım 1 — Klasörü girdi olarak kullan
Her zaman buradan başlarım çünkü gerçekçi giriş noktasıdır. Pratikte, başka bir şey (yükleme işleyicisi, e‑posta alım işi, finansal gece dökümü) bir dizine bir sürü dosya bırakır ve kodum ne bulursa onunla başa çıkmak zorundadır.
// Drop klasöründeki her desteklenen dosyayı al; PDF pozisyon 0 için
// tie‑break yapar, böylece birleştirici çıktıyı
// dosyalar nasıl adlandırılmış olursa olsun PDF olarak tutar.
string[] extensions = { ".pdf", ".docx", ".xlsx" };
var files = Directory.EnumerateFiles(folderPath)
.Where(f => extensions.Contains(Path.GetExtension(f).ToLowerInvariant()))
.OrderBy(f => Path.GetExtension(f).ToLowerInvariant() == ".pdf" ? 0 : 1)
.ThenBy(f => f)
.ToArray();
if (files.Length == 0)
throw new InvalidOperationException(
$"No supported documents found in '{folderPath}'.");
OrderBy hilesi ilginç kısımdır. GroupDocs.Merger çıktısının formatını ilk açtığınız dosyadan alır — eğer bir DOCX’i birincil belge olarak verirseniz, DOCX olarak çıkar. Pipeline’im her zaman PDF çıkarmak istediği için klasörde mevcut herhangi bir PDF’in pozisyon 0 almasını sağlıyorum.
Dikkat edilmesi gereken iki nokta:
ToLowerInvariant()çünkü bir ortak bir gün sizeREPORT.PDFgönderebilir ve sadece küçük harf filtrelemeniz sessizce onu atar.ThenBy(f)sadece çıktıyı deterministik hâle getirmek içindir. Olmasaydı aynı klasörde iki çalıştırma dosya sistemi ruh haline göre farklı sonuçlar verebilirdi.
Adım 2 — Birleştirme kendisi
Sıralı yol listesine sahip olduğumda, birleştirme tanımından daha kısa olur.
Console.WriteLine($"Primary source: {sourcePaths[0]}");
using var merger = new Merger(sourcePaths[0]);
var joinOptions = new JoinOptions();
for (int i = 1; i < sourcePaths.Length; i++)
{
Console.WriteLine($"Joining: {sourcePaths[i]}");
merger.Join(sourcePaths[i], joinOptions);
}
merger.Save(outputPath);
Console.WriteLine($"Unified PDF binder saved to: {Path.GetFullPath(outputPath)}");
Kullanırken öğrendiğim birkaç not:
usingönemli.Mergerkaynak dosyalar üzerinde dosya tutucularını tutar; onu dispose etmezseniz drop‑folder çalışanı sonunda kendi girdilerini silemez.JoinOptionsburada boş çünkü varsayılanlar %95 ihtiyacımı karşılıyor. Gerçekten ihtiyacınız olduğunda sayfa aralıkları, döndürme ve ekleme konumları burada bulunur.- Excel bağlayıcıya girdiğinde, sayfa‑sayfa yerleşimi kaynak çalışma kitabının yazdırma alanına göre belirlenir. XLSX’iniz 38 sayfaya çıkıyorsa ve üç sayfa istiyorsanız, düzeltme elektronik tabloda yapılır,
JoinOptionsiçinde değil.
Kaydetme işleminden hemen sonra eklediğim bir bütünlük kontrolü:
using var verify = new Merger(outputPath);
Console.WriteLine($"Result pages: {verify.GetDocumentInfo().PageCount}");
Herhangi bir testten daha fazla “sessizce atılan ek” hatasını yakalayan iki saniyelik kod.
Adım 3 — Sonradan bir dilim çıkar
Her seferinde aldığım takip isteği: “Kapak sayfasını gönderebilir misin?” ya da “Müşteri sadece imzaları istiyor.” Tüm bağlayıcıyı yeniden inşa edip iki sayfa vermek saçma — çıkarma doğrudan bunu yapar.
using var merger = new Merger(binderPath);
merger.ExtractPages(new ExtractOptions(pages));
merger.Save(outputPath);
Console.WriteLine($"Extracted pages [{string.Join(",", pages)}] to " +
Path.GetFullPath(outputPath));
pages, tutmak istediğiniz 1‑tabanlı sayfa numaralarının bir int[]’idir. Geri kalan her şey atılır. Sonuç zaten bir PDF olduğu için hızlıdır — dönüşüm turu yoktur.
Öncesi vs. sonrası, dürüstçe
| Eskiden Ne Yapıyordum | Merger.Join ile |
|
|---|---|---|
| Sözleşme başına zaman | 5–10 dakika tıklama | uçtan uca 30 saniyenin altında |
| Tipik hata | Sayfalar yanlış sırada, kimse fark etmez | Dosya listesinin belirttiği sırada, tekrarlanabilir şekilde |
| Günde 100’e ölçekleme | Yapmaz — birini işe alırsınız | Tek çalışan, çoğu zaman sıkılmış |
| Bakımını yaptığınız kod | “Binder Process v4” başlıklı bir Confluence sayfası | Bir sınıf, ~70 satır |
| Çıktı | Üç PDF ve bir dua | Sayfa sayısını kaydedebileceğiniz tek bir bağlayıcı |
En çok önem verdiğim satır “hata” satırı. Manuel birleştirme sessizce başarısız olur; sayfa sayısını loglayan kod yüksek sesle başarısız olur.
Küçük bir legal‑tech ekibinden gerçek bir hikâye
İki kişilik bir startup’ta çalıştığım bir paralegal, sabahını sözleşme derlemesiyle başlatıyordu. Word anlaşma, Excel fiyatlandırma, PDF ek, bir uygulamada birleştiriliyor, DocuSign’a yüklüyordu. Bir paket yaklaşık sekiz dakika sürüyordu, günde 30 paket onun bütün sabahını alıyordu.
Klasör‑tarama yöntemini zaten gelen e‑posta kutusunu izleyen arka uç servisine eklediler. Paket başına yirmi saniye, üstüne bir log satırıyla sayfa sayısı. Paralegal artık sözleşmeleri derlemek yerine incelemeye başladı. Bir daha kimse yanlış sıralı bağlayıcı göndermedi — kütüphane sihirli olduğu için değil, dosya listesi kodda açıkça tanımlı olduğu ve farkı görebildiğiniz için.
string folder = @"C:\IncomingContracts";
string output = @"C:\Processed\ContractPackage.pdf";
var files = CreatePdfBinderFromFolder(folder, output);
Console.WriteLine($"Package created: {files}");
Bu bütün entegrasyon. Yukarı akış (e‑posta dinleyicisi, depolama yolu) zaten yerindeydi.
Bugün ihtiyacım olmayan ama yarın ihtiyacım olacak şeyler
Aynı kütüphane, makaleyi uzatacağı için değinmediğim bir sürü şey yapıyor. Yaklaşık olarak şu sırayla kullandığım özellikler:
- Watermarks on the output “DRAFT” damgaları için ön‑imza kopyalarında.
- Page rotation yan yatmış taramalar için.
- Custom page ordering kaynak sırası teslim sırası olmadığında.
- PDF encryption dış taraflara gönderilen her şey için.
Tüm bunlar aynı Merger API’sinin arkasında. docs tam listeyi içeriyor — sadece “merge” ucuz başlangıç ve geri kalan ihtiyacınız olduğunda mevcut.
Geçmiş ben’e söyleyeceklerim
“Kendi DOCX‑to‑PDF adımını yazacaksınız çünkü sadece bir metod” diyorsanız, durun. Dönüştürme sessizce çürüyen bölümdür — yeni Office özellikleri, taranmış‑görüntü işleme, gömülü fontlar, hepsi. Bu yüzeyi başka bir şeyin sahip olmasına izin verin ve Cuma öğleden sonranızı dosya adı sıralaması olmayan bir şeye harcayın.
Sonraki adımlar:
- Temporary license — filigransız çıktı için gerekli
- Advanced merging options — JoinOptions, kaydetme seçenekleri, sıkıştırma
- Supported formats — burada gösterdiğim üç formatın çok ötesi
- Sample projects on GitHub — bu proje dahil