มีอันตรายในการเขียนข้อมูลดิบไปยังไฟล์หรือไม่? [ปิด]


12

ฉันกำลังทำงานกับปัญหาในการเขียนโปรแกรม Pearls - โดยเฉพาะการใช้งานโปรแกรมที่เรียงลำดับไฟล์ที่มีอย่างน้อย 10,000,000 จำนวนเต็ม (คอลัมน์ 1 ปัญหา 3) เนื่องจากหนังสือไม่ได้ระบุวิธีการจัดเก็บข้อมูลในไฟล์ฉันจึงพิจารณาจัดเก็บจำนวนเต็มเป็นไบต์ดิบ (มีข้อ จำกัด อื่น ๆ ที่ทำให้ตัวเลือกดิบเป็นตัวเลือกที่ดี) ฉันไม่เคยทำงานที่ระดับต่ำนี้มาก่อนดังนั้นฉันต้องการทราบว่ามีสิ่งใดที่อันตรายที่ฉันควรระวัง ฉันต้องกังวลเกี่ยวกับการใช้ลำดับจุดสิ้นสุดของไฟล์โดยไม่ตั้งใจเมื่อฉันเขียนไบต์ดิบไปยังไฟล์หรือไม่?

แก้ไข:

ตอนนี้ฉันรู้แล้วว่าคำถามของฉันกว้างแค่ไหน ฉันหมายถึงปัญหาของความหายนะมากขึ้นเช่นเขียนทับไฟล์อื่น ๆ บนดิสก์โดยไม่ตั้งใจ ขออภัยฉันไม่ชัดเจนในตอนแรก


6
โปรดทราบว่า Programming Pearls เป็นหนังสือที่เก่ามาก คุณสามารถอ่านจำนวนเต็ม 10 ^ 7 ทั้งหมดลงในหน่วยความจำบนเครื่องเดสก์ท็อปสมัยใหม่ทำการเรียงลำดับแล้วเขียนมันอีกครั้ง ในการรับจุดเริ่มต้นของบทนั้น จำกัด จำนวนที่คุณอ่านได้ตลอดเวลาให้เป็นเศษส่วนของจำนวนทั้งหมด หรือเพิ่มขนาดไฟล์เป็นจำนวนเต็ม 10 ^ 10
คาเลบ

3
ที่จริงแล้วเมื่อฉันได้ยินคำว่า "อันตราย" ฉันคิดถึงสิ่งต่าง ๆ ที่ทำให้พีซีของฉันระเบิดลบบัญชีธนาคารหรืออะไรทำนองนั้น และฉันคิดว่ามันน่าจะปลอดภัยที่สุดที่จะสมมติว่า - ตราบใดที่โปรแกรมของคุณไม่ได้ใช้สำหรับควบคุมแอร์บัสหรือโรงไฟฟ้า - ไม่มีอะไร "อันตราย" จริง ๆ ที่จะเกิดขึ้นเมื่อคุณลองสิ่งที่คุณมีอยู่ในใจ
Doc Brown

4
ไม่มีตัวอักษร EOF / ลำดับ

2
@delnan ปีที่ผ่านมาเมื่อตำนานของตัวละคร EOF อยู่ในสมัยฉันจำได้ว่าระบบป้องกันการคัดลอกที่ขึ้นอยู่กับ 'คัดลอกถึงตัวละคร EOF' ที่โปรแกรมคัดลอกหลายครั้ง บางโปรแกรมจะใส่ข้อมูลเพิ่มเติมที่จะตรวจสอบหลังจากตัวทำเครื่องหมาย EOF ของไฟล์ข้อความที่เกี่ยวข้อง แต่ก่อนที่จะสิ้นสุดการจัดสรรไฟล์ โปรแกรมคัดลอกจะไม่คัดลอกข้อมูลเพิ่มเติมที่ตรวจสอบความถูกต้องในการติดตั้ง ... อ๊ะ ... ความคิดถึง

อันตราย? เช่นเดียวกับใน "คอมพิวเตอร์ของฉันจะระเบิดถ้าฉันทำสิ่งนี้" Nope
jwenting

คำตอบ:


11

อันตรายเพียงอย่างเดียวที่คุณจะพบเจอคือความสิ้นหวังน้อยและใหญ่ (ไม่ว่าจะเป็นไบต์ที่สำคัญที่สุด อย่างไรก็ตามหากคุณยังคงอยู่ในสภาพแวดล้อมเดียวกันจะไม่มีปัญหา นอกเหนือจากทั่วไปเพื่อให้มั่นใจว่าการเขียน / การแยกวิเคราะห์ไปกลับ

ระบบไฟล์ถูกออกแบบมาเพื่อจัดการกับลำดับของไบต์ใด ๆ


2
+1 สำหรับบรรทัดสุดท้าย ฉันไม่แน่ใจว่าปัญหาใหญ่ / น้อยเป็นปัญหาเดียว - ตัวอย่างเช่น OP อาจสับสนได้ว่าขอบเขตระหว่างจำนวนเต็มเป็นอย่างไร แต่คำตอบที่ดีอยู่ดี
คาเลบ

27

ไม่ความจริงแล้วนี่เป็นรูปแบบไฟล์ที่ใช้งานได้หลายรูปแบบ ตัวอย่างทั่วไปของไฟล์ไบนารีเช่นนี้รวมถึงรูปภาพและไฟล์เพลง / เสียง

ในการรักษาความสมบูรณ์ของไฟล์และข้อมูลที่อ่านจากไฟล์โปรดปฏิบัติตามแนวทางเหล่านี้:

  • เปิดไฟล์ (อ่านหรือเขียน) เสมอโดยใช้โหมดเดียวกัน: ข้อความหรือไบนารี ความแตกต่างหลักคือโหมดข้อความใส่ใจเกี่ยวกับการขึ้นบรรทัดใหม่และอาจ "chomp" ปิดอักขระบรรทัดใหม่เมื่ออ่านไฟล์ (ขึ้นอยู่กับไลบรารีเฉพาะที่ใช้) โหมดข้อความอาจทำการแปล Unicode ที่มีโอกาสสำลักข้อมูลที่ไม่ใช่ Unicode
  • เมื่ออ่านข้อมูลที่ไม่ใช่สตริงโปรดอ่านโดยใช้ชนิดข้อมูลเดียวกันกับที่คุณเขียน ตัวอย่างเช่นหากสี่ไบต์แรกของไฟล์เป็นจำนวนเต็มอธิบายให้แน่ใจว่าได้อ่านและเขียนโดยใช้วิธีการที่ / ให้จำนวนเต็มเพื่อให้แน่ใจว่าได้รับการปฏิบัติอย่างสม่ำเสมอ ประเภทข้อมูลเดียวกันอาจมีขนาดแตกต่างกันในเครื่องที่แตกต่างกันและการผสมข้อมูลในเครื่องเดียวกันยังสามารถเปลี่ยนความหมายของข้อมูล (เช่นการตีความบิตในช่วงกลางของจำนวนเต็มอีกต่อไปเป็นบิตบิต)
  • Endianness: หากไลบรารีที่คุณใช้ไม่สามารถจัดการสิ่งนี้ได้อย่างสม่ำเสมอคุณอาจต้องจัดการด้วยตนเอง ตัวอย่างเช่น Java ใช้คำสั่งไบต์เครือข่าย (big endian) เสมอสำหรับประเภทหลายไบต์ C และ C ++ ใช้สิ่งที่ผู้ใช้ไลบรารีตัดสินใจโดยทั่วไปเหมือนกับโปรเซสเซอร์ (endian เล็ก ๆ น้อย ๆ ใน Intel, big endian กับคนอื่น ๆ ส่วนใหญ่) หากนี่คือการฝึกหัดอย่างรวดเร็วในระบบใดระบบหนึ่งมันไม่สำคัญ แต่มันก็ยังเป็นนิสัยที่ดีที่จะให้ความสนใจกับเรื่องนี้และใช้รหัสหากจำเป็น

รายละเอียดเฉพาะจะแตกต่างกันไปตามกรอบแพลตฟอร์มและภาษา แต่สิ่งนี้ควรครอบคลุม "gotchas" พื้นฐานด้วยไฟล์ I / O


3
จุดเพิ่มเติมสำหรับข้อมูลที่ไม่ใช่สตริง: ตรวจสอบให้แน่ใจว่าคุณใช้จำนวนไบต์ที่สอดคล้องกันสำหรับแต่ละประเภท ใน C และ C ++ intสามารถอยู่ที่ใดก็ได้ระหว่าง 2 ถึง 8 หรือมากกว่า (ไบต์จริง ๆ )
Bart van Ingen Schenau

นั่นรวมอยู่ในจุดที่สองของฉันเช่นจำนวนเต็ม 32 v. 64 บิต พวกเขาจะเป็นประเภทข้อมูลที่แตกต่างกัน

คุณอาจต้องการทำให้ชัดเจน ไม่ชัดเจนว่าintในสองเครื่องที่แตกต่างกันอาจได้รับการพิจารณาประเภทข้อมูลที่แตกต่างกัน
Bart van Ingen Schenau

9

นอกเหนือจาก gotchas ทั้งหมดที่กล่าวถึงแล้วหากคุณกำลังสร้างรูปแบบไฟล์ไบนารีใหม่แทนที่จะอ่านและเขียนข้อมูลในรูปแบบที่มีอยู่เป็นสิ่งสำคัญอย่างยิ่งที่คุณต้องรวมส่วนหัวของไฟล์ไว้ : บล็อกของข้อมูลที่จุดเริ่มต้น ของไฟล์ที่ระบุรูปแบบไฟล์อย่างไม่น่าสงสัยและบันทึกข้อมูลเมตาใด ๆ ที่อาจจำเป็นต้องใช้

ส่วนหัวไฟล์ที่ดีมีอย่างน้อยสามสิ่ง:

  • " หมายเลขเวทมนต์ " อย่างน้อยสี่ไบต์ หมายเลขอาถรรพ์ต้องrfc2119เป็น N ไบต์แรกในไฟล์ต้องไม่เคยถูกใช้สำหรับรูปแบบไฟล์อื่น ๆ ที่คุณสามารถขุดขึ้นมาและต้องมีอย่างน้อยหนึ่งไบต์ที่ไม่ใช่อักขระ ASCII ที่พิมพ์ได้ ดูข้อกำหนด PNGสำหรับวิธีการออกแบบหมายเลขเวทย์มนตร์ที่ละเอียดถี่ถ้วน ดูซอร์สโค้ดของfile(1)คำสั่งสำหรับฐานข้อมูลของตัวเลขเวทย์มนตร์ที่มีอยู่ซึ่งมีความครอบคลุมเท่าที่คุณจะหาได้

    จุดของเลขอาถรรพ์คือการกำหนดเลเบลไฟล์ในแบนด์ด้วยรูปแบบของมันอย่างไม่น่าสงสัย หากคุณไม่ได้ใส่หมายเลขเวทย์มนตร์หรือไม่ใช่สิ่งแรกสุดในไฟล์คุณจะเสี่ยงต่อการที่โปรแกรมระบุไฟล์ของคุณผิดประเภทไฟล์ประเภทอื่นซึ่งนำไปสู่การสูญเสียข้อมูลการตรวจจับไวรัสและอื่น ๆ หายนะ

  • ข้อบ่งชี้ของเวอร์ชันของรูปแบบไฟล์ แม้ว่าคุณคิดว่าคุณจะไม่ต้องแก้ไขรูปแบบไฟล์ของคุณให้ทำสองไบต์ถัดไปหลังจากเลขอาถรรพ์00 00แล้วเอกสารว่านี่เป็นหมายเลขเวอร์ชัน 16 บิตใน endianness ที่แน่นอน (แล้วแต่จำนวนใดก็ตามที่คุณต้องการ แต่เลือก หนึ่งและติดกับมันตลอดทั้งไฟล์ ) และจะเพิ่มขึ้นหากความหมายของข้อมูลที่ตามมามีการเปลี่ยนแปลงอย่างรุนแรง ตัวคุณในอนาคตจะขอบคุณ

    (สเปค PNG ใช้เส้นทางที่แตกต่างกันที่นี่ระบุว่ารูปแบบของชิ้นข้อมูลจะถูกแช่แข็งและการเปลี่ยนแปลงรูปแบบในอนาคตทั้งหมดจะอยู่ในรูปแบบของชิ้นส่วนแบบใหม่นั้นใช้ได้เช่นกัน แต่ฉันขอแนะนำให้ใช้ ผู้เริ่มต้นจนถึงการประมวลผลข้อมูลแบบไบนารีผู้ที่ออกแบบ PNG นั้นได้รับการรวบรวมจากประสบการณ์ที่สั่งสมมานานหลายทศวรรษด้วยรูปแบบภาพ)

  • กลไกบางอย่างสำหรับการฝังข้อมูลเมตาโดยพลการในไฟล์ สิ่งนี้สามารถทำได้ง่ายเหมือนกับการมีสองไบต์ถัดไปเป็นออฟเซ็ต 16 บิตจากจุดสิ้นสุดของส่วนหัวไปยังจุดเริ่มต้นของข้อมูลจริงโดยทุกสิ่งในระหว่างนั้นจะถูกตีความเป็นคู่ค่าคีย์ UTF-8 a la RFC 822 (นั่นคือ " Tag: value\n" - ถ้าคุณไปเส้นทางนี้ฉันไม่แนะนำให้อนุญาตให้พับเส้นยาว) อีกครั้ง PNG นั้นฉลาดกว่ามาก


ไม่จำเป็นต้องสร้างรูปแบบไฟล์ของคุณเอง ... เพียงแค่เก็บข้อมูลเป็นภาพ คุณอาจต้องเปลี่ยนขนาดข้อมูล (เช่น 10k x 1k) ดังนั้นจึงรองรับ หรือคุณอาจจะใช้พอดี ถ้าข้อมูลของคุณที่ซับซ้อนมากขึ้นกว่าเพียงแค่อาร์เรย์เดียวคุณสามารถใช้HDF , CDFหรือNetCDF
โจ

ฉันอยากจะแนะนำให้มันง่าย 256 เวอร์ชันที่แตกต่างกันจะพอเพียงและหากไม่ใช่เวอร์ชันเพิ่มเติมสามารถถูกออกแบบเป็นเวอร์ชันย่อยได้ของเวอร์ชัน 255 ในทำนองเดียวกันกับเมตาดาต้าก็เพียงพอที่จะเพิ่มลงในเวอร์ชันเมื่อจำเป็นจริงๆ @Joe Image ??? คุณกำลังหลีกเลี่ยงความสับสนของรูปแบบที่อาจเกิดขึ้นโดยทำให้ทุกคนสับสนก่อน!
maaartinus

@maaartinus การทำให้ฟิลด์เวอร์ชันสองไบต์บังคับให้ผู้ออกแบบรูปแบบยอมรับกับ endianness ล่วงหน้า พื้นที่สำหรับเมทาดาทาควรอยู่ในรูปแบบไบนารีของเวอร์ชัน 0 มิฉะนั้นคุณจะต้องปิดท้ายด้วย kludges ที่น่ากลัวอย่าง ID3 ฉันมีความเห็นอกเห็นใจอย่างมากสำหรับตรรกะของ PNG เกี่ยวกับความสามารถในการขยายผ่านประเภทก้อนใหม่แทนที่จะเป็นรูปแบบการกระแทก อย่างไรก็ตามไฟล์ที่มีโครงสร้างแบบกลุ่มมีความซับซ้อนเป็นของตัวเองดังนั้นฉันจึงลังเลที่จะแนะนำพวกเขาสำหรับกรณีง่าย ๆ ฉันถูกล่อลวงให้แนะนำ HDF เป็นรูปแบบทั่วไปที่จัดการกับปัญหาเหล่านี้แล้ว
zwol

2

สถาปัตยกรรมที่แตกต่างมีการแสดงที่แตกต่างกันสำหรับจำนวนเต็ม ความเสี่ยงหลักที่นี่คือการบันทึกการแสดงจำนวนเต็มในเครื่อง A แล้วพยายามอ่านกลับและตีความเนื้อหาเป็นจำนวนเต็มในเครื่อง B หากเครื่อง A และ B มีขนาดแตกต่างกันสำหรับจำนวนเต็มและ / หรือendianness ที่แตกต่างกันคุณ ' จะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด (เช่นใน C) หรือข้อยกเว้น

เนื่องจากนี่เป็นเพียงตัวอย่างการเขียนโปรแกรมและไม่ใช่โปรแกรม "ของจริง" จึงไม่ใช่ปัญหา หากนี่เป็นโปรแกรมจริงการหมุนรูปแบบไบนารีเฉพาะแอปพลิเคชันของคุณเองนั้นไม่ใช่ความคิดที่ดี มีวิธีแก้ปัญหาที่ดีกว่าเช่น SQLite หรือรูปแบบการทำให้เป็นสตริงแบบสตริงเช่น JSON, YAML, XML เป็นต้นสำหรับค่าเดียวที่เปลี่ยนเป็นสตริงจะเพียงพอ สำหรับรายการง่าย ๆ คุณสามารถบันทึกหนึ่งสายต่อบรรทัดและแยกอินพุตในบรรทัดใหม่เมื่อคุณอ่านกลับมา


เห็นด้วยโดยทั่วไป แต่ JSON หรือ XML จะเพิ่มขนาดของไฟล์ที่มีหมายเลข 10 ^ 7 อย่างมาก นอกจากนี้โดยทั่วไปแล้วพวกเขาจะอ่านและแยกวิเคราะห์ทั้งหมดในคราวเดียว แต่บทที่มีปัญหาเกี่ยวข้องกับการเรียงลำดับไฟล์ที่มีข้อมูลมากกว่าที่คุณจะพอดีกับหน่วยความจำที่มีอยู่
คาเลบ

ขึ้นอยู่กับสิ่งที่คุณทำ บางครั้งประสิทธิภาพการทำงานของ SQL เทียบกับการหมุนของคุณเองเป็นสำคัญ ครั้งสุดท้ายที่ฉันทำมันฉันมีบันทึกเล็ก ๆ และมีโอกาสสูงที่ฉันจะต้องการเพื่อนบ้าน การอ่านบล็อกขนาดใหญ่นอกดิสก์โดยทั่วไปจะไม่มีค่าใช้จ่ายเลยดังนั้นหากฉันต้องการบันทึกหนึ่งรายการฉันอ่าน 1,000 รายการลงในแคช บันทึกของฉันเกือบจะติดกันด้วย SQL ด้วยหัวดิสก์จะกระเด้งไปทั่วสถานที่
Loren Pechtel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.