ב-Online
 
 
 
 
 
 
 
לפרק את הבייט 
איך בונים תוכנה – חלק ח' 

איך בונים תוכנה – חלק ח'

 
לפרק את הבייט |
 
עידו גנדל

איך להשתמש בדלפי כדי לכתוב תוכנית שתשנה שמות של מאות תמונות בכמה פעולות בודדות? עידו גנדל מפרק את הבייט

 
 
 
 
 
 
 
 
 
 
 
השבוע נעשה הפסקה קצרה מהעיסוק בוורונוי (התוכנה ההיא תחזור בשבוע הבא עם המון תכנות מונחה עצמים), ונדבר על תוכנה אחרת, קטנטנה ושימושית, שיכולה להוות אתגר מצוין למתכנתים מתחילים. הרעיון לתוכנה צץ כאשר רוקנתי לתוך המחשב מאות תמונות מתוך המצלמה הדיגיטלית. לרוע המזל, המצלמה העניקה לקבצים שמות סתמיים, על פי סדר הצילום – כגון IMG304, IMG305 וכן הלאה.

כאשר מפתחים תמונות כאלה במעבדות, שם הקובץ נרשם מאחור, אבל הוא חסר תועלת לחלוטין. הוא לא אומר לי, למשל, מתי התמונה צולמה. לשנות מאות שמות קבצים ידנית – לא בא בחשבון. אז למה לא לכתוב תוכנה שתעשה את זה? מן הסתם, אפשר למצוא באינטרנט תוכנות קיימות שעושות בדיוק אותו דבר, אבל אין בזה שום אתגר. אז בואו ונראה איך עושים את זה בדלפי, ואילו בעיות צצות אפילו בפרוייקט זעיר שכזה.
 
 
לצורך הפשטות, ניצור תוכנה מסוג Console Application, כזו שנראית ומתנהגת כמו בימי ה-DOS הישן והטוב. תחת Windows, תוכנות כאלה נפתחות בחלון טקסט שחור-לבן (Command Prompt), וקובץ ה-EXE שלהן הרבה יותר קטן משל תוכנות רגילות כי אין בו שום אלמנטים גרפיים. אם כן, מה הדבר הראשון שהתוכנה צריכה לעשות, לדעתכם? לאתר את הקבצים? טעות. הדבר הראשון שחייבים לעשות הוא לתת למשתמש הזדמנות להתחרט לפני שקורה משהו. וזה נעשה ככה:



// הגדרת מחרוזת
Var s : String;
// כתיבת הודעה למשתמש
Write('Are you sure you want to convert file names? (Y/N) ');
// קריאת קלט מהמשתמש לתוך המחרוזת
Readln(s);
// בדיקת הקלט
If UpperCase(s) <> 'Y' then Exit;



הפקודה האחרונה ממירה את הקלט לאותיות רישיות (Capitals) ומפסיקה את התוכנה אם המשתמש בחר כל דבר שהוא מלבד Y – "כן". מדוע לא לבדוק אם הקלט שווה ל-N – "לא"? כי נניח שהמשתמש התבלבל, התכוון לכתוב "N" אבל לחץ על Enter במקום. הקלט במקרה כזה הוא ריק, שונה מ-N, והתוכנה תמשיך ותעשה פעולה שהמשתמש לא מעוניין בה. אל תשאירו מקום לפרשנויות.
 
דיאגרמת הוורונוי המתקבלת (צילומסך: עידו גנדל)
 דיאגרמת הוורונוי המתקבלת (צילומסך: עידו גנדל) 
 
 
 
הלאה: נניח שכבר מצאנו קובץ כלשהו, ואנחנו רוצים להפוך את השם שלו לתאריך שבו צולמה התמונה. כאן לכאורה אין שום טריקים – רק היכרות עם הפקודות היבשות. הפקודה DateTimeToStr, למשל, ממירה משתנה מסוג DateTime – חותמת זמן – למחרוזת. אז אם ניקח את התאריך של הקובץ כמשתנה, נעביר אותו דרך הפונקציה הזו ונקבע את המחרוזת המתקבלת כשם הקובץ החדש, הכל יעבוד, לא? לא, ואם תנסו זאת תקבלו הודעת שגיאה. הסיבה היא שהפקודה ממירה זמן למחרוזת בפורמט מאד מסוים, שנראה כך: "21/07/08 14:30:51". מחרוזת כזו אינה יכולה לשמש שם קובץ חוקי, כי היא מכילה תווים אסורים כמו לוכסן ונקודתיים. לפני שנוכל להשתמש בה, חייבים להמיר את התווים האלה לתווים קבילים – קו תחתון ומינוס, למשל.

כעת אנחנו יודעים איך לשנות שם של קובץ יחיד, אבל יש לנו מאות כאלה. איך מוצאים את כולם? לשם כך צריך להתממשק עם מערכת הקבצים של מערכת ההפעלה עצמה. דלפי נותן אמנם כלים לעשות זאת, אך הם מגושמים למדי. למעשה, מי שלמד אי-פעם לתכנת בטורבו פסקל הוותיק יגלה שבתחום זה, שום דבר לא השתנה. ראשית, צריך להגדיר משתנה מסוג רשומת חיפוש (TSearchRec), ועוד משתנה שיקבל קודי שגיאה שיוחזרו מהפונקציות הייעודיות:



Var ts : TSearchRec;
ErrorCode : Integer;



הפונקציה הראשונה, הכתובה להלן, מחפשת את הקובץ הראשון בתיקיה הנוכחית בעל הסיומת jpg. קובץ זה יכול להיות מכל סוג שהוא (כלומר, גם קבצים מוסתרים וקובצי מערכת), ואם הוא נמצא, פרטיו מוכנסים לתוך ts. התוצאה של הפעולה מוכנסת למשתנה ErrorCode, כאשר התוצאה 0 פירושה שנמצא קובץ והכל תקין.



ErrorCode := FindFirst('*.jpg', faAnyFile, ts);



אם התוצאה היא 0, אפשר להמשיך ולחפש קבצים בעזרת הפקודות הבאות. הפרמטרים של החיפוש יישארו כפי שהוגדרו בפקודה הקודמת.



while ErrorCode = 0 do
Begin
ErrorCode := FindNext(ts);
End;



תיאורטית, אם נכניס מייד לאחר ה-Begin את הקוד שממיר את שם הקובץ, התוכנה תושלם. בפועל, אנחנו עוד רחוקים מכך. קודם כל, בואו ונחשוב מה קורה אם המצלמה שלנו נורא מהירה, או שהתאריך שלה התאפס בטעות, ויש לנו שני קבצים שצולמו – או שנרשם כאילו צולמו – באותה שניה ממש. מה שיקרה הוא שהלולאה שלנו תנסה להמיר את השם של הקובץ השני לאותו שם שניתן לראשון, ואנחנו נקבל הודעת שגיאה. כדי למנוע זאת, יש להכין מחרוזת נוספת, שתכיל את השם המיועד, ואז לבדוק אם כבר קיים קובץ בשם זה. אם כן, צריך להוסיף למחרוזת סימן (כגון "_2"), ולבצע שוב את הבדיקה, עד שמגיעים לשם ייחודי.
 

 צילום: ASAP Images 
 
האם העבודה הושלמה? לכאורה כן: אפשר להריץ את התוכנה ולהתלהב איך כל השמות חסרי המשמעות משתנים בן-רגע והופכים לתאריכים ושעות. אלא שאחרי ההתלהבות הראשונית, אתם עלולים לגלות תקלה: קבצים שבשם שלהם מופיע הסימן הנוסף ההוא ("_2") בלי שום סיבה – מבלי שיהיה קובץ אחר בעל שם דומה. מה קרה כאן?

התשובה פשוטה להביך: כאשר שינינו שם של קובץ מסוים, התיקיה התעדכנה, ופקודת החיפוש FindNext הרי עובדת עם התיקיה העדכנית ביותר: מבחינתה, היא פשוט מצאה קובץ נוסף. אין לה שום דרך לדעת שזה בדיוק אותו הקובץ שגילתה לפני רגע, מפני שהשם שלו שונה. התוכנה שלנו לוקחת את השם החדש הזה, שהוא בעצם התאריך של הקובץ, ומנסה להמיר אותו בתאריך של עצמו שהוא כמובן זהה, וזה יוצר התנגשות.

איך פותרים את הבעיה הזו? אפשר לחשוב על כמה דרכים. המסורבלת ביותר תהיה לשמור מראש את השמות והתאריכים של כל הקבצים בתיקיה, ורק אז לבצע את ההמרות. דרך קלה קצת יותר תהיה לתת לכל הקבצים החדשים זיהוי ייחודי בתחילת השם, כזה שבטוח אין בשום קובץ קיים, (למשל התווים XYZZY), ולשנות שמות רק עבור קבצים שאינם מכילים תווים אלה. בסיום ההמרה אפשר לעבור שוב על כל הקבצים ולמחוק מהשם שלהם את התווים הללו. פתרון אלגנטי עוד יותר יהיה לקחת חתימת זמן ברגע תחילת העבודה, ולטפל רק בקבצים שהשינוי האחרון בהם נעשה לפני חתימת זמן זו. יש לכם רעיונות נוספים? שתפו את כולם בתגובות.

וכמובן, אם בכוונתם לנסות ולכתוב תוכנית שכזו, אל תקחו סיכונים מיותרים. נסו אותה קודם כל על עותקים ולא על הקבצים המקוריים.
 
 
 
@@@@@@@@@@@@@@@@@@@ ilan @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
@@@@@@@@@@@@@@@@@@@ ilan @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 
תגובות
הוסף תגובה0 תגובות
הוספת תגובה
מאת
 
נושא
 
תוכן
 
 
 
 
תודה! תגובתך התקבלה.
התגובה תתפרסם בכפוף לתנאי האתר.
 
 
 
 
 

כל הזכויות שמורות 2011 © נענע 10 בע"מ
 
 
 
 
כל הזכויות שמורות © Nana10 בע"מ
Video powered by