ป้อนข้อมูลจากไฟล์และส่งออกไปยังไฟล์ การทำงานกับไฟล์ในภาษา C อินพุตและเอาท์พุตไปยังไฟล์ในภาษา C การรับข้อมูลเกี่ยวกับไดเร็กทอรี
โปรแกรมคอมพิวเตอร์ส่วนใหญ่ทำงานกับไฟล์ได้ ดังนั้นจึงจำเป็นต้องสร้าง ลบ เขียน อ่าน และเปิดไฟล์ ไฟล์คืออะไร? ไฟล์คือชุดไบต์ที่มีชื่อซึ่งสามารถจัดเก็บไว้ในอุปกรณ์จัดเก็บข้อมูลบางชนิดได้ ตอนนี้เป็นที่ชัดเจนแล้วว่าไฟล์หมายถึงลำดับไบต์ที่มีชื่อเฉพาะของตัวเอง เช่น file.txt ไฟล์ที่มีชื่อเดียวกันไม่สามารถอยู่ในไดเร็กทอรีเดียวกันได้ ชื่อไฟล์ไม่เพียงแต่อ้างอิงถึงชื่อเท่านั้น แต่ยังรวมถึงนามสกุลด้วย เช่น file.txt และ file.dat — ไฟล์ต่างๆ แม้ว่าชื่อจะเหมือนกันก็ตาม มีสิ่งที่เรียกว่าชื่อไฟล์แบบเต็ม - นี่คือที่อยู่แบบเต็มของไดเร็กทอรีไฟล์ที่ระบุชื่อไฟล์ เช่น D:\docs\file.txt สิ่งสำคัญคือต้องเข้าใจแนวคิดพื้นฐานเหล่านี้ ไม่เช่นนั้นการทำงานกับไฟล์จะเป็นเรื่องยาก
ในการทำงานกับไฟล์ คุณต้องรวมไฟล์ส่วนหัวไว้ด้วย
File I/O คล้ายกับ I/O มาตรฐาน ข้อแตกต่างเพียงอย่างเดียวคือ I/O จะดำเนินการกับไฟล์ แทนที่จะดำเนินการกับหน้าจอ หาก I/O ไปยังอุปกรณ์มาตรฐานดำเนินการโดยใช้อ็อบเจ็กต์ cin และ cout ดังนั้นเพื่อจัดระเบียบไฟล์ I/O ก็เพียงพอแล้วที่จะสร้างอ็อบเจ็กต์ของคุณเองที่สามารถนำมาใช้คล้ายกับตัวดำเนินการ cin และ cout
ตัวอย่างเช่น คุณต้องสร้างไฟล์ข้อความและเขียนบรรทัดการทำงานกับไฟล์ในภาษา C++ ลงไป ในการทำเช่นนี้คุณต้องทำตามขั้นตอนต่อไปนี้:
- สร้างอ็อบเจ็กต์ของคลาส ofstream ;
- เชื่อมโยงวัตถุคลาสกับไฟล์ที่จะเขียน;
- เขียนบรรทัดลงในไฟล์
- ปิดไฟล์
เหตุใดจึงจำเป็นต้องสร้างวัตถุ ofstream แทนที่จะเป็นวัตถุ ifstream เนื่องจากคุณจำเป็นต้องเขียนลงไฟล์ และหากคุณต้องการอ่านข้อมูลจากไฟล์ คลาสอ็อบเจ็กต์ ifstream จะถูกสร้างขึ้น
// สร้าง object สำหรับเขียนไฟล์ ofstream /*object name*/; // วัตถุของคลาส ofstream
ลองเรียกวัตถุ fout นี่คือสิ่งที่เราได้รับ:
ออฟสตรีม fout;
ทำไมเราถึงต้องการวัตถุ? วัตถุจะต้องสามารถเขียนลงไฟล์ได้ วัตถุได้ถูกสร้างขึ้นแล้ว แต่ไม่เกี่ยวข้องกับไฟล์ที่ต้องเขียนสตริงลงไป
Fout.open("cppstudio.txt"); // เชื่อมโยงวัตถุกับไฟล์
ด้วยการดำเนินการแบบจุด เราสามารถเข้าถึงเมธอดคลาส open() ซึ่งเราระบุชื่อไฟล์ในวงเล็บ ไฟล์ที่ระบุจะถูกสร้างขึ้นในไดเร็กทอรีปัจจุบันพร้อมกับโปรแกรม หากมีไฟล์ชื่อเดียวกัน ไฟล์ที่มีอยู่จะถูกแทนที่ด้วยไฟล์ใหม่ ดังนั้นไฟล์จึงเปิดอยู่ สิ่งที่เหลืออยู่คือการเขียนบรรทัดที่ต้องการลงไป ทำเช่นนี้:
ฟูต<< "Работа с файлами в С++"; // запись строки в файл
การใช้การดำเนินการสตรีมร่วมกับอ็อบเจ็กต์ fout สตริงการทำงานกับไฟล์ในภาษา C++ จะถูกเขียนลงในไฟล์ เนื่องจากไม่จำเป็นต้องเปลี่ยนเนื้อหาของไฟล์อีกต่อไป จึงต้องปิด กล่าวคือ จะต้องแยกอ็อบเจ็กต์ออกจากไฟล์
Fout.ปิด(); //ปิดไฟล์
ผลลัพธ์ - ไฟล์ถูกสร้างขึ้นโดยมีบรรทัดการทำงานกับไฟล์ใน C ++
ขั้นตอนที่ 1 และ 2 สามารถรวมเข้าด้วยกันได้ กล่าวคือ สร้างออบเจ็กต์และเชื่อมโยงกับไฟล์ในบรรทัดเดียว ทำเช่นนี้:
Ofstream fout("cppstudio.txt"); // สร้างอ็อบเจ็กต์ของคลาส ofstream และเชื่อมโยงกับไฟล์ cppstudio.txt
มารวมโค้ดทั้งหมดเข้าด้วยกันและรับโปรแกรมต่อไปนี้
// file.cpp: กำหนดจุดเริ่มต้นสำหรับแอปพลิเคชันคอนโซล #รวม "stdafx.h" #รวม
ยังคงต้องตรวจสอบว่าโปรแกรมทำงานอย่างถูกต้องหรือไม่ และหากต้องการทำสิ่งนี้ ให้เปิดไฟล์ cppstudio.txt และดูเนื้อหาแล้วมันควรจะเป็น-การทำงานกับไฟล์ในภาษา C++
- สร้างวัตถุของคลาส ifstream และเชื่อมโยงกับไฟล์ที่จะทำการอ่าน
- อ่านไฟล์;
- ปิดไฟล์
โปรแกรมแสดงวิธีการอ่านจากไฟล์ได้ 2 วิธี วิธีแรกใช้การถ่ายโอนไปยังสตรีม วิธีที่สองใช้ฟังก์ชันรับสาย() - ในกรณีแรก เฉพาะคำแรกเท่านั้นที่จะถูกอ่าน และในกรณีที่สอง สตริงที่มีความยาว 50 อักขระจะถูกอ่าน แต่เนื่องจากไฟล์มีอักขระน้อยกว่า 50 ตัว ระบบจึงอ่านอักขระจนถึงและรวมอักขระสุดท้ายด้วย โปรดทราบว่าการอ่านครั้งที่สอง (บรรทัดที่ 17) ต่อเนื่องหลังคำแรก ไม่ใช่ตั้งแต่ต้น เนื่องจากอ่านคำแรกแล้วบรรทัดที่ 14- ผลลัพธ์ของโปรแกรมแสดงในรูปที่ 1
การทำงานกับไฟล์ในภาษา C++ หากต้องการดำเนินการต่อ ให้กดปุ่มใดก็ได้ - -
รูปที่ 1 - การทำงานกับไฟล์ในภาษา C++
โปรแกรมทำงานได้อย่างถูกต้อง แต่สิ่งนี้ไม่ได้เกิดขึ้นเสมอไปแม้ว่าทุกอย่างจะเป็นไปตามรหัสก็ตาม ตัวอย่างเช่นชื่อของไฟล์ที่ไม่มีอยู่ถูกส่งไปยังโปรแกรมหรือมีข้อผิดพลาดในชื่อ แล้วไงล่ะ? ในกรณีนี้จะไม่มีอะไรเกิดขึ้นเลย ไม่พบไฟล์ซึ่งหมายความว่าจะไม่สามารถอ่านได้ ดังนั้นคอมไพลเลอร์จะละเว้นบรรทัดที่ทำงานบนไฟล์ เป็นผลให้โปรแกรมออกอย่างถูกต้อง แต่จะไม่มีอะไรแสดงบนหน้าจอ ดูเหมือนว่านี่จะเป็นปฏิกิริยาปกติอย่างสมบูรณ์ต่อสถานการณ์เช่นนี้ แต่ผู้ใช้ทั่วไปจะไม่เข้าใจว่าเกิดอะไรขึ้นและเหตุใดบรรทัดจากไฟล์จึงไม่ปรากฏบนหน้าจอ ดังนั้นเพื่อให้ทุกอย่างชัดเจน C++ จึงจัดให้มีฟังก์ชันดังกล่าว - is_open() ซึ่งส่งคืนค่าจำนวนเต็ม: 1 - หากเปิดไฟล์ได้สำเร็จ 0 - หากเปิดไฟล์ไม่ได้ มาแก้ไขโปรแกรมด้วยการเปิดไฟล์ เพื่อว่าถ้าไฟล์นั้นไม่ได้เปิดอยู่ ข้อความที่เกี่ยวข้องก็จะปรากฏขึ้น
// file_read.cpp: กำหนดจุดเริ่มต้นสำหรับแอปพลิเคชันคอนโซล #รวม "stdafx.h" #รวม
ผลลัพธ์ของโปรแกรมแสดงในรูปที่ 2
ไม่สามารถเปิดไฟล์ได้! หากต้องการดำเนินการต่อ ให้กดปุ่มใดก็ได้ - -
รูปที่ 2 - การทำงานกับไฟล์ในภาษา C++
ดังจะเห็นได้จากรูปที่ 2 โปรแกรมแจ้งว่าไม่สามารถเปิดไฟล์ได้ ดังนั้นหากโปรแกรมทำงานกับไฟล์ได้ ขอแนะนำให้ใช้ฟังก์ชันนี้ is_open() แม้ว่าคุณจะแน่ใจว่าไฟล์นั้นมีอยู่จริงก็ตาม
โหมดการเปิดไฟล์
โหมดการเปิดไฟล์จะกำหนดวิธีการใช้ไฟล์ ในการตั้งค่าโหมด คลาส ios_base จัดเตรียมค่าคงที่ที่กำหนดโหมดการเปิดไฟล์ (ดูตารางที่ 1)
โหมดการเปิดไฟล์สามารถตั้งค่าได้โดยตรงเมื่อสร้างวัตถุหรือเมื่อเรียกใช้ฟังก์ชัน open() .
Ofstream fout("cppstudio.txt", ios_base::app); // เปิดไฟล์เพื่อผนวกข้อมูลต่อท้ายไฟล์ fout.open("cppstudio.txt", ios_base::app); // เปิดไฟล์เพื่อผนวกข้อมูลต่อท้ายไฟล์
โหมดการเปิดไฟล์สามารถรวมกันได้โดยใช้การดำเนินการทางลอจิคัลระดับบิต หรือ- ตัวอย่างเช่น: ios_base::out | ios_base::trunc - เปิดไฟล์เพื่อเขียนหลังจากล้างข้อมูลแล้ว
ออบเจ็กต์ของคลาส ofstream เมื่อเชื่อมโยงกับไฟล์ โดยค่าเริ่มต้นจะมีโหมดการเปิดไฟล์ ios_base::out | ios_base::trunc . นั่นคือไฟล์จะถูกสร้างขึ้นหากไม่มีอยู่ หากมีไฟล์อยู่ เนื้อหาจะถูกลบ และตัวไฟล์จะพร้อมสำหรับการเขียน ออบเจ็กต์ของคลาส ifstream เมื่อเชื่อมโยงกับไฟล์ จะมีโหมดการเปิดไฟล์เริ่มต้น ios_base::in - ไฟล์เป็นแบบเปิดอ่านอย่างเดียว โหมดการเปิดไฟล์เรียกอีกอย่างว่าแฟล็ก เพื่อให้อ่านง่าย เราจะใช้คำนี้ในอนาคต ตารางที่ 1 ไม่ได้แสดงรายการแฟล็กทั้งหมด แต่สิ่งเหล่านี้น่าจะเพียงพอสำหรับการเริ่มต้นของคุณ
โปรดทราบว่าคำอธิบายของ ate และ app นั้นคล้ายกันมาก โดยทั้งคู่จะเลื่อนตัวชี้ไปที่ท้ายไฟล์ แต่แฟล็กของแอปอนุญาตให้เขียนได้เฉพาะที่ท้ายไฟล์เท่านั้น และแฟล็ก ate ก็ย้ายแฟล็กไปที่จุดสิ้นสุด ของไฟล์และไม่จำกัดตำแหน่งในการเขียน
มาพัฒนาโปรแกรมที่ใช้การดำเนินการ sizeof() เพื่อคำนวณคุณสมบัติของประเภทข้อมูลหลักใน C++ และเขียนลงในไฟล์ ข้อมูลจำเพาะ:
- จำนวนไบต์ที่จัดสรรให้กับชนิดข้อมูล
- ค่าสูงสุดที่ชนิดข้อมูลใดประเภทหนึ่งสามารถจัดเก็บได้
การเขียนไฟล์ควรทำในรูปแบบต่อไปนี้:
/* ประเภทข้อมูลไบต์ค่าสูงสุด bool = 1 255.00 char = 1 255.00 int สั้น = 2 32767.00 int สั้นที่ไม่ได้ลงนาม = 2 65535.00 int = 4 2147483647.00 int ที่ไม่ได้ลงนาม = 4 4294967295.00 long int = 4 .00 int ยาวที่ไม่ได้ลงนาม = 4 4294967295.00 ทศนิยม = 4 2147483647.00 ลอยยาว = 8 9223372036854775800.00 สองเท่า = 8 9223372036854775800.00 */
โปรแกรมดังกล่าวได้รับการพัฒนาแล้วก่อนหน้านี้ในส่วนนี้ แต่มีข้อมูลทั้งหมดเกี่ยวกับประเภทข้อมูลถูกส่งออกไปยังอุปกรณ์เอาต์พุตมาตรฐาน และเราจำเป็นต้องสร้างโปรแกรมใหม่เพื่อให้ข้อมูลถูกเขียนลงในไฟล์ ในการดำเนินการนี้ คุณจะต้องเปิดไฟล์ในโหมดเขียน โดยมีการตัดข้อมูลไฟล์ปัจจุบันออกเบื้องต้น ( บรรทัดที่ 14- เมื่อสร้างไฟล์และเปิดได้สำเร็จ (บรรทัดที่ 16 - 20) แทนที่จะเป็นคำสั่ง cout บรรทัดที่ 22เราใช้วัตถุ fout ดังนั้นข้อมูลประเภทข้อมูลจะถูกเขียนลงไฟล์แทนหน้าจอ
// write_file.cpp: กำหนดจุดเริ่มต้นสำหรับแอปพลิเคชันคอนโซล #รวม "stdafx.h" #รวม
เป็นไปไม่ได้เลยที่จะไม่สังเกตว่าการเปลี่ยนแปลงในโปรแกรมมีเพียงเล็กน้อย และต้องขอบคุณความจริงที่ว่าอินพุต/เอาท์พุตมาตรฐานและอินพุต/เอาท์พุตของไฟล์ถูกใช้ในลักษณะเดียวกันทุกประการ ท้ายโปรแกรมเวลา.บรรทัดที่ 45เราปิดไฟล์อย่างชัดเจน แม้ว่าจะไม่จำเป็น แต่ก็ถือว่าเป็นแนวทางการเขียนโปรแกรมที่ดี เป็นที่น่าสังเกตว่าฟังก์ชันและตัวจัดการทั้งหมดที่ใช้ในการจัดรูปแบบอินพุต/เอาท์พุตมาตรฐานนั้นเกี่ยวข้องกับอินพุต/เอาท์พุตของไฟล์ด้วย ดังนั้นจึงไม่มีข้อผิดพลาดเกิดขึ้นเมื่อมีการกล่าวคำสั่งศาล ถูกแทนที่ด้วยวัตถุสู้
แท็ก: ไฟล์ข้อความ, fopen, fclose, feof, setbuf, setvbuf, fflush, fgetc, fprintf, fscanf, fgets, สตรีมแบบบัฟเฟอร์, สตรีมแบบไม่มีบัฟเฟอร์
การทำงานกับไฟล์ข้อความ
การทำงานกับไฟล์ข้อความนั้นคล้ายคลึงกับการทำงานกับคอนโซล: การใช้ฟังก์ชันอินพุตที่จัดรูปแบบทำให้เราบันทึกข้อมูลลงในไฟล์ การใช้ฟังก์ชันเอาต์พุตที่จัดรูปแบบเราจะอ่านข้อมูลจากไฟล์ มีความแตกต่างมากมายที่เราจะดูในภายหลัง การดำเนินการหลักที่ต้องทำคือ
- 1. เปิดไฟล์เพื่อให้สามารถเข้าถึงได้ ดังนั้นคุณสามารถเปิดเพื่ออ่าน เขียน อ่านและเขียน เขียนใหม่หรือเขียนต่อท้ายไฟล์ ฯลฯ เมื่อคุณเปิดไฟล์ อาจเกิดข้อผิดพลาดมากมาย เช่น ไฟล์อาจไม่มีอยู่ อาจเป็นประเภทไฟล์ที่ไม่ถูกต้อง คุณอาจไม่ได้รับอนุญาตให้ทำงานกับไฟล์ ฯลฯ ทั้งหมดนี้จะต้องนำมาพิจารณาด้วย
- 2. ทำงานโดยตรงกับไฟล์ - การเขียนและการอ่าน ที่นี่เราต้องจำไว้ด้วยว่าเราไม่ได้ทำงานกับหน่วยความจำเข้าถึงโดยสุ่ม แต่ทำงานกับสตรีมแบบบัฟเฟอร์ซึ่งเพิ่มข้อมูลเฉพาะของตัวเอง
- 3. ปิดไฟล์ เนื่องจากไฟล์เป็นทรัพยากรภายนอกโปรแกรม หากไม่ได้ปิด ไฟล์จะยังคงค้างอยู่ในหน่วยความจำ ซึ่งอาจเป็นไปได้แม้ว่าโปรแกรมจะปิดแล้วก็ตาม (เช่น คุณจะไม่สามารถลบไฟล์ที่เปิดอยู่หรือทำการเปลี่ยนแปลงได้ ฯลฯ) นอกจากนี้บางครั้งไม่จำเป็นต้องปิด แต่ต้อง "เปิดใหม่" ไฟล์เพื่อเปลี่ยนโหมดการเข้าถึง
นอกจากนี้ยังมีงานอีกมากมายเมื่อเราไม่จำเป็นต้องเข้าถึงเนื้อหาของไฟล์: การเปลี่ยนชื่อ การย้าย การคัดลอก ฯลฯ น่าเสียดายที่มาตรฐาน C ไม่มีคำอธิบายฟังก์ชันสำหรับความต้องการเหล่านี้ แน่นอนว่าพร้อมใช้งานสำหรับการใช้งานคอมไพลเลอร์แต่ละรายการ การอ่านเนื้อหาของไดเร็กทอรี (โฟลเดอร์, ไดเร็กทอรี) ก็เป็นการเข้าถึงไฟล์เช่นกัน เนื่องจากตัวโฟลเดอร์นั้นเป็นไฟล์ที่มีข้อมูลเมตา
บางครั้งจำเป็นต้องดำเนินการเสริมบางอย่าง: ย้ายไปยังตำแหน่งที่ต้องการในไฟล์ จำตำแหน่งปัจจุบัน กำหนดความยาวของไฟล์ ฯลฯ
หากต้องการทำงานกับไฟล์ คุณต้องมีออบเจ็กต์ FILE ออบเจ็กต์นี้จัดเก็บตัวระบุของสตรีมไฟล์และข้อมูลที่จำเป็นในการจัดการ รวมถึงตัวชี้ไปยังบัฟเฟอร์ ตัวบ่งชี้ตำแหน่งไฟล์ และตัวบ่งชี้สถานะ
วัตถุ FILE นั้นเป็นโครงสร้าง แต่ไม่ควรเข้าถึงฟิลด์ของมัน โปรแกรมพกพาต้องถือว่าไฟล์เป็นวัตถุนามธรรมที่อนุญาตให้เข้าถึงสตรีมไฟล์
การสร้างและการจัดสรรหน่วยความจำสำหรับวัตถุประเภท FILE ดำเนินการโดยใช้ฟังก์ชัน fopen หรือ tmpfile (ยังมีอย่างอื่นอีก แต่เราจะเน้นที่สิ่งเหล่านี้เท่านั้น)
ฟังก์ชั่น fopen จะเปิดไฟล์ ได้รับสองอาร์กิวเมนต์ - สตริงที่มีที่อยู่ไฟล์และสตริงที่มีโหมดการเข้าถึงไฟล์ ชื่อไฟล์อาจเป็นแบบสัมบูรณ์หรือแบบสัมพันธ์ก็ได้ fopen ส่งคืนตัวชี้ไปยังวัตถุ FILE ที่สามารถใช้เพื่อเข้าถึงไฟล์เพิ่มเติม
FILE* fopen (ชื่อไฟล์ const char*, โหมด const char*);
ตัวอย่างเช่น ลองเปิดไฟล์แล้วเขียน Hello World ลงไป
#รวม
ฟังก์ชัน fopen จะจัดสรรหน่วยความจำให้กับอ็อบเจ็กต์เอง การทำความสะอาดจะดำเนินการโดยฟังก์ชัน fclose จำเป็นต้องปิดไฟล์ แต่จะไม่ปิดเอง
ฟังก์ชั่น fopen สามารถเปิดไฟล์ในโหมดข้อความหรือไบนารี ค่าเริ่มต้นคือข้อความ โหมดการเข้าถึงอาจเป็นดังนี้
พิมพ์ | คำอธิบาย |
---|---|
ร | การอ่าน. ไฟล์จะต้องมีอยู่ |
ว | เขียนไฟล์ใหม่ หากมีไฟล์ชื่อเดียวกันนี้อยู่แล้ว เนื้อหาจะหายไป |
ก | เขียนที่ส่วนท้ายของไฟล์ การดำเนินการกำหนดตำแหน่ง (fseek, fsetpos, frewind) จะถูกละเว้น ไฟล์จะถูกสร้างขึ้นหากไม่มีอยู่ |
ร+ | กำลังอ่านและอัพเดตครับ คุณสามารถอ่านและเขียนได้ ไฟล์จะต้องมีอยู่ |
มี+ | การบันทึกและการอัปเดต ไฟล์ใหม่จะถูกสร้างขึ้น หากมีไฟล์ชื่อเดียวกันนี้อยู่แล้ว เนื้อหาจะหายไป คุณสามารถเขียนและอ่านได้ |
เอ+ | จบการโพสต์และอัพเดต การดำเนินการกำหนดตำแหน่งเป็นแบบอ่านอย่างเดียวและละเว้นสำหรับการเขียน หากไม่มีไฟล์อยู่ ไฟล์ใหม่จะถูกสร้างขึ้น |
หากจำเป็นต้องเปิดไฟล์ในโหมดไบนารี ตัวอักษร b จะถูกเพิ่มที่ท้ายบรรทัด เช่น "rb", "wb", "ab" หรือสำหรับโหมดผสม "ab+", " wb+”, “ab+” แทนที่จะเป็น b คุณสามารถเพิ่มตัวอักษร t จากนั้นไฟล์จะเปิดในโหมดข้อความ ขึ้นอยู่กับการดำเนินการ ในมาตรฐาน C ใหม่ (2011) ตัวอักษร x หมายความว่า fopen ควรล้มเหลวหากไฟล์มีอยู่แล้ว มาเสริมโปรแกรมเก่าของเรา: เปิดไฟล์อีกครั้งและพิจารณาสิ่งที่เราเขียนไว้ที่นั่น
#รวม
แทนที่จะใช้ฟังก์ชัน fgets คุณสามารถใช้ fscanf ได้ แต่คุณต้องจำไว้ว่ามันสามารถอ่านบรรทัดได้จนถึงช่องว่างแรกเท่านั้น
fscanf(ไฟล์, "%127s", บัฟเฟอร์);
นอกจากนี้ แทนที่จะเปิดและปิดไฟล์ คุณสามารถใช้ฟังก์ชัน freopen ซึ่งจะ "เปิดใหม่" ไฟล์ด้วยสิทธิ์การเข้าถึงใหม่
#รวม
ฟังก์ชัน fprintf และ fscanf แตกต่างจาก printf และ scanf เพียงตรงที่ฟังก์ชันเหล่านี้ใช้เป็นอาร์กิวเมนต์แรกเป็นตัวชี้ไปยัง FILE ที่จะส่งออกหรืออ่านข้อมูล ควรเพิ่มทันทีว่าฟังก์ชัน printf และ scanf สามารถแทนที่ได้อย่างง่ายดายด้วยฟังก์ชัน fprintf และ fscanf ในระบบปฏิบัติการ (เรากำลังพิจารณาระบบปฏิบัติการที่ใช้กันทั่วไปและเหมาะสมที่สุด) มีสตรีมมาตรฐานสามรายการ: stdout สตรีมเอาต์พุตมาตรฐาน, stdin สตรีมอินพุตมาตรฐาน และ stderr สตรีมเอาต์พุตข้อผิดพลาดมาตรฐาน stderr สิ่งเหล่านี้จะเปิดขึ้นโดยอัตโนมัติเมื่อมีการเปิดตัวแอปพลิเคชันและเชื่อมโยงกับคอนโซล ตัวอย่าง
#รวม
เกิดข้อผิดพลาดในการเปิดไฟล์
หากการเรียกใช้ฟังก์ชัน fopen ล้มเหลว ก็จะส่งกลับค่า NULL ข้อผิดพลาดในการทำงานกับไฟล์เกิดขึ้นค่อนข้างบ่อย ดังนั้นทุกครั้งที่เปิดไฟล์เราจึงต้องตรวจสอบผลงาน
#รวม
ปัญหาเกิดขึ้นเมื่อเปิดไฟล์หลายไฟล์พร้อมกัน: หากไม่สามารถเปิดไฟล์ใดไฟล์หนึ่งได้ จะต้องปิดไฟล์ที่เหลือด้วย
ไฟล์ *inputFile, *outputFile;
ไม่ได้ลงนาม m, n;
ไม่ได้ลงนาม i, j;
inputFile = fopen(INPUT_FILE, READ_ONLY);
- if (inputFile == NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์ %s", INPUT_FILE); getch(); exit(3); ) outputFile = fopen(OUTPUT_FILE, WRITE_ONLY);
- if (outputFile == NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์ %s", OUTPUT_FILE); getch(); if (inputFile != NULL) ( fclose(inputFile); ) exit(4); ) ...
- ในกรณีง่ายๆ คุณสามารถดำเนินการแบบเผชิญหน้าได้ เช่นเดียวกับในโค้ดก่อนหน้า ในกรณีที่ซับซ้อนมากขึ้น จะมีการใช้วิธีการแทนที่ RAII จาก C++: wrappers หรือคุณสมบัติคอมไพเลอร์ (การล้างข้อมูลใน GCC) เป็นต้น
- การบัฟเฟอร์ข้อมูล
ตามที่กล่าวไว้ข้างต้น เมื่อเราส่งออกข้อมูล ข้อมูลนั้นจะถูกวางไว้ในบัฟเฟอร์ก่อน บัฟเฟอร์ถูกล้างแล้ว
#รวม
2) หากสตรีมถูกปิด
3) หากเราระบุอย่างชัดเจนว่าจำเป็นต้องล้างบัฟเฟอร์ (มีข้อยกเว้นที่นี่ด้วย :))
4) เคลียร์ด้วยหากโปรแกรมเสร็จสมบูรณ์ ในเวลาเดียวกัน ไฟล์ทั้งหมดจะถูกปิด ในกรณีที่เกิดข้อผิดพลาดรันไทม์ สิ่งนี้อาจไม่เกิดขึ้น
คุณสามารถบังคับให้บัฟเฟอร์ขนถ่ายได้โดยการเรียกใช้ฟังก์ชัน fflush(File *) ลองดูสองตัวอย่าง - แบบมีและไม่มีการทำความสะอาด
Int setvbuf (สตรีม FILE *, ถ่าน * บัฟเฟอร์, โหมด int, ขนาด size_t);
ซึ่งรับบัฟเฟอร์ที่มีขนาดตามใจชอบ โหมดสามารถรับค่าต่อไปนี้
- _IOFBF- บัฟเฟอร์เต็ม ข้อมูลจะถูกเขียนลงในไฟล์เมื่อเต็ม ในการอ่าน บัฟเฟอร์จะถือว่าเต็มเมื่อมีการร้องขอการดำเนินการอินพุตและบัฟเฟอร์ว่างเปล่า
- _IOLBF- การบัฟเฟอร์เชิงเส้น ข้อมูลจะถูกเขียนลงในไฟล์เมื่อเต็มหรือเมื่อพบอักขระขึ้นบรรทัดใหม่ เมื่ออ่าน บัฟเฟอร์จะถูกเติมลงในอักขระขึ้นบรรทัดใหม่เมื่อมีการร้องขอการดำเนินการอินพุตและบัฟเฟอร์ว่างเปล่า
- _IONBF– ไม่มีการบัฟเฟอร์ ในกรณีนี้ พารามิเตอร์ขนาดและบัฟเฟอร์จะถูกละเว้น
ตัวอย่าง: มาตั้งค่าบัฟเฟอร์ของเราเองแล้วดูว่าอ่านจากไฟล์อย่างไร ปล่อยให้ไฟล์สั้น (เช่น Hello, World!) แล้วเราจะอ่านมันทีละตัวอักษร
#รวม
จะเห็นได้ว่าข้อมูลอยู่ในบัฟเฟอร์แล้ว การอ่านอักขระทีละอักขระเสร็จสิ้นจากบัฟเฟอร์
ฟีฟ
ฟังก์ชั่น int feof (FILE * สตรีม); คืนค่าเป็นจริงหากถึงจุดสิ้นสุดของไฟล์ ฟังก์ชั่นนี้สะดวกในการใช้งานเมื่อคุณต้องการอ่านไฟล์ทั้งหมดตั้งแต่ต้นจนจบ ให้มีไฟล์ที่มีเนื้อหาข้อความ text.txt เราอ่านอักขระไฟล์ทีละอักขระและแสดงบนหน้าจอ
#รวม
ทุกอย่างจะเรียบร้อยดี แต่ฟังก์ชัน feof ทำงานไม่ถูกต้อง... เนื่องจากไม่ได้กำหนดแนวคิดเรื่อง "จุดสิ้นสุดไฟล์" ข้อผิดพลาดที่มักเกิดขึ้นเมื่อใช้ feof คือ ข้อมูลล่าสุดที่อ่านถูกพิมพ์สองครั้ง นี่เป็นเพราะว่าข้อมูลถูกเขียนไปยังบัฟเฟอร์อินพุต การอ่านครั้งล่าสุดเกิดขึ้นพร้อมกับข้อผิดพลาด และฟังก์ชันจะคืนค่าการอ่านเก่า
#รวม
ตัวอย่างนี้จะล้มเหลว (เป็นไปได้มากที่สุด) และพิมพ์อักขระตัวสุดท้ายของไฟล์สองครั้ง
วิธีแก้ไขคืออย่าใช้ feof ตัวอย่างเช่นจัดเก็บจำนวนบันทึกทั้งหมดหรือใช้ข้อเท็จจริงที่ว่าฟังก์ชัน fscanf ฯลฯ มักจะส่งคืนจำนวนค่าที่อ่านและจับคู่อย่างถูกต้อง
#รวม
ตัวอย่าง
1. ไฟล์หนึ่งประกอบด้วยตัวเลขสองตัว - ขนาดของอาร์เรย์ ลองเติมไฟล์ที่สองด้วยอาร์เรย์ของตัวเลขสุ่ม
#รวม
2. ผู้ใช้คัดลอกไฟล์ และเลือกโหมดการทำงานก่อน: ไฟล์สามารถส่งออกไปยังคอนโซลหรือคัดลอกไปยังไฟล์ใหม่ได้
#รวม
3. ผู้ใช้ป้อนข้อมูลจากคอนโซลและเขียนลงในไฟล์จนกว่าจะกดปุ่ม esc ตรวจสอบโปรแกรมและดู มันจะทำงานอย่างไรหากคุณป้อน backspace: สิ่งที่ส่งออกไปยังไฟล์และสิ่งที่ส่งออกไปยังคอนโซล
#รวม
4. ไฟล์มีจำนวนเต็ม ค้นหาค่าสูงสุดของพวกเขา เรามาใช้ประโยชน์จากข้อเท็จจริงที่ว่าฟังก์ชัน fscanf ส่งคืนจำนวนอ็อบเจ็กต์ที่อ่านและจับคู่อย่างถูกต้อง ควรคืนหมายเลข 1 ทุกครั้ง
#รวม
อีกวิธีหนึ่งคืออ่านตัวเลขจนกระทั่งถึงจุดสิ้นสุดของไฟล์
#รวม
5. ไฟล์ประกอบด้วยคำ: คำภาษารัสเซีย, ตาราง, คำภาษาอังกฤษ, ในหลายแถว ผู้ใช้ป้อนคำภาษาอังกฤษจำเป็นต้องส่งออกคำภาษารัสเซีย
ไฟล์การแปลจะมีลักษณะเช่นนี้
ดวงอาทิตย์
ปากกาดินสอ
ดินสอปากกาลูกลื่น
ประตูประตู
หน้าต่าง หน้าต่าง
เก้าอี้ เก้าอี้
เก้าอี้นวม
และบันทึกไว้ในการเข้ารหัส cp866 (OEM 866) สิ่งสำคัญคือ คำคู่สุดท้ายจะลงท้ายด้วยการขึ้นบรรทัดใหม่ด้วย
อัลกอริทึมมีดังนี้: เราอ่านบรรทัดจากไฟล์, ค้นหาเครื่องหมายแท็บในบรรทัด, แทนที่เครื่องหมายแท็บด้วยศูนย์, คัดลอกคำภาษารัสเซียจากบัฟเฟอร์, คัดลอกคำภาษาอังกฤษจากบัฟเฟอร์, ตรวจสอบความเท่าเทียมกัน
#รวม
6. นับจำนวนบรรทัดในไฟล์ เราจะอ่านอักขระไฟล์ทีละอักขระ โดยนับจำนวนอักขระ "\n" จนกว่าเราจะพบอักขระ EOF EOF เป็นอักขระพิเศษที่ระบุว่าอินพุตเสร็จสมบูรณ์แล้ว และไม่มีข้อมูลให้อ่านอีก ฟังก์ชันจะส่งกลับค่าลบในกรณีที่เกิดข้อผิดพลาด
หมายเหตุ: EOF เป็นประเภท int ดังนั้นคุณต้องใช้ int เพื่ออ่านอักขระ นอกจากนี้ ค่าของ EOF ไม่ได้ถูกกำหนดโดยมาตรฐาน
#define _CRT_SECURE_NO_WARNINGS #รวม
Ru-Cyrl 18-บทช่วยสอน ไซปาเชฟ เอส.เอส. 1989-04-14[ป้องกันอีเมล]สเตฟาน ไซปาเชฟ
นักเรียน
ยังไม่ชัดเจน? – เขียนคำถามไปที่กล่องจดหมาย
เพื่อความสะดวกในการเข้าถึงข้อมูลในอุปกรณ์จัดเก็บข้อมูลจะถูกจัดเก็บในรูปแบบไฟล์
ไฟล์คือพื้นที่ที่มีชื่อของหน่วยความจำภายนอกซึ่งจัดสรรไว้สำหรับจัดเก็บอาร์เรย์ของข้อมูล ข้อมูลที่อยู่ในไฟล์มีลักษณะที่หลากหลายมาก: โปรแกรมในอัลกอริธึมหรือภาษาเครื่อง ข้อมูลเริ่มต้นสำหรับการทำงานของโปรแกรมหรือผลการดำเนินการของโปรแกรม ข้อความฟรี ภาพกราฟิก ฯลฯ
ไดเร็กทอรี (โฟลเดอร์, ไดเร็กทอรี) - ชุดไบต์ที่มีชื่อบนสื่อเก็บข้อมูลที่มีชื่อของไดเร็กทอรีย่อยและไฟล์ที่ใช้ในระบบไฟล์เพื่อลดความซับซ้อนในการจัดระเบียบไฟล์ระบบไฟล์
FAT มีสามเวอร์ชันหลัก: FAT12, FAT16 และ FAT32 มีความแตกต่างกันในความลึกบิตของบันทึกในโครงสร้างดิสก์ เช่น จำนวนบิตที่จัดสรรเพื่อจัดเก็บหมายเลขคลัสเตอร์ FAT12 ใช้สำหรับฟล็อปปี้ดิสก์เป็นหลัก (สูงสุด 4 KB), FAT16 สำหรับดิสก์ความจุขนาดเล็ก, FAT32 สำหรับไดรฟ์ FLASH ความจุสูง (สูงสุด 32 GB)
มาดูโครงสร้างระบบไฟล์ที่ใช้ FAT32 เป็นตัวอย่างกัน
โครงสร้างไฟล์ FAT32
อุปกรณ์หน่วยความจำภายนอกในระบบ FAT32 มีการกำหนดแอดเดรสแบบบล็อกมากกว่าการกำหนดแอดเดรสแบบไบต์ ข้อมูลถูกเขียนไปยังอุปกรณ์หน่วยความจำภายนอกเป็นบล็อกหรือเซกเตอร์
เซกเตอร์คือหน่วยจัดเก็บข้อมูลขั้นต่ำที่สามารถกำหนดแอดเดรสได้บนอุปกรณ์จัดเก็บข้อมูลภายนอก โดยทั่วไป ขนาดเซกเตอร์ได้รับการแก้ไขที่ 512 ไบต์ ในการเพิ่มพื้นที่ที่อยู่ของอุปกรณ์หน่วยความจำภายนอก เซกเตอร์จะรวมกันเป็นกลุ่มที่เรียกว่าคลัสเตอร์
คลัสเตอร์คือการรวมตัวกันของหลายภาคส่วน ซึ่งถือได้ว่าเป็นหน่วยอิสระที่มีคุณสมบัติบางอย่าง คุณสมบัติหลักของคลัสเตอร์คือขนาด ซึ่งวัดเป็นจำนวนเซกเตอร์หรือจำนวนไบต์
ระบบไฟล์ FAT32 มีโครงสร้างดังนี้
คลัสเตอร์ที่ใช้สำหรับการเขียนไฟล์จะมีหมายเลขเริ่มต้นจาก 2 ตามกฎแล้ว คลัสเตอร์หมายเลข 2 จะถูกใช้โดยไดเรกทอรีราก และเริ่มจากคลัสเตอร์หมายเลข 3 อาร์เรย์ข้อมูลจะถูกจัดเก็บ เซกเตอร์ที่ใช้ในการจัดเก็บข้อมูลเหนือไดเร็กทอรีรากจะไม่ถูกรวมกลุ่ม
ขนาดไฟล์ขั้นต่ำที่ต้องการบนดิสก์สอดคล้องกับ 1 คลัสเตอร์
บูตเซกเตอร์เริ่มต้นด้วยข้อมูลต่อไปนี้:
- EB 58 90 – การกระโดดแบบไม่มีเงื่อนไขและลายเซ็น;
- 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
- 00 02 – จำนวนไบต์ในภาค (ปกติคือ 512)
- 1 ไบต์ – จำนวนเซกเตอร์ในคลัสเตอร์
- 2 ไบต์ – จำนวนเซกเตอร์สำรอง
นอกจากนี้ บูตเซกเตอร์ยังมีข้อมูลสำคัญต่อไปนี้:
- 0x10 (1 ไบต์) – จำนวนตาราง FAT (ปกติคือ 2)
- 0x20 (4 ไบต์) - จำนวนเซกเตอร์บนดิสก์
- 0x2С (4 ไบต์) - หมายเลขคลัสเตอร์ของไดเร็กทอรีราก
- 0x47 (11 ไบต์) – ป้ายกำกับโวลุ่ม;
- 0x1FE (2 ไบต์) - ลายเซ็นบูตเซกเตอร์ (55 AA)
เซกเตอร์ข้อมูลระบบไฟล์ประกอบด้วย:
- 0x00 (4 ไบต์) – ลายเซ็น (52 52 61 41)
- 0x1E4 (4 ไบต์) - ลายเซ็น (72 72 41 61);
- 0x1E8 (4 ไบต์) – จำนวนคลัสเตอร์ว่าง -1 หากไม่ทราบ
- 0x1EC (4 ไบต์) - จำนวนคลัสเตอร์ที่บันทึกไว้ล่าสุด
- 0x1FE (2 ไบต์) – ลายเซ็น (55 AA)
ตาราง FAT ประกอบด้วยข้อมูลเกี่ยวกับสถานะของแต่ละคลัสเตอร์บนดิสก์ 2 ไบต์ล่างของตาราง FAT จะเก็บ F8 FF FF 0F FF FF FF FF (ซึ่งสอดคล้องกับสถานะของคลัสเตอร์ 0 และ 1 ซึ่งไม่มีอยู่จริง) นอกจากนี้ สถานะของแต่ละคลัสเตอร์ประกอบด้วยหมายเลขของคลัสเตอร์ที่ไฟล์ปัจจุบันดำเนินต่อไปหรือข้อมูลต่อไปนี้:
- 00 00 00 00 – คลัสเตอร์ว่าง
- FF FF FF 0F – จุดสิ้นสุดของไฟล์ปัจจุบัน
- 8 ไบต์ – ชื่อไฟล์;
- 3 ไบต์ – นามสกุลไฟล์;
ไดเร็กทอรีรากประกอบด้วยชุดบันทึกข้อมูลแบบ 32 บิตเกี่ยวกับแต่ละไฟล์ ซึ่งมีข้อมูลต่อไปนี้:
เมื่อทำงานกับชื่อไฟล์ขนาดยาว (รวมถึงชื่อภาษารัสเซีย) ชื่อไฟล์จะถูกเข้ารหัสโดยใช้ระบบเข้ารหัส UTF-16 ในกรณีนี้จะมีการจัดสรร 2 ไบต์สำหรับการเข้ารหัสอักขระแต่ละตัว ในกรณีนี้ ชื่อไฟล์จะถูกเขียนในโครงสร้างต่อไปนี้:
- 1 ไบต์ลำดับ;
- 10 ไบต์ประกอบด้วยอักขระ 5 ตัวล่างของชื่อไฟล์
- คุณลักษณะ 1 ไบต์;
- สงวนไว้ 1 ไบต์;
- 1 ไบต์ - การตรวจสอบชื่อ DOS
- 12 ไบต์ประกอบด้วยอักขระ 3 ตัวล่างของชื่อไฟล์
- 2 ไบต์ – จำนวนของคลัสเตอร์แรก
- อักขระที่เหลือของชื่อยาว
การทำงานกับไฟล์ในภาษา C
สำหรับโปรแกรมเมอร์ ไฟล์ที่เปิดอยู่จะแสดงเป็นลำดับของข้อมูลที่อ่านหรือเขียน เมื่อเปิดไฟล์ขึ้นมาจะมีการเชื่อมโยงด้วย สตรีม I/O- ข้อมูลเอาต์พุตจะถูกเขียนไปยังสตรีม ข้อมูลอินพุตจะถูกอ่านจากสตรีม
เมื่อเปิดสตรีมสำหรับ I/O สตรีมจะเชื่อมโยงกับโครงสร้าง FILE มาตรฐาน ซึ่งกำหนดไว้ใน stdio.h โครงสร้าง FILE ประกอบด้วยข้อมูลที่จำเป็นเกี่ยวกับไฟล์
การเปิดไฟล์ทำได้โดยใช้ฟังก์ชัน fopen() ซึ่งจะส่งคืนตัวชี้ไปยังโครงสร้าง FILE ที่สามารถใช้สำหรับการดำเนินการกับไฟล์ในภายหลัง
FILE *fopen(ชื่อ, ประเภท);
ชื่อ – ชื่อของไฟล์ที่จะเปิด (รวมถึงเส้นทาง)
type เป็นตัวชี้ไปยังสตริงอักขระที่กำหนดวิธีการเข้าถึงไฟล์:
- "r" - เปิดไฟล์เพื่ออ่าน (ต้องมีไฟล์อยู่)
- "w" - เปิดไฟล์เปล่าเพื่อเขียน หากมีไฟล์อยู่ เนื้อหาจะสูญหาย
- "a" - เปิดไฟล์เพื่อเขียนต่อท้าย (เพื่อต่อท้าย); ไฟล์จะถูกสร้างขึ้นหากไม่มีอยู่
- "r+" - เปิดไฟล์เพื่ออ่านและเขียน (ต้องมีไฟล์อยู่)
- "w+" - เปิดไฟล์เปล่าเพื่ออ่านและเขียน หากมีไฟล์อยู่ เนื้อหาจะสูญหาย
- "a+" - เปิดไฟล์เพื่ออ่านและต่อท้าย หากไม่มีไฟล์อยู่ ไฟล์นั้นจะถูกสร้างขึ้น
ค่าที่ส่งกลับเป็นตัวชี้ไปยังกระแสเปิด หากพบข้อผิดพลาด จะส่งคืนค่า NULL
ฟังก์ชัน fclose() จะปิดสตรีมหรือสตรีมที่เกี่ยวข้องกับไฟล์ที่เปิดโดยใช้ฟังก์ชัน fopen() สตรีมที่จะปิดถูกกำหนดโดยอาร์กิวเมนต์ของฟังก์ชัน fclose()
ค่าส่งคืน: ค่า 0 หากปิดสตรีมสำเร็จ EOF คงที่หากเกิดข้อผิดพลาด
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#รวม
int หลัก() (
ไฟล์ *fp;
ชื่อถ่าน = "my.txt" ;
ถ้า ((fp = fopen(ชื่อ, "r" )) == NULL )
{
พิมพ์f( "ไม่สามารถเปิดไฟล์ได้");
รับชาร์();
กลับ 0;
}
// เปิดไฟล์สำเร็จ
... // การดำเนินการที่จำเป็นกับข้อมูล
fclose(fp);
รับชาร์();
กลับ 0;
}
การอ่านอักขระจากไฟล์:
ถ่าน fgetc (สตรีม);
อาร์กิวเมนต์ของฟังก์ชันเป็นตัวชี้ไปยังสตรีมประเภท FILE ฟังก์ชันส่งคืนรหัสของอักขระที่อ่าน หากถึงจุดสิ้นสุดของไฟล์หรือมีข้อผิดพลาดเกิดขึ้น ค่าคงที่ EOF จะถูกส่งกลับ
การเขียนสัญลักษณ์ลงในไฟล์:
fputc(ถ่าน, สตรีม);
อาร์กิวเมนต์ของฟังก์ชันคืออักขระและตัวชี้ไปยังสตรีมประเภท FILE ฟังก์ชันส่งคืนรหัสของอักขระที่อ่าน
ฟังก์ชัน fscanf() และ fprintf() คล้ายคลึงกับฟังก์ชัน scanf() และ printf() แต่ทำงานกับไฟล์ข้อมูลและมีตัวชี้ไฟล์เป็นอาร์กิวเมนต์แรก
fscanf(สตรีม, "InputFormat", อาร์กิวเมนต์);
ในบทความนี้ เราจะเรียนรู้วิธีการอ่านข้อมูลจากไฟล์และเขียนข้อมูลลงไฟล์ในโปรแกรม C ไฟล์ในภาษาซีใช้สำหรับบันทึกผลลัพธ์ของโปรแกรม C และใช้เมื่อเริ่มโปรแกรมอีกครั้ง ตัวอย่างเช่น คุณสามารถบันทึกผลการคำนวณและสถิติของเกมได้
หากต้องการทำงานกับไฟล์ในภาษา C คุณต้องรวมไลบรารี stdio.h ด้วย
#รวม
ที่จะทำงานร่วมกับ ไฟล์ใน Cคุณต้องระบุตัวชี้ไปยังไฟล์ตามตัวอย่าง
FILE *ชื่อตัวชี้ไฟล์;
ตัวอย่างเช่น
ไฟล์ *ครีบ;
ระบุตัวชี้ครีบไปยังไฟล์
ถัดไปคุณจะต้องเปิดไฟล์และเชื่อมโยงไปยังตัวชี้ไฟล์ หากต้องการเปิดไฟล์ในภาษา C เพื่ออ่าน ให้ใช้คำสั่ง
ชื่อตัวชี้ไฟล์= fopen("เส้นทางไฟล์", "r");
ยกตัวอย่างคำสั่งต่อไปนี้
fin = fopen("C:\\Users\\user\\Desktop\\data.txt", "r");
จะเปิดไฟล์ data.txt ซึ่งอยู่บนเดสก์ท็อปตามเส้นทาง C:\\Users\\user\\Desktop หากต้องการค้นหาเส้นทางไปยังไฟล์คุณสามารถเลือกไฟล์ด้วยเมาส์ได้โดยคลิกที่ปุ่มเมาส์ขวา และเลือกคุณสมบัติไฟล์ ส่วนตำแหน่งจะระบุเส้นทางไปยังไฟล์ โปรดทราบว่าในภาษา C เส้นทางจะถูกระบุโดยใช้เครื่องหมายทับสองอัน
หลังจากทำงานกับไฟล์ใน C แล้วคุณจะต้องปิดมันโดยใช้คำสั่ง
fclose(ชื่อตัวชี้ไฟล์)
การอ่านข้อมูลจากไฟล์ข้อความในภาษาซี
เพื่อให้สามารถอ่านอักขระภาษารัสเซียจากไฟล์ได้ คุณต้องกำหนดค่าการทำงานกับ Cyrillic โดยใช้คำสั่ง
setlocale(LC_ALL, "รัสเซีย");
ในกรณีนี้ คุณต้องรวม #include ไว้ที่ตอนเริ่มต้นของโปรแกรม
ตัวดำเนินการ fscanf()
เพื่ออ่านคำศัพท์จาก ไฟล์ใน Cใช้คำสั่ง fscanf() คำสั่งนี้คล้ายกับคำสั่งป้อนข้อมูลจากแป้นพิมพ์ เฉพาะพารามิเตอร์แรกเท่านั้นที่เป็นตัวชี้ไปยังไฟล์
fscanf(ตัวชี้ไฟล์,"%รูปแบบการป้อนข้อมูล1% รูปแบบการป้อนข้อมูล2...",&variable1,&variable2...);
ยกตัวอย่างคำสั่ง
fscanf(fin,"%d%d%d",&a,&b,&c);
อ่านสตริงของตัวแปรจำนวนเต็มสามตัวจากไฟล์ที่เชื่อมโยงกับครีบตัวชี้ไฟล์
ลองดูตัวอย่างโปรแกรมที่อ่านข้อมูลจากไฟล์ข้อความ data.txt ซึ่งมีการเขียนตัวเลขสามคอลัมน์และเขียนลงในอาร์เรย์ ข้อมูลแต่ละคอลัมน์มีอาร์เรย์ของตัวเอง รายละเอียดเกี่ยวกับ.
#รวม
#รวม
หลัก()
(int ก;
อินท์ข;
อินท์ค;
ฉัน;
// กำหนดตัวชี้ไปยังไฟล์
ไฟล์ *ครีบ;
//เปิดไฟล์เพื่ออ่าน
fin = fopen("C:\\Users\\user\\Desktop\\data.txt", "r");
// อ่านจากไฟล์ทีละบรรทัด
สำหรับ (i=0;i<3;i++)
{
// อ่านสตริงจากค่าไฟล์สามค่าและเขียนลงในอาร์เรย์
fscanf(fin,"%d%d%d",&a[i],&b[i],&c[i]);
}
// แสดงอาร์เรย์บนหน้าจอ
สำหรับ (i=0;i<3;i++)
{
printf("%d %d %d ",a[i],b[i],c[i]);
}
รับ();
//ปิดไฟล์
fclose(ครีบ);
}
การอ่านข้อมูลจากไฟล์ใน SI แบบทีละบรรทัด
ตัวดำเนินการ fscanf() อ่านคำจากไฟล์ เช่น สู่พื้นที่แรกที่พบเจอ
หากต้องการอ่านทั้งบรรทัดจากไฟล์ในภาษา C ให้ใช้โครงสร้าง
if (NULL != fgets (ตัวแปรสตริง, ความยาวสตริง, ตัวชี้ไฟล์))
{
การดำเนินการเมื่ออ่านบรรทัด
}
ตัวอย่างเช่น โปรแกรม C ที่อ่านสองบรรทัดจากไฟล์แล้วแสดงบนหน้าจอ
#รวม
#รวม
#รวม
หลัก()
{
// ตั้งค่าตัวแปรสตริง
ถ่าน st1;
ถ่าน st2;
//กำหนด pointer ไปยังไฟล์
ไฟล์ *ครีบ;
// ตั้งค่างานด้วยอักษรซีริลลิก
setlocale(LC_ALL, "รัสเซีย");
//เปิดไฟล์เพื่ออ่าน
fin = fopen("C:\\data.txt", "r");
// อ่านบรรทัดแรกจากไฟล์
ถ้า (NULL != fgets (st1, 100, fin))
{
// แสดงสตริงบนหน้าจอ
printf("%s ",st1);)
// อ่านบรรทัดที่สองจากไฟล์
ถ้า (NULL != fgets (st2, 100, ครีบ))
{
// แสดงสตริงบนหน้าจอ
printf("%s ",st2);)
// ปิดไฟล์เพื่ออ่าน
fclose(ครีบ);
}
การเขียนข้อมูลลงไฟล์ข้อความในภาษาซี
เพื่อบันทึกข้อมูล ไปยังไฟล์ในภาษา Cคุณต้องเปิดไฟล์ในโหมดบันทึก
ชื่อตัวชี้ไฟล์= fopen("เส้นทางไฟล์", "w");
หากต้องการเขียนบรรทัดในไฟล์ข้อความ ให้ใช้คำสั่ง fprnitf() ซึ่งคล้ายกับคำสั่งในภาษา C เพียงพารามิเตอร์แรกเท่านั้นที่เป็นตัวชี้ไปยังไฟล์
fprintf (ชื่อตัวชี้ไฟล์, "% รูปแบบอินพุต", ตัวแปร);
เช่น การเขียนค่าตัวแปร a ลงในไฟล์ out.txt
ก=10;
fout = fopen("C:\\Users\\user\\Desktop\\out.txt", "w");
fprintf(fout,"%d", a);
ตัวอย่างของโปรแกรมภาษาซีที่ขอตัวเลขสองตัวและเขียนตัวเลขทั้งสองนี้และผลรวมของตัวเลขเหล่านั้นลงในไฟล์ out.txt
#รวม
#รวม
หลัก()
(int ก;
อินท์ข;
อินท์ค;
ไฟล์ *fout;
fout = fopen("C:\\Users\\user\\Desktop\\out.txt", "w");
printf("ใส่หมายเลขแรก");
scanf("%d", &a);
printf("กรอกหมายเลขที่สอง");
scanf("%d", &b);
ค=ก+ข;
fprintf(fout,"%d %d %d",a,b,c);
รับ();
fclose(fout);
}
กลไก I/O ที่พัฒนาโดย ไม่สอดคล้องกับรูปแบบการเขียนโปรแกรมเชิงวัตถุที่เป็นที่ยอมรับโดยทั่วไปในปัจจุบัน นอกจากนี้ยังใช้การทำงานของตัวชี้อย่างมาก ซึ่งถือว่าอาจไม่ปลอดภัยในสภาพแวดล้อมการเรียกใช้โค้ดที่ปลอดภัยสมัยใหม่ อีกทางเลือกหนึ่งเมื่อพัฒนาแอปพลิเคชันแอปพลิเคชันคือกลไกของคลาส I/O มาตรฐานที่จัดทำโดยมาตรฐานภาษา C++
กำลังเปิดไฟล์
คลาสที่ใช้กันมากที่สุดคือ ifstream สำหรับการอ่าน ofstream สำหรับการเขียน และ fstream สำหรับการแก้ไขไฟล์
คลาส I/O แบบเธรดทั้งหมดได้รับมาทางอ้อมจาก iOS บรรพบุรุษร่วมกัน โดยสืบทอดฟังก์ชันการทำงานอย่างสมบูรณ์ ดังนั้น โหมดการเปิดไฟล์จะถูกระบุโดยสมาชิกข้อมูลของประเภทแจกแจง open_mode ซึ่งกำหนดไว้ดังนี้:
Enum open_mode (แอป, ไบนารี, เข้า, ออก, ตัดทอน, กิน);
ด้านล่างนี้เป็นค่าที่เป็นไปได้ของธงและวัตถุประสงค์
ตัวอย่างเช่น หากต้องการเปิดไฟล์ชื่อ test.txt เพื่ออ่านข้อมูลในรูปแบบไบนารี่ คุณจะต้องเขียนว่า:
ไฟล์อิฟสตรีม; file.open("test.txt", ios::in | ios::binary);
ตัวดำเนินการโลจิคัล OR (|) ช่วยให้คุณสร้างโหมดที่มีการรวมกันของแฟล็กใดก็ได้ ดังนั้น เพื่อที่ว่าเมื่อเปิดไฟล์ตามรายการ คุณจะไม่เขียนทับไฟล์ที่มีอยู่ด้วยชื่อเดียวกันโดยไม่ตั้งใจ คุณต้องใช้แบบฟอร์มต่อไปนี้:
ไฟล์ออฟสตรีม; file.open("test.txt", ios::out | ios::app);
สันนิษฐานว่าไฟล์ส่วนหัวที่เกี่ยวข้องรวมอยู่ในโครงการ:
#รวม
หากต้องการตรวจสอบว่าเปิดไฟล์สำเร็จหรือไม่ คุณสามารถใช้โครงสร้างได้
ถ้า (!file) ( //การจัดการข้อผิดพลาดในการเปิดไฟล์)
ตัวดำเนินการรวมและแยก
ถูกแทนที่ในคลาสการจัดการไฟล์ ตัวดำเนินการรวม (<<) записывает данные в файловый поток. Как только вы открыли файл для записи, можно записывать в него текстовую строку целиком:
ไฟล์<< "Это строка текста";
คุณยังสามารถเขียนสตริงข้อความเป็นส่วนๆ ได้:
ไฟล์<< "Это " << "строка " << "текста";
คำสั่ง endl สิ้นสุดอินพุตบรรทัดด้วยการขึ้นบรรทัดใหม่:
ไฟล์<< "Это строка текста" << endl;
การใช้ตัวดำเนินการรวมทำให้ง่ายต่อการเขียนค่าของตัวแปรหรือองค์ประกอบอาร์เรย์ลงในไฟล์:
ไฟล์ออฟสตรีม ("Temp.txt"); char buff = "อาร์เรย์ข้อความมีตัวแปร"; int vx = 100; โฟลต pi = 3.14159; ไฟล์<< buff << endl << vx << endl << pi << endl;
จากการรันโค้ด ไฟล์ข้อความ Temp.txt สามบรรทัดจะถูกสร้างขึ้น:
อาร์เรย์ข้อความมีตัวแปร 100 3.14159
โปรดทราบว่าค่าตัวเลขจะถูกเขียนลงในไฟล์เป็นสตริงข้อความแทนที่จะเป็นค่าไบนารี
ตัวดำเนินการดึงข้อมูล(>>) ให้ผลตรงกันข้าม ดูเหมือนว่าหากต้องการแยกอักขระออกจากไฟล์ Temp.txt ที่เขียนไว้ก่อนหน้านี้ คุณจะต้องเขียนโค้ดดังนี้:
ไฟล์ Ifstream ("Temp.txt"); หนังถ่าน; intvx; พายลอย; ไฟล์ >> บัฟ >> vx >> pi;
อย่างไรก็ตาม ตัวดำเนินการแยกจะหยุดที่ตัวคั่นแรกที่พบ (ช่องว่าง แท็บ หรือขึ้นบรรทัดใหม่) ดังนั้น เมื่อแยกวิเคราะห์ประโยค “อาร์เรย์ข้อความมีตัวแปร” จะมีเพียงคำว่า “ข้อความ” เท่านั้นที่จะถูกเขียนลงในอาร์เรย์บัฟ ช่องว่างจะถูกละเว้น และคำว่า “อาร์เรย์” จะกลายเป็นค่าของตัวแปร vx ทั้งหมด และโค้ด การดำเนินการจะ "ผิดพลาด" โดยมีการละเมิดโครงสร้างข้อมูลอย่างหลีกเลี่ยงไม่ได้ ต่อไป เมื่อพูดถึงคลาส ifstream เราจะแสดงวิธีจัดระเบียบการอ่านไฟล์จากตัวอย่างก่อนหน้านี้อย่างเหมาะสม
คลาส ifstream: การอ่านไฟล์
ตามชื่อที่แนะนำ คลาส ifstream ได้รับการออกแบบมาเพื่ออินพุตสตรีมไฟล์ วิธีการหลักของชั้นเรียนมีดังต่อไปนี้ ส่วนใหญ่สืบทอดมาจากคลาส istream และโอเวอร์โหลดเพื่อขยายฟังก์ชันการทำงานหลัก ตัวอย่างเช่น ฟังก์ชัน get ขึ้นอยู่กับพารามิเตอร์การโทร สามารถอ่านได้ไม่เพียงแต่อักขระตัวเดียว แต่ยังรวมถึงกลุ่มอักขระด้วย
ตอนนี้เป็นที่ชัดเจนแล้วว่าตัวอย่างก่อนหน้านี้จำเป็นต้องได้รับการแก้ไขอย่างไร เพื่อให้การใช้ตัวดำเนินการแยกข้อมูลให้ผลลัพธ์ที่คาดหวัง:
ไฟล์ Ifstream ("Temp.txt"); หนังถ่าน; intvx; พายลอย; file.getline(บัฟ, ขนาดของ(บัฟ)); ไฟล์ >> vx >> pi:
เมธอด getline จะอ่านบรรทัดแรกของไฟล์จนจบ และตัวดำเนินการ >> จะกำหนดค่าให้กับตัวแปร
ตัวอย่างต่อไปนี้แสดงการเพิ่มข้อมูลลงในไฟล์ข้อความแล้วอ่านทั้งไฟล์ มีการใช้ while(1) วนซ้ำแทน while(!file2.eof()) ด้วยเหตุผลที่กล่าวถึงใน
#รวม
ถ้า (file2.eof()) พัง;
#รวม
รหัสนี้ภายใต้ระบบปฏิบัติการ Windows ขึ้นอยู่กับการมีอักขระขึ้นบรรทัดใหม่ในบรรทัดสุดท้ายของไฟล์ด้วย ซึ่งจะเชื่อถือได้มากกว่าหากทำเช่นนี้:
ในขณะที่ (1) ( if (file.eof()) break; file.getline(str, sizeof(str)); cout<< str << endl; }
ไม่จำเป็นต้องเรียกวิธีการเปิดและปิดที่ชัดเจน แน่นอนว่าการเรียก Constructor ด้วยอาร์กิวเมนต์ทำให้คุณสามารถเปิดไฟล์ได้ทันทีในขณะที่สร้างอ็อบเจ็กต์ไฟล์แบบเธรด:
ไฟล์ Ifstream("test.txt");
แทนที่จะใช้วิธีปิด คุณสามารถใช้ตัวดำเนินการลบ ซึ่งจะเรียกตัวทำลายของออบเจ็กต์ไฟล์โดยอัตโนมัติและปิดไฟล์ โค้ดลูป while ช่วยให้มั่นใจได้ถึงการตรวจสอบการสิ้นสุดไฟล์ที่เหมาะสม
คลาส ofstream: การเขียนไฟล์
คลาส ofstream ได้รับการออกแบบมาเพื่อส่งออกข้อมูลจากสตรีมไฟล์ ต่อไปนี้จะแสดงวิธีการหลักของคลาสนี้
ตัวดำเนินการรวมที่อธิบายไว้ก่อนหน้านี้สะดวกสำหรับการจัดระเบียบการเขียนลงในไฟล์ข้อความ:
ไฟล์ Ofstream("temp.txt"); ถ้า (!file) กลับมา; สำหรับ (int i=1; i<=3; i++) file << "Строка " << i << endl; file.close();
ไฟล์ไบนารี
โดยหลักการแล้ว ข้อมูลไบนารีจะถือเป็นข้อมูลข้อความ ข้อแตกต่างก็คือ ถ้าข้อมูลไบนารี่ถูกเขียนในโครงสร้างโลจิคัลเฉพาะ จะต้องอ่านจากไฟล์ลงในตัวแปรที่มีโครงสร้างประเภทเดียวกัน
พารามิเตอร์แรกของวิธีการเขียนและอ่าน (ที่อยู่ของบล็อกการเขียน/อ่าน) จะต้องเป็นประเภทตัวชี้อักขระ char * ดังนั้นจึงจำเป็นต้องทำการแปลงประเภทที่อยู่ของโครงสร้าง void * อย่างชัดเจน พารามิเตอร์ที่สองระบุว่าบล็อกไบนารีของไฟล์มีขนาดไบต์คงที่โดยไม่คำนึงถึงความยาวบันทึกจริง แอปพลิเคชันต่อไปนี้เป็นตัวอย่างของการสร้างและการแสดงข้อมูลในสมุดบันทึกอย่างง่าย รายการไฟล์จะถูกอ่านตามลำดับและแสดงบนคอนโซล
#รวม
ผลจากการรันโค้ดนี้ ทำให้ไฟล์ไบนารี Notebook.dat ถูกสร้างขึ้นจากสามบล็อก แต่ละบล็อกมีขนาด 80 ไบต์ (สมมติว่าอักขระเป็นไบต์เดียว) โดยปกติแล้ว คุณสามารถใช้วิธีการเธรดอื่นๆ และดำเนินการใดๆ บนฟิลด์ของโครงสร้างข้อมูลเฉพาะได้
คลาส fstream: การเข้าถึงไฟล์แบบสุ่ม
สมมติว่าเรามี 100 รายการในสมุดบันทึกของเรา และเราต้องการนับรายการที่ 50 แน่นอนคุณสามารถจัดระเบียบและอ่านบันทึกทั้งหมดตั้งแต่รายการแรกจนถึงรายการที่กำหนดได้ เห็นได้ชัดว่าวิธีแก้ปัญหาที่ตรงเป้าหมายมากกว่าคือตั้งค่าตัวชี้ตำแหน่งไฟล์ pos โดยตรงเป็นรายการ 50 แล้วอ่านจากมัน:
Ifstream ifile("Notebook.dat", ios::binary); int pos = 49 * ขนาดของ (หมายเหตุ); ifile.seekg(pos); // ค้นหารายการบันทึกย่อที่ 50;
//หมายเหตุ – โครงสร้าง “บันทึก” ที่อธิบายไว้ข้างต้น ifile.read((char*)&Note, sizeof(Notes));
การดำเนินการค้นหาดังกล่าวจะมีประสิทธิภาพหากไฟล์ประกอบด้วยบันทึกที่มีขนาดที่รู้จักและคงที่ หากต้องการแทนที่เนื้อหาของบันทึกที่กำหนดเอง คุณต้องเปิดสตรีมเอาต์พุตในโหมดแก้ไข:
Ofstream ofile ("Notebook.dat", ios::binary | ios::ate); int pos = 49 * ขนาดของ (หมายเหตุ); ofile แสวงหา (pos); // ค้นหาบันทึกย่อที่ 50 หมายเหตุ Note50 = ("Yeltsin Boris Nikolaevich", "095-222-3322", 64); ofile.write((ถ่าน*)&หมายเหตุ, ขนาดของ(หมายเหตุ)); // แทนที่
สุดท้ายนี้ เป็นไปได้ที่จะเปิดไฟล์พร้อมกันเพื่ออ่าน/เขียน โดยใช้วิธีการที่สืบทอดมาจากคลาสสตรีมมิ่ง fstream จากรุ่นก่อน เนื่องจากคลาส fstream นั้นได้มาจาก istream และ ostream (พาเรนต์ของ ifstream และ ofstream ตามลำดับ) วิธีการทั้งหมดที่กล่าวถึงก่อนหน้านี้จึงมีอยู่ในแอปพลิเคชัน
ตัวอย่างต่อไปนี้แสดงรายการการจัดเรียงรายการแรกและรายการที่สามใหม่ในไฟล์ Notebook.dat
#รวม
ในตัวสร้างของออบเจ็กต์ไฟล์ คุณต้องระบุแฟล็ก ios::in และ ios::out เพื่อให้สามารถอ่านและเขียนพร้อมกันได้ ผลจากการรันโค้ดนี้ รายการแรกและรายการที่สามในไฟล์ไบนารี Notebook.dat จะถูกสลับ
มีตัวอย่างเพิ่มเติมในหัวข้อนี้