HotXLS יכולה לכתוב מחדש גיליון עבודה בודד בתוך חבילת XLSX קיימת בלי לנתח או לדחוס מחדש את שאר הקובץ. TXLSDirectWriter.BeginPatch פותחת חבילת מקור, מעתיקה כל רשומה מלבד גיליון היעד עם הבייטים הדחוסים שלה כלשונם, ומאפשרת לכתוב מחדש את אותו גיליון בודד דרך הקריאות הרגילות AddSheet, AddRow ו-Write*. תרשימים, מטמוני ציר, ערכות נושא, סגנונות ומחרוזות משותפות אף פעם לא עוברים דחיסה כלל
זרימת העבודה שזה פותר מופיעה בדיווח ורענון נתונים. חוברת עבודה מגיעה מצוות עסקי כשהיא נושאת טבלאות ציר, מחתכים, פורמטים מותנים ועשור של עיצוב שהצטבר. בכל לילה גיליון נתונים אחד צריך להתחלף במספרים טריים. טעינה ושמירה מחדש של כל חוברת העבודה עולה דקות לקובץ, וחשוב יותר, מסכנת נאמנות בתכונות שמנוע הטעינה חייב לבנות מחדש. הטלאה עוקפת את שתי הבעיות על ידי אי-נגיעה במה שאין צורך לגעת בו
למה העתקת בייטים דחוסים היא החלק המעניין?
רשומת zip המועתקת ברמה הדחוסה עולה העתקת זרם. אותה רשומה שעוברת דרך נתיב כתיבה רגיל עולה פתיחה בכניסה ודחיסה ביציאה, והדחיסה היא המחצית היקרה. בחוברת עבודה עם מטמון ציר גדול וכמה עשרות תמונות מוטמעות, ההבדל הזה הוא ההבדל בין טלאי שמסתיים בזמן שלוקח לכתוב את הגיליון החדש לבין כזה שמבזבז את רוב זמנו בדחיסה מחדש של בייטים שהוא מעולם לא בחן
HotXLS משתמשת ב-CopyCompressedFrom לשם כך, שכותבת את הבייטים הדחוסים של רשומת המקור ישירות לתוך המכל היעד. כשרשומה לא יכולה להיות מועתקת בדרך זו, מכיוון שהיא משתמשת בשיטת דחיסה אחרת או בהצפנה חלשה, הכותב נופל בחזרה להעתקת זרם מפוענח במקום להיכשל. רשומות סמן ספרייה מדולגות, מכיוון שהכותב מייצר משלו
החלפה במקום, או כתיבה לקובץ חדש
שני עומסי-יתר מכסים את שתי הצורות שמשימה זו לובשת. הצורה במקום מארגנת את התוצאה בקובץ זמני לצד המקור, סוגרת את מקור המקור, ואז מוחקת ומשנה שם, כך שקריסה באמצע הכתיבה משאירה את המקור שלם. הצורה עם יעד מפורש משאירה את המקור בלי לגעת בו ויכולה להחליף גיליון או לצרף חדש:
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;
וריאנט ההוספה מקבל נתיב מקור ויעד בתוספת 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 פולט סוגי קשרים מחמירים וטלאי לחוברת מעברית פולט סוגים מעבריים
מה הטלאי משמיט ומגביל במכוון
שרשרת החישוב נמחקת בשני המצבים. במצב החלפה הרשומות שלה מתארות תאים בגיליון שכבר לא קיים בצורה הזו; במצב הוספה הזזת אינדקס הגיליון מבטלת אותה לחלוטין. Excel בונה את השרשרת מחדש בחישוב הבא, כך שהשמטתה נכונה ולא כרוכה באובדן. החלק מושמט מההעתקה, ורשומת הקשר שלו ועקיפת סוג התוכן שלו מוסרות בניתוח כירורגי
שני סמנטיקות כתיבה משתנות בתוך טלאי, ושתיהן נובעות מאותו עיקרון: הטלאי אסור שיפריע לחלקים שלא כתב מחדש. מחרוזות נכתבות באופן מוטבע בתוך הגיליון במקום להתווסף לטבלת המחרוזות המשותפת, מכיוון שהטבלה של המקור עוברת ללא נגיעה. ו-StyleIndex מתייחס לרשומות ב-cellXfs של חבילת המקור, לא לטבלת סגנונות שהכותב בונה. זה אומר שאפשר להפנות לפורמטים שחוברת העבודה המקורית כבר מגדירה, מה שבדרך כלל בדיוק מה שרענון נתונים רוצה, אבל זה גם אומר שצריך לדעת איזה אינדקס נושא איזה פורמט
// בתוך טלאי, StyleIndex מאנדקס את cellXfs של חבילת המקור.
// תאריך זקוק לאינדקס מפורש שממופה שם לפורמט תאריך:
W.WriteDateTime(3, EncodeDate(2026, 8, 22), DateStyleIndexFromTemplate);
// עומס-היתר של WriteDateTime חסר-הסגנון נדחה במצב טלאי,
// מכיוון שהוא מניח את טבלת הסגנונות של הכותב עצמו, שטלאי
// לעולם לא יוצר
שש נקודות כניסת כתיבה חסומות: הוספת טבלאות, תרשימים, תמונות, הערות, שמות מוגדרים וסגנונות תא כולם זורקים חריגה במצב טלאי, עם רשת ביטחון שנייה בזמן סגירה שנכשלת אם אחד המונים שלהם אינו אפס. כל אחת מהתכונות הללו הייתה דורשת עריכת חלקים שהטלאי מעתיק כלשונם, וחבילה שנערכה בחצי דרך גרועה יותר מפעולה שסורבה. ניתן לטלא בדיוק גיליון אחד לכל פעולה
מתי לטלא ומתי לטעון
הטלאה היא הכלי הנכון כאשר חוברת העבודה גדולה, השינוי מוגבל לגיליון אחד, ושאר הקובץ חייב לשרוד ביט לביט. זהו הכלי השגוי כאשר השינוי משתרע על פני כמה גיליונות, כשנדרש עיצוב או אובייקטים חדשים, או כשהקובץ קטן מספיק שטעינה ושמירה רגילות לא עולות דבר. עבור יצירה בכמות גדולה מאפס, נתיב ההזרמה המתואר בהכותב הישיר הזורם נשאר ההתאמה הטובה יותר, והוא חולק את אותו API של AddRow ו-Write*, כך שהמעבר בין השניים מכני
עבודה ברמת גיליון בתוך חוברת עבודה טעונה, כשרוצים את מודל האובייקטים המלא, מכוסה בשכפול גיליונות עבודה בחבילות XLSX. ואם הסיבה ששוקלים טלאי היא שעיבוד חוברת עבודה שלמה נעשה איטי, המדידות והתנהגות הזיכרון בביצועי חוברות עבודה גדולות שוות קריאה לפני בחירת גישה
אימות שטלאי באמת עשה מה שחשבתם
שלוש בדיקות תופסות כמעט כל טעות. אמתו שהחלקים שציפיתם שישרדו עדיין נמצאים בארכיון, ש-xl/calcChain.xml נעלם, ושפתיחה מחדש של הקובץ דרך TXLSXWorkbook מדווחת על מספר הגיליונות שציפיתם לו, ללא שינוי עבור החלפה ומוגדל באחד עבור הוספה. קריאת הגיליון המטולא בחזרה והשוואת כמה ערכים ונוסחאות סוגרת את המעגל
פרט מימוש אחד מפיתוח תכונה זו ראוי לחזרה, מכיוון שהוא יכול לפגוע במי שכותב קוד zip דומה ברמה. שמות חלקי גיליון עבודה מותאמים לפי קידומת, וטעות של אחד באורך הקידומת אומרת שהפרדיקט אף פעם לא מתאים, כך שחלק שנכתב זה עתה מתנגש בשם קיים וקוראים שלוקחים את הרשומה האחרונה עם שם נתון בוחרים בשקט בגיליון השגוי. אם טלאי נראה כאילו הוא החליף את תוכן שני הגיליונות, בדקו את התאמת השמות לפני שבודקים את ה-XML
טלאה במקום, כתיבה זורמת ומודל האובייקטים המלא של חוברת עבודה משוגרים באותה ספרייה לדלפי ו-C++Builder; רשימת התכונות נמצאת בעמוד רכיב הגיליון האלקטרוני HotXLS Delphi