ป้อนข้อมูลจากไฟล์และส่งออกไปยังไฟล์ การทำงานกับไฟล์ในภาษา 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++ ลงไป ในการทำเช่นนี้คุณต้องทำตามขั้นตอนต่อไปนี้:

  1. สร้างอ็อบเจ็กต์ของคลาส ofstream ;
  2. เชื่อมโยงวัตถุคลาสกับไฟล์ที่จะเขียน;
  3. เขียนบรรทัดลงในไฟล์
  4. ปิดไฟล์

เหตุใดจึงจำเป็นต้องสร้างวัตถุ 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" #รวม ใช้เนมสเปซมาตรฐาน; int main(int argc, char* argv) ( ofstream fout("cppstudio.txt"); // สร้างอ็อบเจ็กต์ของคลาส ofstream เพื่อบันทึกและเชื่อมโยงกับไฟล์ cppstudio.txt fout<< "Работа с файлами в С++"; // запись строки в файл fout.close(); // закрываем файл system("pause"); return 0; }

ยังคงต้องตรวจสอบว่าโปรแกรมทำงานอย่างถูกต้องหรือไม่ และหากต้องการทำสิ่งนี้ ให้เปิดไฟล์ cppstudio.txt และดูเนื้อหาแล้วมันควรจะเป็น-การทำงานกับไฟล์ในภาษา C++

  1. สร้างวัตถุของคลาส ifstream และเชื่อมโยงกับไฟล์ที่จะทำการอ่าน
  2. อ่านไฟล์;
  3. ปิดไฟล์
// file_read.cpp: กำหนดจุดเริ่มต้นสำหรับแอปพลิเคชันคอนโซล #รวม "stdafx.h" #รวม #รวม ใช้เนมสเปซมาตรฐาน; int main(int argc, char* argv) ( setlocale(LC_ALL, "rus"); // การแสดงที่ถูกต้องของ Cyrillic char buff; // บัฟเฟอร์สำหรับการจัดเก็บข้อความระดับกลางที่อ่านจากไฟล์ ifstream fin ("cppstudio.txt") ; // เปิดไฟล์เพื่ออ่าน fin >><< buff << endl; // напечатали это слово fin.getline(buff, 50); // считали строку из файла fin.close(); // закрываем файл cout << buff << endl; // напечатали эту строку system("pause"); return 0; }

โปรแกรมแสดงวิธีการอ่านจากไฟล์ได้ 2 วิธี วิธีแรกใช้การถ่ายโอนไปยังสตรีม วิธีที่สองใช้ฟังก์ชันรับสาย() - ในกรณีแรก เฉพาะคำแรกเท่านั้นที่จะถูกอ่าน และในกรณีที่สอง สตริงที่มีความยาว 50 อักขระจะถูกอ่าน แต่เนื่องจากไฟล์มีอักขระน้อยกว่า 50 ตัว ระบบจึงอ่านอักขระจนถึงและรวมอักขระสุดท้ายด้วย โปรดทราบว่าการอ่านครั้งที่สอง (บรรทัดที่ 17) ต่อเนื่องหลังคำแรก ไม่ใช่ตั้งแต่ต้น เนื่องจากอ่านคำแรกแล้วบรรทัดที่ 14- ผลลัพธ์ของโปรแกรมแสดงในรูปที่ 1

การทำงานกับไฟล์ในภาษา C++ หากต้องการดำเนินการต่อ ให้กดปุ่มใดก็ได้ - -

รูปที่ 1 - การทำงานกับไฟล์ในภาษา C++

โปรแกรมทำงานได้อย่างถูกต้อง แต่สิ่งนี้ไม่ได้เกิดขึ้นเสมอไปแม้ว่าทุกอย่างจะเป็นไปตามรหัสก็ตาม ตัวอย่างเช่นชื่อของไฟล์ที่ไม่มีอยู่ถูกส่งไปยังโปรแกรมหรือมีข้อผิดพลาดในชื่อ แล้วไงล่ะ? ในกรณีนี้จะไม่มีอะไรเกิดขึ้นเลย ไม่พบไฟล์ซึ่งหมายความว่าจะไม่สามารถอ่านได้ ดังนั้นคอมไพลเลอร์จะละเว้นบรรทัดที่ทำงานบนไฟล์ เป็นผลให้โปรแกรมออกอย่างถูกต้อง แต่จะไม่มีอะไรแสดงบนหน้าจอ ดูเหมือนว่านี่จะเป็นปฏิกิริยาปกติอย่างสมบูรณ์ต่อสถานการณ์เช่นนี้ แต่ผู้ใช้ทั่วไปจะไม่เข้าใจว่าเกิดอะไรขึ้นและเหตุใดบรรทัดจากไฟล์จึงไม่ปรากฏบนหน้าจอ ดังนั้นเพื่อให้ทุกอย่างชัดเจน C++ จึงจัดให้มีฟังก์ชันดังกล่าว - is_open() ซึ่งส่งคืนค่าจำนวนเต็ม: 1 - หากเปิดไฟล์ได้สำเร็จ 0 - หากเปิดไฟล์ไม่ได้ มาแก้ไขโปรแกรมด้วยการเปิดไฟล์ เพื่อว่าถ้าไฟล์นั้นไม่ได้เปิดอยู่ ข้อความที่เกี่ยวข้องก็จะปรากฏขึ้น

// file_read.cpp: กำหนดจุดเริ่มต้นสำหรับแอปพลิเคชันคอนโซล #รวม "stdafx.h" #รวม #รวม ใช้เนมสเปซมาตรฐาน; int main(int argc, char* argv) ( setlocale(LC_ALL, "rus"); // แก้ไขการแสดง Cyrillic char buff; // บัฟเฟอร์สำหรับการจัดเก็บข้อความระดับกลางที่อ่านจากไฟล์ ifstream fin("cppstudio.doc") ; // ( คุณป้อนชื่อไฟล์ที่ไม่ถูกต้อง) ถ้า (!fin.is_open()) // ถ้าไฟล์ไม่ได้เปิดอยู่<< "Файл не может быть открыт!\n"; // сообщить об этом else { fin >>หนัง; // นับคำแรกจากไฟล์ cout<< buff << endl; // напечатали это слово fin.getline(buff, 50); // считали строку из файла fin.close(); // закрываем файл cout << buff << endl; // напечатали эту строку } system("pause"); return 0; }

ผลลัพธ์ของโปรแกรมแสดงในรูปที่ 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++ และเขียนลงในไฟล์ ข้อมูลจำเพาะ:

  1. จำนวนไบต์ที่จัดสรรให้กับชนิดข้อมูล
  2. ค่าสูงสุดที่ชนิดข้อมูลใดประเภทหนึ่งสามารถจัดเก็บได้

การเขียนไฟล์ควรทำในรูปแบบต่อไปนี้:

/* ประเภทข้อมูลไบต์ค่าสูงสุด 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" #รวม #รวม // ทำงานกับไฟล์ #include // เครื่องมือจัดการอินพุต/เอาท์พุตโดยใช้เนมสเปซ std; int main(int argc, char* argv) ( setlocale(LC_ALL, "rus"); // เชื่อมโยงวัตถุกับไฟล์และเปิดไฟล์ในโหมดเขียน ขั้นแรกให้ลบข้อมูลทั้งหมดออกจากมัน ofstream fout("data_types.txt ", ios_base::out | ios_base::trunc); if (!fout.is_open()) // หากไฟล์ไม่ได้ถูกเปิด ( cout<< "Файл не может быть открыт или создан\n"; // напечатать соответствующее сообщение return 1; // выполнить выход из программы } fout << " data type " << "byte" << " " << " max value "<< endl // ส่วนหัวของคอลัมน์ <<"bool = " << sizeof(bool) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных bool*/ << (pow(2,sizeof(bool) * 8.0) - 1) << endl << "char = " << sizeof(char) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных char*/ << (pow(2,sizeof(char) * 8.0) - 1) << endl << "short int = " << sizeof(short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных short int*/ << (pow(2,sizeof(short int) * 8.0 - 1) - 1) << endl << "unsigned short int = " << sizeof(unsigned short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned short int*/ << (pow(2,sizeof(unsigned short int) * 8.0) - 1) << endl << "int = " << sizeof(int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных int*/ << (pow(2,sizeof(int) * 8.0 - 1) - 1) << endl << "unsigned int = " << sizeof(unsigned int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned int*/ << (pow(2,sizeof(unsigned int) * 8.0) - 1) << endl << "long int = " << sizeof(long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных long int*/ << (pow(2,sizeof(long int) * 8.0 - 1) - 1) << endl << "unsigned long int = " << sizeof(unsigned long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных undigned long int*/ << (pow(2,sizeof(unsigned long int) * 8.0) - 1) << endl << "float = " << sizeof(float) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных float*/ << (pow(2,sizeof(float) * 8.0 - 1) - 1) << endl << "long float = " << sizeof(long float) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных long float*/ << (pow(2,sizeof(long float) * 8.0 - 1) - 1) << endl << "double = " << sizeof(double) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных double*/ << (pow(2,sizeof(double) * 8.0 - 1) - 1) << endl; fout.close(); // программа больше не использует файл, поэтому его нужно закрыть cout << "Данные успешно записаны в файл data_types.txt\n"; system("pause"); return 0; }

เป็นไปไม่ได้เลยที่จะไม่สังเกตว่าการเปลี่ยนแปลงในโปรแกรมมีเพียงเล็กน้อย และต้องขอบคุณความจริงที่ว่าอินพุต/เอาท์พุตมาตรฐานและอินพุต/เอาท์พุตของไฟล์ถูกใช้ในลักษณะเดียวกันทุกประการ ท้ายโปรแกรมเวลา.บรรทัดที่ 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 ลงไป

#รวม #รวม #รวม ถือเป็นโมฆะ main() ( //ใช้ตัวแปรไฟล์ เราจะเข้าถึงไฟล์ FILE *file; //เปิดไฟล์ข้อความที่มีสิทธิ์ในการเขียน file = fopen("C:/c/test.txt", "w+t") ; // เขียนไปที่ไฟล์ fprintf (ไฟล์ "Hello, World!"); // ปิดไฟล์ fclose (ไฟล์);

ฟังก์ชัน fopen จะจัดสรรหน่วยความจำให้กับอ็อบเจ็กต์เอง การทำความสะอาดจะดำเนินการโดยฟังก์ชัน fclose จำเป็นต้องปิดไฟล์ แต่จะไม่ปิดเอง

ฟังก์ชั่น fopen สามารถเปิดไฟล์ในโหมดข้อความหรือไบนารี ค่าเริ่มต้นคือข้อความ โหมดการเข้าถึงอาจเป็นดังนี้

ตัวเลือกการเข้าถึงไฟล์
พิมพ์ คำอธิบาย
การอ่าน. ไฟล์จะต้องมีอยู่
เขียนไฟล์ใหม่ หากมีไฟล์ชื่อเดียวกันนี้อยู่แล้ว เนื้อหาจะหายไป
เขียนที่ส่วนท้ายของไฟล์ การดำเนินการกำหนดตำแหน่ง (fseek, fsetpos, frewind) จะถูกละเว้น ไฟล์จะถูกสร้างขึ้นหากไม่มีอยู่
ร+ กำลังอ่านและอัพเดตครับ คุณสามารถอ่านและเขียนได้ ไฟล์จะต้องมีอยู่
มี+ การบันทึกและการอัปเดต ไฟล์ใหม่จะถูกสร้างขึ้น หากมีไฟล์ชื่อเดียวกันนี้อยู่แล้ว เนื้อหาจะหายไป คุณสามารถเขียนและอ่านได้
เอ+ จบการโพสต์และอัพเดต การดำเนินการกำหนดตำแหน่งเป็นแบบอ่านอย่างเดียวและละเว้นสำหรับการเขียน หากไม่มีไฟล์อยู่ ไฟล์ใหม่จะถูกสร้างขึ้น

หากจำเป็นต้องเปิดไฟล์ในโหมดไบนารี ตัวอักษร b จะถูกเพิ่มที่ท้ายบรรทัด เช่น "rb", "wb", "ab" หรือสำหรับโหมดผสม "ab+", " wb+”, “ab+” แทนที่จะเป็น b คุณสามารถเพิ่มตัวอักษร t จากนั้นไฟล์จะเปิดในโหมดข้อความ ขึ้นอยู่กับการดำเนินการ ในมาตรฐาน C ใหม่ (2011) ตัวอักษร x หมายความว่า fopen ควรล้มเหลวหากไฟล์มีอยู่แล้ว มาเสริมโปรแกรมเก่าของเรา: เปิดไฟล์อีกครั้งและพิจารณาสิ่งที่เราเขียนไว้ที่นั่น

#รวม #รวม #รวม เป็นโมฆะ main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); fclose(file); file = fopen("C:/c/test.txt", "r"); fgets(บัฟเฟอร์, 127, ไฟล์); printf("%s", บัฟเฟอร์(ไฟล์);

แทนที่จะใช้ฟังก์ชัน fgets คุณสามารถใช้ fscanf ได้ แต่คุณต้องจำไว้ว่ามันสามารถอ่านบรรทัดได้จนถึงช่องว่างแรกเท่านั้น
fscanf(ไฟล์, "%127s", บัฟเฟอร์);

นอกจากนี้ แทนที่จะเปิดและปิดไฟล์ คุณสามารถใช้ฟังก์ชัน freopen ซึ่งจะ "เปิดใหม่" ไฟล์ด้วยสิทธิ์การเข้าถึงใหม่

#รวม #รวม #รวม เป็นโมฆะ main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); freopen("C:/ c/test.txt", "r", ไฟล์); fgets(บัฟเฟอร์, 127, ไฟล์); printf("%s", บัฟเฟอร์); fclose(ไฟล์); getch(); )

ฟังก์ชัน fprintf และ fscanf แตกต่างจาก printf และ scanf เพียงตรงที่ฟังก์ชันเหล่านี้ใช้เป็นอาร์กิวเมนต์แรกเป็นตัวชี้ไปยัง FILE ที่จะส่งออกหรืออ่านข้อมูล ควรเพิ่มทันทีว่าฟังก์ชัน printf และ scanf สามารถแทนที่ได้อย่างง่ายดายด้วยฟังก์ชัน fprintf และ fscanf ในระบบปฏิบัติการ (เรากำลังพิจารณาระบบปฏิบัติการที่ใช้กันทั่วไปและเหมาะสมที่สุด) มีสตรีมมาตรฐานสามรายการ: stdout สตรีมเอาต์พุตมาตรฐาน, stdin สตรีมอินพุตมาตรฐาน และ stderr สตรีมเอาต์พุตข้อผิดพลาดมาตรฐาน stderr สิ่งเหล่านี้จะเปิดขึ้นโดยอัตโนมัติเมื่อมีการเปิดตัวแอปพลิเคชันและเชื่อมโยงกับคอนโซล ตัวอย่าง

#รวม #รวม #รวม เป็นโมฆะ main() ( int a, b; fprintf(stdout, "ใส่ตัวเลขสองตัว\n"); fscanf(stdin, "%d", &a); fscanf(stdin, "%d", &b); if (b == 0) ( fprintf(stderr, "ข้อผิดพลาด: หารด้วยศูนย์"); ) else ( fprintf(stdout, "%.3f", (float) a / (float) b); ) getch();

เกิดข้อผิดพลาดในการเปิดไฟล์

หากการเรียกใช้ฟังก์ชัน fopen ล้มเหลว ก็จะส่งกลับค่า NULL ข้อผิดพลาดในการทำงานกับไฟล์เกิดขึ้นค่อนข้างบ่อย ดังนั้นทุกครั้งที่เปิดไฟล์เราจึงต้องตรวจสอบผลงาน

#รวม #รวม #รวม #define ERROR_OPEN_FILE -3 void main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); if (file == NULL) ( printf("เกิดข้อผิดพลาดในการเปิด file"); getch(); exit(ERROR_OPEN_FILE); ) fprintf(file, "Hello, World!"); freopen("C:/c/test.txt", "r", file); ถ้า (file = = NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์"); getch(); exit(ERROR_OPEN_FILE); ) fgets(buffer, 127, file); printf("%s", buffer(file); ; )

ปัญหาเกิดขึ้นเมื่อเปิดไฟล์หลายไฟล์พร้อมกัน: หากไม่สามารถเปิดไฟล์ใดไฟล์หนึ่งได้ จะต้องปิดไฟล์ที่เหลือด้วย

ไฟล์ *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) เป็นต้น
  • การบัฟเฟอร์ข้อมูล

ตามที่กล่าวไว้ข้างต้น เมื่อเราส่งออกข้อมูล ข้อมูลนั้นจะถูกวางไว้ในบัฟเฟอร์ก่อน บัฟเฟอร์ถูกล้างแล้ว

#รวม #รวม #รวม 1) หากเต็มแล้ว

2) หากสตรีมถูกปิด

3) หากเราระบุอย่างชัดเจนว่าจำเป็นต้องล้างบัฟเฟอร์ (มีข้อยกเว้นที่นี่ด้วย :))

4) เคลียร์ด้วยหากโปรแกรมเสร็จสมบูรณ์ ในเวลาเดียวกัน ไฟล์ทั้งหมดจะถูกปิด ในกรณีที่เกิดข้อผิดพลาดรันไทม์ สิ่งนี้อาจไม่เกิดขึ้น

คุณสามารถบังคับให้บัฟเฟอร์ขนถ่ายได้โดยการเรียกใช้ฟังก์ชัน fflush(File *) ลองดูสองตัวอย่าง - แบบมีและไม่มีการทำความสะอาด

Int setvbuf (สตรีม FILE *, ถ่าน * บัฟเฟอร์, โหมด int, ขนาด size_t);

ซึ่งรับบัฟเฟอร์ที่มีขนาดตามใจชอบ โหมดสามารถรับค่าต่อไปนี้

  • _IOFBF- บัฟเฟอร์เต็ม ข้อมูลจะถูกเขียนลงในไฟล์เมื่อเต็ม ในการอ่าน บัฟเฟอร์จะถือว่าเต็มเมื่อมีการร้องขอการดำเนินการอินพุตและบัฟเฟอร์ว่างเปล่า
  • _IOLBF- การบัฟเฟอร์เชิงเส้น ข้อมูลจะถูกเขียนลงในไฟล์เมื่อเต็มหรือเมื่อพบอักขระขึ้นบรรทัดใหม่ เมื่ออ่าน บัฟเฟอร์จะถูกเติมลงในอักขระขึ้นบรรทัดใหม่เมื่อมีการร้องขอการดำเนินการอินพุตและบัฟเฟอร์ว่างเปล่า
  • _IONBF– ไม่มีการบัฟเฟอร์ ในกรณีนี้ พารามิเตอร์ขนาดและบัฟเฟอร์จะถูกละเว้น
หากสำเร็จ ฟังก์ชันจะส่งกลับ 0

ตัวอย่าง: มาตั้งค่าบัฟเฟอร์ของเราเองแล้วดูว่าอ่านจากไฟล์อย่างไร ปล่อยให้ไฟล์สั้น (เช่น Hello, World!) แล้วเราจะอ่านมันทีละตัวอักษร

#รวม #รวม #รวม เป็นโมฆะ main() ( FILE *input = NULL; char c; char buffer = (0); input = fopen("D:/c/text.txt", "rt"); setbuf (อินพุต, บัฟเฟอร์); ในขณะที่ ( !feof(input)) ( c = fgetc(input); printf("%c\n", c); printf("%s\n", buffer); _getch(); ) fclose(input )

จะเห็นได้ว่าข้อมูลอยู่ในบัฟเฟอร์แล้ว การอ่านอักขระทีละอักขระเสร็จสิ้นจากบัฟเฟอร์

ฟีฟ

ฟังก์ชั่น int feof (FILE * สตรีม); คืนค่าเป็นจริงหากถึงจุดสิ้นสุดของไฟล์ ฟังก์ชั่นนี้สะดวกในการใช้งานเมื่อคุณต้องการอ่านไฟล์ทั้งหมดตั้งแต่ต้นจนจบ ให้มีไฟล์ที่มีเนื้อหาข้อความ text.txt เราอ่านอักขระไฟล์ทีละอักขระและแสดงบนหน้าจอ

#รวม #รวม #รวม ถือเป็นโมฆะ main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("เกิดข้อผิดพลาดในการเปิดไฟล์") ; _getch(); exit(0); while (!feof(input)) ( c = fgetc()); fprintf(stdout, "%c", c); ) fclose(อินพุต());

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

#รวม #รวม #รวม ถือเป็นโมฆะ main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("เกิดข้อผิดพลาดในการเปิดไฟล์") ; _getch(); exit(0); while (!feof(input)) ( fscanf(input, "%c", &c); fprintf(stdout, "%c", c); ) fclose(อินพุต); ();

ตัวอย่างนี้จะล้มเหลว (เป็นไปได้มากที่สุด) และพิมพ์อักขระตัวสุดท้ายของไฟล์สองครั้ง

วิธีแก้ไขคืออย่าใช้ feof ตัวอย่างเช่นจัดเก็บจำนวนบันทึกทั้งหมดหรือใช้ข้อเท็จจริงที่ว่าฟังก์ชัน fscanf ฯลฯ มักจะส่งคืนจำนวนค่าที่อ่านและจับคู่อย่างถูกต้อง

#รวม #รวม #รวม ถือเป็นโมฆะ main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("เกิดข้อผิดพลาดในการเปิดไฟล์") ; _getch(); exit(0); ในขณะที่ (fscanf(input, "%c", &c) == 1) ( fprintf(stdout, "%c", c); ) fclose(input);

ตัวอย่าง

1. ไฟล์หนึ่งประกอบด้วยตัวเลขสองตัว - ขนาดของอาร์เรย์ ลองเติมไฟล์ที่สองด้วยอาร์เรย์ของตัวเลขสุ่ม

#รวม #รวม #รวม #รวม // ชื่อไฟล์และการอนุญาต #define INPUT_FILE "D:/c/input.txt" #define OUTPUT_FILE "D:/c/output.txt" #define READ_ONLY "r" #define WRITE_ONLY "w" // ค่าสูงสุดสำหรับอาร์เรย์ ขนาด #define MAX_DIMENSION 100 //เกิดข้อผิดพลาดเมื่อเปิดไฟล์ #define ERROR_OPEN_FILE -3 void main() ( FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if ( inputFile == NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์ %s", INPUT_FILE); getch(); exit(ERROR_OPEN_FILE); ) outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) ( printf("Error กำลังเปิดไฟล์ %s", OUTPUT_FILE); getch(); //หากสามารถเปิดไฟล์เพื่ออ่านได้ จะต้องปิดมันหาก (inputFile != NULL) ( fclose(inputFile); ) exit(ERROR_OPEN_FILE); ) fscanf (inputFile, "%ud %ud", &m, &n); if (m > MAX_DIMENSION) ( m = MAX_DIMENSION; ) ถ้า (n > MAX_DIMENSION) ( n = MAX_DIMENSION; ) srand(time(NULL));< n; i++) { for (j = 0; j < m; j++) { fprintf(outputFile, "%8d ", rand()); } fprintf(outputFile, "\n"); } //Закрываем файлы fclose(inputFile); fclose(outputFile); }

2. ผู้ใช้คัดลอกไฟล์ และเลือกโหมดการทำงานก่อน: ไฟล์สามารถส่งออกไปยังคอนโซลหรือคัดลอกไปยังไฟล์ใหม่ได้

#รวม #รวม #รวม #define ERROR_FILE_OPEN -3 void main() ( FILE *origin = NULL; FILE *output = NULL; char filename; int mode; printf("ป้อนชื่อไฟล์: "); scanf("%1023s", ชื่อไฟล์); origin = fopen (ชื่อไฟล์ "r"); if (origin == NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์ %s", ชื่อไฟล์); getch(); exit(ERROR_FILE_OPEN); ) printf("enter mode: "); d", &mode); if (mode == 1) ( printf("Enter filename: "); scanf("%1023s", filename); output = fopen(ชื่อไฟล์, "w"); if (output = = NULL ) ( printf("ข้อผิดพลาดในการเปิดไฟล์ %s", ชื่อไฟล์); getch(); fclose(origin); exit(ERROR_FILE_OPEN); ) ) else ( output = stdout; ) while (!feof(origin)) ( fprintf (output , "%c", fgetc(ต้นทาง)); fclose(ต้นทาง);

3. ผู้ใช้ป้อนข้อมูลจากคอนโซลและเขียนลงในไฟล์จนกว่าจะกดปุ่ม esc ตรวจสอบโปรแกรมและดู มันจะทำงานอย่างไรหากคุณป้อน backspace: สิ่งที่ส่งออกไปยังไฟล์และสิ่งที่ส่งออกไปยังคอนโซล

#รวม #รวม #รวม #define ERROR_FILE_OPEN -3 void main() ( FILE *output = NULL; char c; output = fopen("D:/c/test_output.txt", "w+t"); if (output == NULL) ( printf ("เกิดข้อผิดพลาดในการเปิดไฟล์"); _getch(); exit(ERROR_FILE_OPEN); for (;;) ( c = _getch(); if (c == 27) ( break; ) fputc(c, output); fputc( c , stdout);

4. ไฟล์มีจำนวนเต็ม ค้นหาค่าสูงสุดของพวกเขา เรามาใช้ประโยชน์จากข้อเท็จจริงที่ว่าฟังก์ชัน fscanf ส่งคืนจำนวนอ็อบเจ็กต์ที่อ่านและจับคู่อย่างถูกต้อง ควรคืนหมายเลข 1 ทุกครั้ง

#รวม #รวม #รวม #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์"); _getch(); exit(ERROR_FILE_OPEN); ) maxn = INT_MIN; hasRead = 1; while (hasRead == 1) ( hasRead = fscanf(input, "%d", &num); if (hasRead != 1) ( Continue; ) if (num >

อีกวิธีหนึ่งคืออ่านตัวเลขจนกระทั่งถึงจุดสิ้นสุดของไฟล์

#รวม #รวม #รวม #รวม #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์"); _getch(); exit(ERROR_FILE_OPEN); ) maxn = INT_MIN; while (!feof(input)) ( fscanf(input, "%d", &num); if (num > maxn ) ( maxn = num; ) ) printf("จำนวนสูงสุด = %d", maxn);

5. ไฟล์ประกอบด้วยคำ: คำภาษารัสเซีย, ตาราง, คำภาษาอังกฤษ, ในหลายแถว ผู้ใช้ป้อนคำภาษาอังกฤษจำเป็นต้องส่งออกคำภาษารัสเซีย

ไฟล์การแปลจะมีลักษณะเช่นนี้

ดวงอาทิตย์
ปากกาดินสอ
ดินสอปากกาลูกลื่น
ประตูประตู
หน้าต่าง หน้าต่าง
เก้าอี้ เก้าอี้
เก้าอี้นวม

และบันทึกไว้ในการเข้ารหัส cp866 (OEM 866) สิ่งสำคัญคือ คำคู่สุดท้ายจะลงท้ายด้วยการขึ้นบรรทัดใหม่ด้วย

อัลกอริทึมมีดังนี้: เราอ่านบรรทัดจากไฟล์, ค้นหาเครื่องหมายแท็บในบรรทัด, แทนที่เครื่องหมายแท็บด้วยศูนย์, คัดลอกคำภาษารัสเซียจากบัฟเฟอร์, คัดลอกคำภาษาอังกฤษจากบัฟเฟอร์, ตรวจสอบความเท่าเทียมกัน

#รวม #รวม #รวม #รวม #define ERROR_FILE_OPEN -3 โมฆะ main() ( FILE *input = NULL; char buffer; char enWord; char ruWord; char usrWord; ดัชนีที่ไม่ได้ลงนาม; int length; int wasFound; input = fopen("D:/c/input.txt ", "r"); if (input == NULL) ( printf("ข้อผิดพลาดในการเปิดไฟล์"); _getch(); exit(ERROR_FILE_OPEN); ) printf("enter word: "); fgets(usrWord, 127, stdin ); wasFound = 0; while (!feof(input)) ( fgets(buffer, 511, input); length = strlen(buffer); for (ดัชนี = 0; ดัชนี< length; index++) { if (buffer == "\t") { buffer = "\0"; break; } } strcpy(ruWord, buffer); strcpy(enWord, &buffer); if (!strcmp(enWord, usrWord)) { wasFound = 1; break; } } if (wasFound) { printf("%s", ruWord); } else { printf("Word not found"); } fclose(input); _getch(); }

6. นับจำนวนบรรทัดในไฟล์ เราจะอ่านอักขระไฟล์ทีละอักขระ โดยนับจำนวนอักขระ "\n" จนกว่าเราจะพบอักขระ EOF EOF เป็นอักขระพิเศษที่ระบุว่าอินพุตเสร็จสมบูรณ์แล้ว และไม่มีข้อมูลให้อ่านอีก ฟังก์ชันจะส่งกลับค่าลบในกรณีที่เกิดข้อผิดพลาด
หมายเหตุ: EOF เป็นประเภท int ดังนั้นคุณต้องใช้ int เพื่ออ่านอักขระ นอกจากนี้ ค่าของ EOF ไม่ได้ถูกกำหนดโดยมาตรฐาน

#define _CRT_SECURE_NO_WARNINGS #รวม #รวม #รวม int cntLines(const char *filename) ( int lines = 0; int any; //any เป็นประเภท int เพราะ EOF เป็นประเภท int! FILE *f = fopen(filename, "r"); if (f == NULL ) ( return -1; ) do ( any = fgetc(f); //printf("%c", any);//debug if (any == "\n") ( lines++; ) ) while(any ! = EOF); ​​​​fclose(f); return lines; ) เป็นโมฆะ main() ( printf("%d\n", cntLines("C:/c/file.txt")); _getch(); )

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()) ด้วยเหตุผลที่กล่าวถึงใน

#รวม #รวม ใช้เนมสเปซมาตรฐาน; int main() ( ไฟล์ ofstream; file.open("test.txt",ios::out|ios::app); if (!file) ( ศาล<< "File error - can"t open to write data!"; cin.sync(); cin.get(); return 1; } for (int i=0; i<10; i++) file << i << endl; file.close(); ifstream file2; file2.open("test.txt", ios::in); if (!file2) { cout << "File error - can"t open to read data!"; cin.sync(); cin.get(); return 2; } int a,k=0; while (1) { file2 >>ก;<< a << " "; k++; } cout << endl << "K=" << k << endl; file2.close(); cin.sync(); cin.get(); return 0; }

ถ้า (file2.eof()) พัง;

#รวม #รวม ศาล<< str << endl; // вывод прочитанной строки на экран cin.sync(); cin.get(); return 0; }

รหัสนี้ภายใต้ระบบปฏิบัติการ 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 * อย่างชัดเจน พารามิเตอร์ที่สองระบุว่าบล็อกไบนารีของไฟล์มีขนาดไบต์คงที่โดยไม่คำนึงถึงความยาวบันทึกจริง แอปพลิเคชันต่อไปนี้เป็นตัวอย่างของการสร้างและการแสดงข้อมูลในสมุดบันทึกอย่างง่าย รายการไฟล์จะถูกอ่านตามลำดับและแสดงบนคอนโซล

#รวม #รวม #รวม ใช้เนมสเปซมาตรฐาน; struct Notes ( // ชื่อโครงสร้างข้อมูลสมุดบันทึก char; // ชื่อเต็ม char Phone; // phone int Age; // age ); int main() ( setlocale(LC_ALL, "Russian"); Notes Note1= ("Ioann Vasilyevich แย่มาก", "ไม่ได้ติดตั้ง", 60 ); Notes Note2= ("Godunov Boris Fedorovich", "095-111-2233" , 30 ); หมายเหตุ Note3= ("Romanov Petr Mikhailovich", "812-333-2211", 20 ); ofstream ofile("Notebook.dat", ios::binary); ofile.write((char*)&Note1, sizeof (หมายเหตุ)); // บล็อกที่ 1 ofile.write((char*)&Note2, sizeof(Notes)); // บล็อกที่ 2 ofile.write((char*)&Note3, sizeof(Notes)); .close(); // ปิดไฟล์ที่บันทึกไว้ ifstream ifile("Notebook.dat", ios::binary); // ตัวแปรที่มีโครงสร้าง str; // บัฟเฟอร์สตริงแบบคงที่ // อ่านและแสดงบรรทัดในลูปจนกระทั่ง eof (!ifile.read((char*)&Note, sizeof(Notes)).eof()) ( sprintf(str, "%s\tPhone: %s\tAge: %d" , Note.Name, Note.Phone, หมายเหตุอายุ);<< str << endl; } ifile.close(); // закрыть прочитанный файл cin.sync(); cin.get(); return 0; }

ผลจากการรันโค้ดนี้ ทำให้ไฟล์ไบนารี 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

#รวม #รวม #รวม ใช้เนมสเปซมาตรฐาน; struct หมายเหตุ (ชื่อถ่าน; ถ่านโทรศัพท์; อายุ int; ); int main() ( setlocale(LC_ALL, "Russian"); Notes Note1, Note3; // เปิดไฟล์เพื่ออ่าน/เขียนพร้อมกัน ไฟล์ fstream("Notebook.dat", ios::binary | ios::in | ios: : out); file.seekg(2 * sizeof(Notes)); // ค้นหาและอ่าน Note3 file.read((char*)&Note3, sizeof(Notes)); // ค้นหาและอ่าน Note1 file.read((char *)&Note1, ขนาดของ(หมายเหตุ)); file.seekg(0);<== Note3 file.write((char*)&Note3, sizeof(Notes)); file.seekg(2 * sizeof(Notes)); // Note3 <== Note1 file.write((char*)&Note1, sizeof(Notes)); char str; // Считывать и отображать записи в цикле, пока не eof file.seekg(0); // вернуться к началу файла while (!file.read((char*)&Note1, sizeof(Notes)).eof()) { sprintf(str, "%s\tТел: %s\tВозраст: %d", Note1.Name, Note1.Phone, Note1.Age); cout << str << endl; } file.close(); cin.sync(); cin.get(); return 0; }

ในตัวสร้างของออบเจ็กต์ไฟล์ คุณต้องระบุแฟล็ก ios::in และ ios::out เพื่อให้สามารถอ่านและเขียนพร้อมกันได้ ผลจากการรันโค้ดนี้ รายการแรกและรายการที่สามในไฟล์ไบนารี Notebook.dat จะถูกสลับ

มีตัวอย่างเพิ่มเติมในหัวข้อนี้