משיב מוביל
חיפוש byte=null במערך של byte

שאלה
-
שלום,
אני קוראת קובץ הנוצר בmainframe, עד כמה שאני יודעת זה קובץ אסקי של בתים.
אני קוראת שורה שורה, אבל בתוך השורה תקועים כמה null byte, בית שהערך שלו 0.
הבעיה שאח"כ אני מעלה את הקובץ לoracle באמצעות loader, והוא מסתבך עם התו הזה.
מבחינתו זה מעבר שורה כמו הבתים 1310 (crlf)
לכן אני רוצה או לקרוא שורה למערך של byte ואז לחפש שם את הבית שערכו 0, (ולא את הבית שמייצג את המספר 0) ואז להחליף אותו ברווח,
או לקרוא בית בית, ואם הוא בערך 0 אז להחליפו.
לא יודעת איך לעשות את זה בקוד, מתבלבלת קצת בין char לbyte.
מישהו יכול לעזור?
- שינה את הסוג pituachMVP, Moderator יום שישי 21 יוני 2013 07:01 זו שאלה
תשובות
-
תוו האפס :-) זו חוויה בפני עצמה
הנה בלוג קטן בנושא תוו האפס והגישה של שפות פיתוח לעומת מסדי נתונים כשהדגש על שרת SQL:
http://ariely.info/dnn/Blog/tabid/83/EntryId/60/Null-character.aspx
* ההחלפה שאת עושה דווקא אמורה לעבוד אבל יכולה להיות מאוד מסוכנת :-)
ל CHAR אפס יש משמעות בשרשרת טקסט End-Of-String. החלפה של התוו עלולה לגרום לחלק מהמערכות לא לעבוד טוב. למשל לחבר את השרשרת הבאה עם השרשרת הנוכחית או לקטוע שרשרת באמצע :-)
יש בבלוג בדיוק דוגמה מתאימה בשבילך בשפת C++ כדאי להבין מה המשעות של התוו לפני שמתחילים לנקות אותו מפני שהוא קיים לך בכל אלמנט מסוג STRING שנסנה במערכת ההפעלה כמו WIN כניראה. צריך לוודא שאת לא מחליפה את התוו הלא נכון. C# היא שפה מאוד ידידותית והקוד שכתבת אמור לעבוד טוב כפי שמוסבר בבלוג אבל קוד כזה בשפת C היה יכול ליצור באלגן שלם ( ב C# תוו האפס האחרון לא מזוההה כחלק מהשרשרת שמבצעים עלייה REPLACE ולכן זה אמור לעבוד טוב אבל כאמור כדאי לדעת קצת רקע... מחר את עלולה לעבור לשפה אחרת או לדבר עם מתכנת שעובד בשפה אחרת ולהיכנס לריב ומכות)* אם החלטת כבר לבצע REPLACE אז מה שאת עושה פשוט לא נכון מפני שאת מחליפה תוו אפס בתוו ריק ולא מוחקת את התווי אפס. בכל מקרה אני לא ממליץ לעשות שימוש ב minvalue אלא פשוט בתוו המסויים בצורה ישירה תוך עבודה עם STRING ולא לעבור ל CHAR. זה יותר בטוח כשיש קידודים שונים למשל להמשיך לעבוד תחת השרשרת שלנו בלי לשחק הלוך וחזור. בכל מקרה מחיקה של תווי אפס אפשר לבצע כך
Replace("\0", string.Empty)
דוגמת קוד שמראה כיצד לא לעבוד ולמה ההחלפה שלך לא טובה וכיצד כן לעבוד באופציה שרוצים בכוח למחוק את התוו:
String MyStr = "12345\06789"; // אפשר באותה מידה לרשום // String MyStr = "12345" + '\0' + "6789"; // String MyStr = "12345" + Convert.ToChar(0) + "6789"; String MyCleanStr = String.Empty; // WORK OK MyCleanStr = MyStr.Replace("\0", string.Empty); Console.WriteLine( String.Format("MyStr: {0} Length={1}; MyCleanStr: {2} Length={3}" , MyStr , MyStr.Length , MyCleanStr , MyCleanStr.Length ) ); // NOT OK MyCleanStr = MyStr.Replace('\0', ' '); Console.WriteLine( String.Format("MyStr: {0} Length={1}; MyCleanStr: {2} Length={3}" , MyStr , MyStr.Length , MyCleanStr , MyCleanStr.Length ) );
מקווה שזה עוזר ואני מאוד ממליץ לקרוא את הבלוג ולהבין מה זה בכלל תוו אפס ולמה הוא כל כך חשוב בחיים :-)
- סומן כתשובה על-ידי יפהפיה נרדמת יום ראשון 23 יוני 2013 05:56
-
STRING הוא למעשה אוסף של CHAR (רישמית... אם תסתכלי על המחלקה STRING תיראי שימוש במערך של CHAR).
מכיוון שלתוו אפס יש משמעות והוא קיים גם כשאת לא יודעת שהוא קיים אם את מבצעת עבודה כירורגית ברמת CHAR את עלולה להחליף את תוו האפס שאת כן רוצה להשאיר (זה שמסמן את סיום ה STRING). זה יכול להוביל לתוצאות מאוד מצחיקות ששרשראות שונות מקבלות נתונים נוספים.
* הערה: הכל תיאורטי בשלב זה מכיוון שכרגע הדברים מנוהלים ב C# בצורה ידידותית ואת לא אמורה לקבל בעיות כאלה אלא אם דברים ישתנו או תעלי על מקרה ששכחו לכסות. אבל זו הצורה הנכונה לעבוד וצריך לזכור שמחר אולי תעברי לעבוד בשפה או טכנולוגיה אחרת כמו C++ ואז החוויות יתחילו בגדול :-) צריך להתרגל לעבוד נכון
תחשבי למשל על המקרה הבא:
יש לנו בזכרון 100 מקומות רצופים
תוכנה A מכניסה שרשרת a באורך 20 בהתחלה של הזכרון, ומייד אחרי זה תוכנה B אחרת מכניסה שרשרת b נוספת באורך 30. כל שרשרת קיבלה בסיום תוו אפס כדי לזהות שהגיע סיום השרשרת (לכן תפוסים לנו כרגע 21+31 מקומות... זה לא מדוייק בכלל מפני שתוו לא תופס מקום אחד והדברים לא מנוהלים בדיוק ככה אבל אני רק מצייר מצב דמיוני לשם ההסבר)
עתה תוכנה A רוצה לנקות תווי אפס שנכנסו בטעות. מוחקים משרשרת ראשונה את תווי האפס המיותרים אבל מוחקים בטעות גם את התוו האחרון שמסמן את סיום השרשרת.שרשרת כזכור היא מופע של מחלקה ז"א אובייקט ז"א בפנייה לשרשרת אנחנו בעצם פונים להפנייה למיקום השרשרת ולא לנתון עצמו.
נחזור לדוגמה: עתה תוכנה A מנסה למצוא את השרשרת. היא יודעת לפי ההפניה שהשרשרת נמצאת במיקום 0 (בתחילת המקום בזכרון) ולכן היא מוצאת את השרשרת אבל בגלל שהתוכנה המסויימת הנ"ל מתבססת על תוו האפס שאמור להיות בסיום היא מוציאה את שרשרת הראשונה ביחד עם השנייה. נניח שהשנייה במקרה היתה ססמת האדמין של המחשב...
- סומן כתשובה על-ידי יפהפיה נרדמת יום ראשון 23 יוני 2013 07:02
כל התגובות
-
-
תוו האפס :-) זו חוויה בפני עצמה
הנה בלוג קטן בנושא תוו האפס והגישה של שפות פיתוח לעומת מסדי נתונים כשהדגש על שרת SQL:
http://ariely.info/dnn/Blog/tabid/83/EntryId/60/Null-character.aspx
* ההחלפה שאת עושה דווקא אמורה לעבוד אבל יכולה להיות מאוד מסוכנת :-)
ל CHAR אפס יש משמעות בשרשרת טקסט End-Of-String. החלפה של התוו עלולה לגרום לחלק מהמערכות לא לעבוד טוב. למשל לחבר את השרשרת הבאה עם השרשרת הנוכחית או לקטוע שרשרת באמצע :-)
יש בבלוג בדיוק דוגמה מתאימה בשבילך בשפת C++ כדאי להבין מה המשעות של התוו לפני שמתחילים לנקות אותו מפני שהוא קיים לך בכל אלמנט מסוג STRING שנסנה במערכת ההפעלה כמו WIN כניראה. צריך לוודא שאת לא מחליפה את התוו הלא נכון. C# היא שפה מאוד ידידותית והקוד שכתבת אמור לעבוד טוב כפי שמוסבר בבלוג אבל קוד כזה בשפת C היה יכול ליצור באלגן שלם ( ב C# תוו האפס האחרון לא מזוההה כחלק מהשרשרת שמבצעים עלייה REPLACE ולכן זה אמור לעבוד טוב אבל כאמור כדאי לדעת קצת רקע... מחר את עלולה לעבור לשפה אחרת או לדבר עם מתכנת שעובד בשפה אחרת ולהיכנס לריב ומכות)* אם החלטת כבר לבצע REPLACE אז מה שאת עושה פשוט לא נכון מפני שאת מחליפה תוו אפס בתוו ריק ולא מוחקת את התווי אפס. בכל מקרה אני לא ממליץ לעשות שימוש ב minvalue אלא פשוט בתוו המסויים בצורה ישירה תוך עבודה עם STRING ולא לעבור ל CHAR. זה יותר בטוח כשיש קידודים שונים למשל להמשיך לעבוד תחת השרשרת שלנו בלי לשחק הלוך וחזור. בכל מקרה מחיקה של תווי אפס אפשר לבצע כך
Replace("\0", string.Empty)
דוגמת קוד שמראה כיצד לא לעבוד ולמה ההחלפה שלך לא טובה וכיצד כן לעבוד באופציה שרוצים בכוח למחוק את התוו:
String MyStr = "12345\06789"; // אפשר באותה מידה לרשום // String MyStr = "12345" + '\0' + "6789"; // String MyStr = "12345" + Convert.ToChar(0) + "6789"; String MyCleanStr = String.Empty; // WORK OK MyCleanStr = MyStr.Replace("\0", string.Empty); Console.WriteLine( String.Format("MyStr: {0} Length={1}; MyCleanStr: {2} Length={3}" , MyStr , MyStr.Length , MyCleanStr , MyCleanStr.Length ) ); // NOT OK MyCleanStr = MyStr.Replace('\0', ' '); Console.WriteLine( String.Format("MyStr: {0} Length={1}; MyCleanStr: {2} Length={3}" , MyStr , MyStr.Length , MyCleanStr , MyCleanStr.Length ) );
מקווה שזה עוזר ואני מאוד ממליץ לקרוא את הבלוג ולהבין מה זה בכלל תוו אפס ולמה הוא כל כך חשוב בחיים :-)
- סומן כתשובה על-ידי יפהפיה נרדמת יום ראשון 23 יוני 2013 05:56
-
תודה רבה רבה, קראתי את הבלוג והוא אכן מחכים, ותודה על הקישורים בסוף. (אפשר הערה קטנה? תחליף את הגופן לARIAL כמו פה בפורומים, זה קשה לקרוא את הDAVID הזה.)
אני מחליפה ל' ' כי חשוב לי לשמור על האורך האחיד של השורה.
חשבתי באמת להחליף ל '#' או לכל תו שבטוח לי יהיו לו שימוש בקובץ.
תסביר לי שוב למה זה חשוב להשתמש בstring ולא לעבור לchar?
-
STRING הוא למעשה אוסף של CHAR (רישמית... אם תסתכלי על המחלקה STRING תיראי שימוש במערך של CHAR).
מכיוון שלתוו אפס יש משמעות והוא קיים גם כשאת לא יודעת שהוא קיים אם את מבצעת עבודה כירורגית ברמת CHAR את עלולה להחליף את תוו האפס שאת כן רוצה להשאיר (זה שמסמן את סיום ה STRING). זה יכול להוביל לתוצאות מאוד מצחיקות ששרשראות שונות מקבלות נתונים נוספים.
* הערה: הכל תיאורטי בשלב זה מכיוון שכרגע הדברים מנוהלים ב C# בצורה ידידותית ואת לא אמורה לקבל בעיות כאלה אלא אם דברים ישתנו או תעלי על מקרה ששכחו לכסות. אבל זו הצורה הנכונה לעבוד וצריך לזכור שמחר אולי תעברי לעבוד בשפה או טכנולוגיה אחרת כמו C++ ואז החוויות יתחילו בגדול :-) צריך להתרגל לעבוד נכון
תחשבי למשל על המקרה הבא:
יש לנו בזכרון 100 מקומות רצופים
תוכנה A מכניסה שרשרת a באורך 20 בהתחלה של הזכרון, ומייד אחרי זה תוכנה B אחרת מכניסה שרשרת b נוספת באורך 30. כל שרשרת קיבלה בסיום תוו אפס כדי לזהות שהגיע סיום השרשרת (לכן תפוסים לנו כרגע 21+31 מקומות... זה לא מדוייק בכלל מפני שתוו לא תופס מקום אחד והדברים לא מנוהלים בדיוק ככה אבל אני רק מצייר מצב דמיוני לשם ההסבר)
עתה תוכנה A רוצה לנקות תווי אפס שנכנסו בטעות. מוחקים משרשרת ראשונה את תווי האפס המיותרים אבל מוחקים בטעות גם את התוו האחרון שמסמן את סיום השרשרת.שרשרת כזכור היא מופע של מחלקה ז"א אובייקט ז"א בפנייה לשרשרת אנחנו בעצם פונים להפנייה למיקום השרשרת ולא לנתון עצמו.
נחזור לדוגמה: עתה תוכנה A מנסה למצוא את השרשרת. היא יודעת לפי ההפניה שהשרשרת נמצאת במיקום 0 (בתחילת המקום בזכרון) ולכן היא מוצאת את השרשרת אבל בגלל שהתוכנה המסויימת הנ"ל מתבססת על תוו האפס שאמור להיות בסיום היא מוציאה את שרשרת הראשונה ביחד עם השנייה. נניח שהשנייה במקרה היתה ססמת האדמין של המחשב...
- סומן כתשובה על-ידי יפהפיה נרדמת יום ראשון 23 יוני 2013 07:02
-
חחחחחחחחחחחחחחח הצחקת אותי.. זה היה נראה כמו קדימון לסרט אימה.
להרגעה אני משנה את הכיתוב בקובץ (יוצרת קובץ חדש) ככה שזה לא יגיע לאדמין של המחשב.
מה שאני יודעת על הקובץ הוא: באמצע יכולים להיות שתולים 0\ ובסוף יש crlf שזה 1310 באסקי קוד.
עדין יש מקום לחשש?
בכל זאת מה אכפת לי לשמוע בקולך ולעבוד נכון? :)
-
לכל שורה יש סיום בתוו מסויים (תוו 13 + תוו 10 בחלונות ותו 13 בלבד בלינוקס ותו 10 בלבד ביוניקס או הפוך... אני תמיד לא זוכר מי זה מי)
לכל קובץ יש תווים המגדירים שהגענו לסים הקובץ (בהתאם למערכת ההפעלה בדרך כלל)
לשרשרת ברמת האפליקציה יש תוו סוגר (תוו האפס בדרך כלל)
אלו דברים שונים :-) סגירת קובץ וסגירת שורה וסגירת שרשרת יכולים כולם ליצור בעיות כאלה ואחרות אם לא נזהרים....
* פעם היה לנו סיפור עם קבצים של UNIX שגובו לטייפ. בטייפ שמים קובץ אחרי קובץ בצורה סינכרונית. נוצר מצב שהתווים שמגדירים סיום קובץ היו שונים (אני לא בדיוק זוכר אם זה בגלל מערכות OS שונות או בגלל תוכנת הגיבוי כי עברו כמה שנים מאז). מה שקרה זה שבקריאה של הטייפ לשחזור לא הצלחנו בהתחלה לקרוא את הקבצים. בסופו של דבר המנהל IT מצא פתרון מקורי. הוא קרא את כל התוכן כאילו זה קובץ אחד (פשוט קריאה בינארית as it is). כתב סקריפט ב SHELL של היוניקס שהוסיף תווים במיקום מתאים והכל בא למקומו בשלום. זה היה דטא של תוצאות סקר של חיפושי נפט שהיה שווה להשקיע בו, אבל אני לא בטוח שאת רוצה להשקיע על בעיות כאלה :-)