مقاله فنی

وصله‌کردن یک کاربرگ در یک XLSX بزرگ از دلفی

HotXLS می‌تواند یک کاربرگ را درون یک بسته XLSX موجود بازنویسی کند، بدون تجزیه یا فشرده‌سازی مجدد بقیه فایل. TXLSDirectWriter.BeginPatch یک بسته منبع را باز می‌کند، هر ورودی به‌جز کاربرگ هدف را با بایت‌های فشرده‌اش عیناً کپی می‌کند، و به شما اجازه می‌دهد آن کاربرگ واحد را از طریق فراخوانی‌های معمول AddSheet، AddRow و Write* دوباره تألیف کنید. نمودارها، کش‌های جدول‌محوری، تم‌ها، سبک‌ها و رشته‌های مشترک اصلاً هرگز از حالت فشرده خارج نمی‌شوند

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

چرا کپی‌کردن بایت‌های فشرده بخش جالب ماجراست؟

یک ورودی zip که در سطح فشرده کپی می‌شود، هزینه‌ای برابر یک کپی جریانی دارد. همان ورودی که از یک مسیر نوشتن معمولی عبور می‌کند، در راه ورود هزینه یک واکاهش (inflate) و در راه خروج هزینه یک کاهش (deflate) دارد، و deflate نیمه پرهزینه است. روی کارپوشه‌ای با یک کش جدول‌محوری بزرگ و چند ده تصویر تعبیه‌شده، این تفاوت، تفاوت بین وصله‌ای است که در همان زمانی که نوشتن کاربرگ جدید طول می‌کشد تمام می‌شود، و وصله‌ای که بیشتر زمان خود را صرف فشرده‌سازی دوباره بایت‌هایی می‌کند که هرگز بررسی نکرده

HotXLS برای این کار از CopyCompressedFrom استفاده می‌کند، که بایت‌های فشرده ورودی منبع را مستقیماً در آرشیو هدف می‌نویسد. وقتی یک ورودی نمی‌تواند به آن شکل کپی شود، زیرا از یک روش فشرده‌سازی متفاوت یا رمزنگاری ضعیف استفاده می‌کند، نویسنده به‌جای شکست‌خوردن، به یک کپی جریانی از حالت خارج‌شده از فشرده‌سازی بازمی‌گردد. ورودی‌های نشانگر دایرکتوری نادیده گرفته می‌شوند، زیرا نویسنده نسخه خودش را تولید می‌کند

جایگزینی در همان‌جا، یا نوشتن در یک فایل جدید

دو گونه اضافه‌بار (overload) دو شکلی را که این وظیفه به خود می‌گیرد پوشش می‌دهند. شکل درجا نتیجه را در یک فایل موقت کنار فایل اصلی مرحله‌بندی می‌کند، دسته منبع را می‌بندد، سپس حذف و تغییرنام می‌دهد، بنابراین یک خرابی در میانه نوشتن، فایل اصلی را دست‌نخورده باقی می‌گذارد. شکل هدف-صریح، منبع را دست‌نخورده باقی می‌گذارد و می‌تواند یا یک کاربرگ را جایگزین کند یا یکی جدید اضافه کند:

var
  W: TXLSDirectWriter;
begin
  W := TXLSDirectWriter.Create;
  try
    W.BeginPatch('monthly-dashboard.xlsx', 'Data');   // درجا
    W.AddSheet('Data');
    W.AddRow(1);
    W.WriteString(1, 'Region');
    W.WriteString(2, 'Revenue');
    W.AddRow(2);
    W.WriteString(1, 'North');
    W.WriteNumber(2, 184320.55);
    W.AddRow(3);
    W.WriteFormula(1, '=SUM(B2:B2)');
    W.Close;
  finally
    W.Free;
  end;
end;

گونه درج (insert) یک مسیر منبع و یک مسیر هدف به‌علاوه InsertSheet می‌گیرد:

  // منبع دست‌نخورده باقی می‌ماند؛ هدف یک کاربرگ اضافه به نام Extra می‌گیرد
  W.BeginPatch('template.xlsx', 'output.xlsx', 'Extra', True);
  W.AddSheet('Extra');
  W.AddRow(1);
  W.WriteString(1, 'appended by the nightly job');
  W.Close;

درج، بخشی است که به یک جراحی حسابداری واقعی نیاز دارد. نویسنده رجیستری کاربرگ در xl/workbook.xml و نگاشت رابطه‌ای را که هر کاربرگ به بخش خودش متصل می‌کند تجزیه می‌کند، سپس شماره بخش آزاد بعدی، شناسه کاربرگ و شناسه رابطه را انتخاب می‌کند. انواع رابطه از قراردادهای بسته منبع پیروی می‌کنند، بنابراین وصله‌کردن یک کارپوشه سخت‌گیرانه ISO 29500 انواع رابطه سخت‌گیرانه منتشر می‌کند و وصله‌کردن یک کارپوشه انتقالی انواع انتقالی

وصله به‌عمد چه چیزی را کنار می‌گذارد و محدود می‌کند؟

زنجیره محاسبه در هر دو حالت کنار گذاشته می‌شود. در حالت جایگزینی، ورودی‌های آن سلول‌هایی را در کاربرگی توصیف می‌کنند که دیگر به آن شکل وجود ندارد؛ در حالت درج، جابه‌جایی اندیس کاربرگ آن را کاملاً نامعتبر می‌کند. اکسل در محاسبه مجدد بعدی زنجیره را بازسازی می‌کند، بنابراین کنارگذاشتن آن درست است نه اتلاف‌کننده. این بخش از کپی حذف می‌شود، و ورودی رابطه و بازنویسی نوع محتوای آن به‌طور جراحی حذف می‌شوند

دو معنای تألیف درون یک وصله تغییر می‌کنند، و هر دو از یک اصل واحد پیروی می‌کنند: وصله نباید بخش‌هایی را که بازنویسی نکرده مختل کند. رشته‌ها به‌جای افزوده‌شدن به جدول رشته مشترک، به‌صورت درون‌خطی در کاربرگ نوشته می‌شوند، زیرا جدول منبع دست‌نخورده منتقل می‌شود. و StyleIndex به ورودی‌های cellXfs بسته منبع اشاره می‌کند، نه به جدول سبکی که نویسنده می‌سازد. این یعنی می‌توانید به قالب‌هایی که کارپوشه اصلی از قبل تعریف کرده ارجاع دهید، که معمولاً دقیقاً همان چیزی است که یک به‌روزرسانی داده می‌خواهد، اما همچنین یعنی باید بدانید کدام اندیس کدام قالب را حمل می‌کند

// درون یک وصله، StyleIndex به cellXfs بسته منبع نمایه می‌شود
// یک تاریخ به یک اندیس صریح نیاز دارد که در آنجا به یک قالب تاریخ نگاشت شود:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);

// اضافه‌بار WriteDateTime بدون سبک، در حالت وصله رد می‌شود،
// زیرا جدول سبک خود نویسنده را فرض می‌کند، که یک وصله
// هرگز آن را نمی‌سازد

شش نقطه ورودی تألیف مسدود شده‌اند: افزودن جدول، نمودار، تصویر، نظر، نام‌های تعریف‌شده و سبک‌های سلولی همگی در حالت وصله یک استثنا صادر می‌کنند، با یک تور ایمنی دوم در زمان بسته‌شدن که اگر هر یک از شمارنده‌های آن‌ها ناصفر باشد شکست می‌خورد. هر یک از آن ویژگی‌ها به ویرایش بخش‌هایی نیاز دارد که وصله عیناً کپی می‌کند، و یک بسته نیمه‌ویرایش‌شده بدتر از یک عملیات ردشده است. دقیقاً یک کاربرگ می‌تواند به ازای هر عملیات وصله شود

چه زمانی وصله کنیم و چه زمانی بار کنیم؟

وصله‌کردن ابزار درست است وقتی کارپوشه بزرگ است، تغییر محدود به یک کاربرگ است، و بقیه فایل باید بیت به بیت زنده بماند. وقتی تغییر چند کاربرگ را در بر می‌گیرد، وقتی قالب‌بندی جدید یا اشیای جدید مورد نیاز است، یا وقتی فایل به‌قدری کوچک است که یک بارگذاری و ذخیره‌سازی معمولی هیچ هزینه‌ای ندارد، ابزار نادرست است. برای تولید انبوه از صفر، مسیر جریانی که در نویسنده مستقیم جریانی شرح داده شده، همچنان تناسب بهتری دارد، و همان API معادل AddRow و Write* را به اشتراک می‌گذارد، بنابراین جابه‌جایی بین این دو مکانیکی است

دستکاری در سطح کاربرگ درون یک کارپوشه بارگذاری‌شده، وقتی واقعاً به مدل شیء کامل نیاز دارید، در تکثیر کاربرگ‌ها در بسته‌های XLSX پوشش داده شده. و اگر دلیل شما برای در نظرگرفتن یک وصله این است که پردازش کل کارپوشه کند شده، اندازه‌گیری‌ها و رفتار حافظه در کارایی کارپوشه‌های بزرگ پیش از انتخاب یک رویکرد ارزش خواندن دارند

تأیید اینکه یک وصله واقعاً همان کاری را کرده که فکر می‌کنید

سه بررسی تقریباً هر اشتباهی را می‌گیرند. تأیید کنید بخش‌هایی که انتظار داشتید زنده بمانند هنوز در آرشیو هستند، xl/calcChain.xml رفته، و بازکردن دوباره فایل از طریق TXLSXWorkbook تعداد کاربرگی را که انتظار دارید گزارش می‌دهد، بدون تغییر برای جایگزینی و یک واحد افزایش‌یافته برای درج. بازخواندن کاربرگ وصله‌شده و مقایسه چند مقدار و فرمول، حلقه را می‌بندد

یک جزئیات پیاده‌سازی از توسعه این ویژگی سزاوار تکرار است، زیرا می‌تواند هرکسی را که کد مشابهی در سطح zip می‌نویسد گاز بگیرد. نام بخش‌های کاربرگ بر اساس پیشوند تطبیق داده می‌شوند، و یک خطای یکی‌کم‌ویکی‌زیاد (off-by-one) در طول پیشوند به این معناست که محمول هرگز تطبیق نمی‌یابد، بنابراین یک بخش تازه‌نوشته‌شده با یک نام موجود برخورد می‌کند و خواننده‌هایی که آخرین ورودی با یک نام مشخص را برمی‌دارند، به‌طور خاموش کاربرگ نادرست را انتخاب می‌کنند. اگر یک وصله به نظر می‌رسد محتوای دو کاربرگ را جابه‌جا کرده، پیش از نگاه‌کردن به XML، به تطبیق نام نگاه کنید

وصله‌کردن درجا، نوشتن جریانی و مدل شیء کامل کارپوشه در یک کتابخانه واحد برای دلفی و C++Builder عرضه می‌شوند؛ فهرست ویژگی‌ها در صفحه مؤلفه صفحه‌گسترده HotXLS برای دلفی قرار دارد