שאלה| מחיקת הסטראקט האחרון מקובץ בינארי C - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

שאלה| מחיקת הסטראקט האחרון מקובץ בינארי C


EasyPooper

Recommended Posts

שלום :)

נניח ויש לי קובץ בינארי שניראה כך (כל שורה מייצגת סטראקט)

1 singer1 song1

2 singer2 song2

3 singer3 song3

3 singer3 song3

איך אני מוחק את הסטראקט האחרון כדי שהקובץ יכיל את הנתונים הבאים:

1 singer1 song1

2 singer2 song2

3 singer3 song3

?

נכון לעכשיו למדנו למחוק סטראקט מאמצע הקובץ ע"י דרישה שלו עם הסטראק הבא, כלומר אם היה לנו 1 2 3 4 5 ורצינו למחוק את 3 היינו מגיעים למצב של 1 2 4 4 5

בהתבסס על אותה טכניקה, אני אמור "לדרוס" את הסטראקט האחרון עם EOF

נ.ב.

חובה לעשות את הכל על קובץ בודד, ללא קבצי עזר

קישור לתוכן
שתף באתרים אחרים

נניח ואנחנו עובדים בWINDOWS :)

יש כלי\ספריה\פונקצייה שיכולות לעזור לי?

סך הכל זאת מטלת הגשה בקורס סדנה מתקדמת בתכנות, משהו שלומדים סטודנטים למדעי המחשב בשנה הראשונה

קשה לי להאמין שהמרצה מצפה מאיתנו "לפלוש" לפונקציות של מערכת ההפלעה

התכלית אמורה ליהיות סי...

אין דרך כלשהיא "לדרוס" את הסטראקט האחרון עם EOF?

קישור לתוכן
שתף באתרים אחרים

נ.ב.

חובה לעשות את הכל על קובץ בודד, ללא קבצי עזר

קובץ בינארי, זה הרעיון בו- אוסף של סטראקטים, עם סיומת DAT. או .BIN (לפחות על אלה למדנו עכשיו)

אחרי כמה שעות של שיטוטים באינטרנט מצאתי את הפונצייה HANDLE של ווינדואוס

וארבעת השורות הבאות אמורות לעשות את העבודה:

HANDLE h=CreateFile(L"TEST.$$$",GENERIC_WRITE | GENERIC_READ,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
// Handle to the file whose file pointer is to be moved.
// The file handle must have been created with GENERIC_READ or GENERIC_WRITE
// DistanceToMove
// lpDistanceToMoveHigh
// Pointer to the high-order 32 bits of the signed 64-bit distance to move.
// If you do not need the high-order 32 bits, this pointer must be set to NULL
// MoveMethod:
// FILE_BEGIN,
// FILE_CURRENT,
// FILE_END
SetFilePointer(h,1*sizeof(s),NULL,FILE_BEGIN);
SetEndOfFile(h);
CloseHandle(h);

עכשיו לשכתב כמה מאות שורות קוד כדי שזה יהיה HANDLE זה קצת קשה... יש איזו פקודת המרה?

קישור לתוכן
שתף באתרים אחרים

לא צריך להמיר. פשוט תסגור את הקובץ אחרי שסיימת לעבוד איתו, ואז תפתח אותו מחדש באמצעות הCreateFile רק בשביל לשנות את הגודל.

אגב, הHandle זה לא הפונקציה, זה הטיפוס של ה"מצביע" לקובץ, שהפונקציה CreateFile מחזירה.

קישור לתוכן
שתף באתרים אחרים

ככה ניראת פוקנציית המחיקה שלי, שמשום מה לא מוחקת את השורה האחרונה (אבל את ההחלפה בין האיבר הנימחק לאיבר האחרון היא עושה)

למישהו יש רעיון מה לא בסדר?



{
HANDLE h;
FILE *f;
struct Track tr;
f=fopen("Vinyl_List.bin", "r+b");
printf("Deleting\n");
fseek(f,-(sizeof(tr)),SEEK_END);
fread(&tr,sizeof(tr),1,f);
fseek(f,(sizeof(tr)*(i-1)),SEEK_SET);
fwrite(&tr,sizeof(tr),1,f);
fseek(f,(sizeof(tr)),SEEK_END);
fclose(f);
printf("Done Deleting\n");
h=CreateFile(L"Vynil_List.bin",GENERIC_WRITE | GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
SetFilePointer(h,-sizeof(tr),NULL,FILE_END);
SetEndOfFile(h);
CloseHandle(h);
void Delete_entry(int i)

דא תודה שניצל שהעמדת אותי על דרך הישר ^^ חייתי באשליה קרוב לשעה

קישור לתוכן
שתף באתרים אחרים

אפשר לעשות זאת ולהסתפק בפונקציות הסטנדרטיות של C בלבד.

א. פתח את הקובץ לקריאה, קרא את כולו לזיכרון וסגור אותו. (fopen, fread)

ב.מחק, הזז בלוקים וכו' מהזיכרון. (פןנקציות memove, memcpy וכו')

ג. פתח את הקובץ לכתיבה, וכתוב את הזיכרון הערוך בקובץ (fopen, fwrite)

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

שנית ייתכן שגודל הקובץ כזה שיקשה עליך לקרוא את כולו לזיכרון.

חוץ מזה השיטה צריכה לעבוד.

אין דרך סטנדרטית לחתוך קובץ וצריך להשתמש בפונקציות של מערכת ההפעלה על מנת לבצע זאת. בלינוקס/יוניקס יש את הפונקציות truncate ו- ftruncate ובחלונות יש את הפונקציה SetEndOfFile

קישור לתוכן
שתף באתרים אחרים

בחיים האמיתיים לא כותבים לאותו קובץ אלא לקובץ backup ואם הפעולה הצליחה אז מןחקים את המקורי ומשנים שם לגיבוי.

בעליית התוכנה אם לא קיים הקובץ הראשי טוענים את הגיבוי.

פתרון ממש טריוויאלי לבעיה

קישור לתוכן
שתף באתרים אחרים

אם היית עוקב אחרי הת'רד היית רואה שהוא כבר עשה את כל מה שכתבת...

ראיתי ועקבתי, התשובה שלי היתה על מנת להבהיר שאפשר בלי פונקציות שחותכות את הקובץ, כלומר רק פונקציות סטנדרטיות (ובטח לא פונקציות מורכבות כמו CreateFile)

בחיים האמיתיים לא כותבים לאותו קובץ אלא לקובץ backup ואם הפעולה הצליחה אז מןחקים את המקורי ומשנים שם לגיבוי.

בעליית התוכנה אם לא קיים הקובץ הראשי טוענים את הגיבוי.

פתרון ממש טריוויאלי לבעיה

נכון, אבל דרישות התרגיל הן ללא קבצים נוספים.

קישור לתוכן
שתף באתרים אחרים

אבל זה אובר-קיל מטורף. אם הקובץ הוא בגודל 1 ג'יגה ואתה רוצה למחוק רשומה בודדת של 10 בתים אז זה ידרוש המון עבודה מיותרת.

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

קישור לתוכן
שתף באתרים אחרים

  • 3 שבועות מאוחר יותר...

תודה רבל לכולם על העזרה! בסוף שעות של שיטוטים באינטרנט מצאתי קטע קוד שעבד

שילוב של setendofFile וספריית io.h בC

 void Delete_entry(int i)

{
HANDLE h;
FILE *f;
struct Track tr;
f=fopen("Vinyl_List.bin", "r+b");
printf("Deleting\n");
fseek(f,-(sizeof(tr)),SEEK_END);
fread(&tr,sizeof(tr),1,f);
fseek(f,(sizeof(tr)*(i-1)),SEEK_SET);
fwrite(&tr,sizeof(tr),1,f);
fseek(f,(sizeof(tr)),SEEK_END);
rewind(f);
fclose(f);
h=(HANDLE)_get_osfhandle(fileno(fopen("Vinyl_List.bin", "r+b")));
SetFilePointer(h,-1*sizeof(tr),NULL,FILE_END);
SetEndOfFile(h);
CloseHandle(h);
printf("Done Deleting\n");
}

ככה ניראה הקוד הסופי (שעבד ד"א! ^^)

שד"א, משום מה לא עבד עם CREATEFILE

שוב תודה לכולם על העזרה, למדתי כמה דברים :)

- - - תגובה אוחדה: - - -

אבל זה אובר-קיל מטורף. אם הקובץ הוא בגודל 1 ג'יגה ואתה רוצה למחוק רשומה בודדת של 10 בתים אז זה ידרוש המון עבודה מיותרת.

אכן, אוברקיל מטורף...

אבל המרצה שלי נוטה לבקש כל מיני מטלות חסרות פואנטה בחיים האמיתיים רק כדי לראות אותנו מתרוצצים ומתאמצים

קישור לתוכן
שתף באתרים אחרים

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

×
  • צור חדש...