Dosya G/Ç'nin C++'daki çalışması, normal G/Ç'ninkiyle hemen hemen aynıdır (ancak birkaç nüansla).
Dosya G/Ç Sınıfları
Var C++'da üç ana dosya G/Ç sınıfı:
akış dışı(sınıfın çocuğudur);
fstream(iostream sınıfının bir çocuğudur).
Bu sınıflar ile tek yönlü dosya girişi, tek yönlü dosya çıkışı ve çift yönlü dosya G/Ç işlemlerini gerçekleştirebilirsiniz. Bunları kullanmak için fstream'e bağlanmanız yeterlidir.
Hemen kullanılabilen cout, cin, cerr ve clog akışlarının aksine, dosya akışları programcı tarafından açıkça ayarlanmalıdır. Yani, bir dosyayı okumak ve/veya yazmak üzere açmak için, dosya adını parametre olarak belirterek uygun dosya I/O sınıfından bir nesne oluşturmanız gerekir. Ardından, ekleme operatörlerini kullanarak (<<) или извлечения (>>), bir dosyaya veri yazabilir veya bir dosyanın içeriğini okuyabilirsiniz. Bundan sonra, son - dosyayı kapatmanız gerekir: açıkça arayın kapat() yöntemi veya sadece dosya G/Ç değişkeninin kapsam dışına çıkmasına izin verin (dosya G/Ç sınıfı o dosyayı bizim için otomatik olarak kapatacaktır).
Dosya çıktısı
ofstream sınıfı bir dosyaya yazmak için kullanılır. Örneğin:
#Dahil etmek
#Dahil etmek #Dahil etmek #Dahil etmek int ana() ad alanı std kullanarak; // ofstream dosyaya veri yazmak için kullanılır // SomeText.txt dosyası oluştur ofstream outf("SomeText.txt" ) ; // Veri yazmak için bu dosyayı açamazsak if(!outf) // Ardından bir hata mesajı yazdırın ve exit()'i yürütün sertifika<< << endl ; çıkış(1) ; // Dosyaya aşağıdaki iki satırı yazın çıkış<< "See line #1!" << endl ; çıkış<< "See line #2!" << endl ; 0 döndür; // outf kapsam dışına çıktığında, ofstream sınıfının yıkıcısı dosyamızı otomatik olarak kapatacaktır. |
Proje dizininize bakarsanız ( Visual Studio'da .cpp dosyanızın adını içeren sekmedeki RMB > "Dosyayı içeren klasörü açınız"), aşağıdaki satırları içeren SomeText.txt adlı bir dosya göreceksiniz:
1. satıra bakın!
2. satıra bakın!
Ayrıca kullanabileceğimizi lütfen unutmayın put() yöntemi bir dosyaya bir karakter yazmak için.
Dosya girişi
#Dahil etmek
#Dahil etmek #Dahil etmek #Dahil etmek #Dahil etmek int ana() ad alanı std kullanarak; // ifstream dosyanın içeriğini okumak için kullanılır // İçeriğini okumak için bu dosyayı açamazsak eğer(!inf) // Ardından aşağıdaki hata mesajını yazdırın ve exit()'i yürütün sertifika<< << endl ; çıkış(1) ; // Okuyabileceğimiz veri olduğu sürece süre(inf) // Daha sonra bu verileri bir dizgeye taşırız ve daha sonra ekranda gösteririz. string strInput ; inf >> strInput ; cout<< strInput << endl ; 0 döndür; // inf kapsam dışına çıktığında ifstream sınıfının yıkıcısı dosyamızı otomatik olarak kapatacaktır. |
Görmek
astar
#1!
Görmek
astar
#2!
Hmm, tam olarak istediğimiz bu değildi. Önceki derslerden zaten bildiğimiz gibi, çıkarma operatörü "biçimlendirilmiş veriler" ile çalışır, yani. tüm boşlukları, sekmeleri ve yeni satırları yok sayar. Tüm içeriği olduğu gibi, parçalara ayırmadan okumak için (yukarıdaki örnekte olduğu gibi) kullanmamız gerekir. getline() yöntemi:
#Dahil etmek
#Dahil etmek #Dahil etmek #Dahil etmek #Dahil etmek int ana() ad alanı std kullanarak; // ifstream dosyaların içeriğini okumak için kullanılır ifstream inf("SomeText.txt" ) ; // İçeriğini okumak için dosyayı açamazsak eğer(!inf) // Ardından aşağıdaki hata mesajını yazdırın ve exit()'i yürütün sertifika<< "Ah, SomeText.txt okumak için açılamadı!"<< endl ; çıkış(1) ; süre(inf) string strInput ; getline (inf, strInput); cout<< strInput << endl ; 0 döndür; // inf kapsam dışına çıktığında ifstream sınıfının yıkıcısı dosyamızı otomatik olarak kapatacaktır. |
Yukarıdaki programı çalıştırmanın sonucu:
arabelleğe alınmış çıktı
C++ çıktısı arabelleğe alınabilir. Bu, dosya akışına gönderilen her şeyin hemen diske (belirli bir dosyaya) yazılamadığı anlamına gelir. Bu öncelikle performans nedenleriyle yapılır. Arabellek verileri diske yazıldığında buna denir. arabelleği temizleme. Arabelleği temizlemenin bir yolu dosyayı kapatmaktır. Bu durumda, arabelleğin tüm içeriği diske taşınacak ve ardından dosya kapatılacaktır.
Çıktı arabelleğe alma genellikle bir sorun değildir, ancak belirli koşullar altında dikkatsiz yeni başlayanlar için sorunlara neden olabilir. Örneğin, veriler arabellekte depolandığında ve program yürütmesini zamanından önce sonlandırdığında (ya bir çökmenin sonucu olarak ya da . Bu gibi durumlarda, dosya G/Ç sınıfı yıkıcılar yürütülmez, dosyalar asla kapatılmaz, arabellekler boşaltılmaz ve verilerimiz sonsuza kadar kaybolur. Bu nedenle, çıkış()'ı çağırmadan önce tüm açık dosyaları açıkça kapatmak iyi bir fikirdir.
Ayrıca kullanarak arabelleği manuel olarak da temizleyebilirsiniz. ostream::flush() yöntemi veya göndererek standart::gömmeçıkış akışına. Bu yöntemlerden herhangi biri, bir program çökmesi durumunda arabellek içeriğinin hemen diske yazılmasını sağlamak için yararlı olabilir.
ilginç bir nüans: Çünkü std::endl; ayrıca çıktı akışını temizler, ardından aşırı kullanılması (gereksiz arabellek temizlemelerine neden olur) program performansını etkileyebilir (çünkü arabellek temizleme bazı durumlarda pahalı olabilir). Bu nedenle, performans bilincine sahip programcılar, gereksiz arabellek temizlemesini önlemek için çıktı akışına yeni satır karakteri eklemek için genellikle std::endl yerine \n kullanır.
Dosya açma modları
Zaten var olan bir dosyaya veri yazmaya çalışırsak ne olur? Yukarıdaki programı yeniden çalıştırmak (ilk olanı), programı yeniden çalıştırdığınızda orijinal dosyanın tamamen üzerine yazıldığını gösterir. Peki ya dosyanın sonuna veri eklememiz gerekirse? Dosya akışının, programcıya dosyayı nasıl açacağını söylemenize izin veren isteğe bağlı ikinci bir parametre aldığı ortaya çıktı. Bu parametre olarak, geçebilirsiniz aşağıdaki bayraklar(kiler ios sınıfındadır):
uygulama- dosyayı ekleme modunda açar;
yemek yedi- okuma/yazma işleminden önce dosyanın sonuna gider;
ikili- dosyayı ikili modda açar (metin modu yerine);
içinde- dosyayı okuma modunda açar (ifstream için varsayılan);
dışarı- dosyayı yazma modunda açar (akış için varsayılan);
gövde- zaten varsa dosyayı siler.
kullanarak aynı anda birden çok bayrak belirtebilirsiniz.
ifstream varsayılan olarak ios::in modunda çalışır;
ofstream varsayılan olarak ios::out modunda çalışır;
fstream varsayılan olarak ios::in VEYA ios::out modunda çalışır; bu, bir dosyanın içeriğini okuyabileceğiniz veya bir dosyaya veri yazabileceğiniz anlamına gelir.
Şimdi daha önce oluşturulan SomeText.txt dosyasına iki satır ekleyecek bir program yazalım:
#Dahil etmek
#Dahil etmek #Dahil etmek #Dahil etmek int ana() ad alanı std kullanarak; // fstream'e verilerimizi dosyanın zaten var olan verilerine ekleyeceğimizi söylemek için ios:app bayrağını iletmek, // dosyanın üzerine yazmayacağız. ios::out bayrağını geçmemize gerek yok, // çünkü akış varsayılanı ios::out modudur ofstream outf("SomeText.txt" , ios::app ) ; // Veri yazmak için dosyayı açamazsak if(!outf) // Ardından aşağıdaki hata mesajını yazdırın ve exit()'i yürütün sertifika<< "Ah, SomeText.txt yazmak için açılamadı!"<< endl ; çıkış(1) ; |
tarafından geliştirilen G/Ç mekanizması, günümüzde genel kabul görmüş nesne yönelimli programlama stiline tekabül etmemekte, ayrıca modern güvenli kod yürütme ortamlarında potansiyel olarak güvenli olmadığı düşünülen işaretçi işlemlerini aktif olarak kullanmaktadır. Uygulama geliştirme için bir alternatif, C++ dil standardı tarafından sağlanan standart G/Ç sınıfı mekanizmasıdır.
Dosyaları açma
En sık kullanılan sınıflar, okuma için ifstream, yazma için ofstream ve dosyaları değiştirmek için fstream'dir.
Tüm iş parçacıklı G/Ç sınıfları, işlevselliğini tamamen devralan ios ortak atasından dolaylı olarak türetilir. Örneğin, open_mode numaralandırılmış veri üyesi, aşağıdaki gibi tanımlanan dosya açma modunu belirtir:
Enum open_mode (uygulama, ikili, içeri, dışarı, trunc, yedi);
Bayrakların olası değerleri ve amaçları aşağıdadır.
Örneğin, ikili verileri okumak üzere test.txt adlı bir dosyayı açmak için şunu yazarsınız:
ifstream dosyası; file.open("test.txt", ios::in | ios::binary);
Mantıksal VEYA operatörü (|), herhangi bir bayrak kombinasyonuyla bir mod oluşturmanıza olanak tanır. Yazarak bir dosyayı açarken, yanlışlıkla aynı isimli mevcut bir dosyanın üzerine yazmamak için aşağıdaki formu kullanmanız gerekir:
akış dışı dosya; file.open("test.txt", ios::out | ios::app);
Uygun başlık dosyasının projeye bağlı olduğu varsayılır:
#Dahil etmek
Dosyanın başarıyla açılıp açılmadığını kontrol etmek için yapıyı kullanabilirsiniz.
If (!file) ( // Bir dosya açma hatasının işlenmesi )
Dahil Etme ve Çıkarma Operatörleri
Dosya işleme sınıflarında geçersiz kılındı operatörü dahil et (<<) записывает данные в файловый поток. Как только вы открыли файл для записи, можно записывать в него текстовую строку целиком:
dosya<< "Это строка текста";
Parçalar halinde bir metin dizesi de yazabilirsiniz:
dosya<< "Это " << "строка " << "текста";
endl ifadesi satır girişini bir satır başı ile bitirir:
dosya<< "Это строка текста" << endl;
Dahil etme operatörünü kullanarak, değişkenlerin veya dizi öğelerinin değerlerini bir dosyaya yazmak kolaydır:
Akış dosyası ("Temp.txt"); char buff = "Metin dizisi değişkenler içeriyor"; int vx = 100; kayan nokta pi = 3.14159; dosya<< buff << endl << vx << endl << pi << endl;
Kod yürütmenin bir sonucu olarak, Temp.txt metin dosyasının üç satırı oluşturulur:
Metin dizisi değişkenler içeriyor 100 3.14159
Sayısal değerlerin dosyaya ikili değerler olarak değil metin dizeleri olarak yazıldığını unutmayın.
çıkarma operatörü(>>) tersini yapar. Daha önce yazılmış Temp.txt dosyasından karakterleri çıkarmak için aşağıdaki gibi bir kod yazmanız gerekiyor gibi görünüyor:
ifstream dosyası ("Temp.txt"); karakter tutkunu; intvx; floatpi; dosya >> buff >> vx >> pi;
Ancak çıkarma operatörü karşılaştığı ilk sınırlayıcıda (boşluk, sekme veya yeni satır) duracaktır. Böylece, "Metin dizisi değişkenler içerir" cümlesini ayrıştırırken, dizi buff'ına sadece "Metin" kelimesi yazılacak, boşluk yok sayılacak ve "dizi" kelimesi, vx tamsayı değişkeninin ve kodun değeri olacaktır. yürütme, veri yapısının kaçınılmaz bir ihlali ile "çarpık" olacaktır. Daha sonra, ifstream sınıfını tartışırken, önceki örnekten dosya okumasının nasıl doğru bir şekilde düzenleneceğini göstereceğiz.
ifstream sınıfı: dosyaları okuma
Adından da anlaşılacağı gibi, ifstream sınıfı bir dosya akışını girmek için tasarlanmıştır. Sınıfın ana yöntemleri aşağıda listelenmiştir. Çoğu, istream sınıfından miras alınır ve üst işlevlerle aşırı yüklenir. Örneğin, call parametresine bağlı olarak get işlevi yalnızca tek bir karakteri değil, aynı zamanda bir karakter bloğunu da okuyabilir.
Şimdi, veri çıkarma operatörünü kullanmanın beklenen sonucu vermesi için önceki örneği nasıl değiştirmeniz gerektiği açıktır:
ifstream dosyası ("Temp.txt"); karakter tutkunu; intvx; floatpi; file.getline(buff, sizeof(buff)); dosya >> vx >> pi:
getline yöntemi dosyanın ilk satırını sonuna kadar okuyacak ve >> operatörü değişkenlere değer atayacaktır.
Aşağıdaki örnek, bir metin dosyasına veri eklemeyi ve ardından tüm dosyayı okumayı gösterir. içinde açıklanan nedenlerle while(!file2.eof()) yerine while (1) döngüsü kullanılır.
#Dahil etmek
Aşağıdaki örnek, test.txt dosyasındaki satırları okuyarak ve bunları konsolda görüntüleyerek döner.
#Dahil etmek
Windows işletim sistemi altındaki bu kod, dosyanın son satırında yeni satır karakterinin varlığına da bağlıdır, bunu yapmak daha güvenilir olacaktır:
while (1) ( if (file.eof()) break; file.getline(str, sizeof(str)); cout<< str << endl; }
Açık ve kapalı yöntemlere yapılan açık çağrılar isteğe bağlıdır. Aslında, yapıcıyı bir argümanla çağırmak, dosya akışı nesnesi oluşturulduğu anda dosyayı hemen açmanıza izin verir:
ifstream dosyası ("test.txt");
Kapat yöntemi yerine, dosya nesnesinin yıkıcısını otomatik olarak çağıracak ve dosyayı kapatacak olan silme operatörünü kullanabilirsiniz. while döngü kodu, uygun dosya sonu denetimi sağlar.
ofstream sınıfı: dosya yazma
ofstream sınıfı, bir dosya akışından veri çıktısı almak için tasarlanmıştır. Bu sınıfın ana yöntemleri aşağıda listelenmiştir.
Daha önce açıklanan içerme operatörü, bir metin dosyasına yazmayı düzenlemek için uygundur:
Akış dosyası ("temp.txt"); eğer (!file) dönerse; for (int i=1; ben<=3; i++) file << "Строка " << i << endl; file.close();
ikili dosyalar
Prensipte, ikili veriler metin verileri gibi sunulur. Aradaki fark, eğer ikili veriler belirli bir mantıksal yapıda yazılırsa, dosyadan aynı yapı tipindeki bir değişkene okunmaları gerektiğidir.
Yazma ve okuma yöntemlerinin ilk parametresi (yazma/okuma bloğunun adresi) karakter işaretçisi char * türünde olmalıdır, bu nedenle void * yapısının adres türünü açıkça dönüştürmek gerekir. İkinci parametre, dosyanın ikili bloklarının gerçek kayıt uzunluğundan bağımsız olarak sabit bir bayt boyutuna sahip olduğunu belirtir. Aşağıdaki ek, basit bir not defterinde verilerin nasıl oluşturulacağına ve görüntüleneceğine ilişkin bir örnek verir. Dosyanın kayıtları daha sonra sırayla okunur ve konsolda görüntülenir.
#Dahil etmek
Bu kodun yürütülmesinin bir sonucu olarak, her biri 80 baytlık üç bloktan (karakterlerin tek bayt olduğu varsayılarak) bir ikili dosya Notebook.dat oluşturulur. Doğal olarak, diğer akış yöntemlerini kullanabilir ve belirli bir veri yapısının alanları üzerinde herhangi bir işlemi gerçekleştirebilirsiniz.
fstream sınıfı: rastgele dosya erişimi
Not defterimizin 100 giriş biriktirdiğini ve 50'sini saymak istediğimizi varsayalım. Tabii ki, bir döngü düzenleyebilir ve ilkinden verilene kadar tüm kayıtları okuyabilirsiniz. Açıkçası, daha hedefli bir çözüm, pos dosyası konum işaretçisini doğrudan 50 girişine ayarlamak ve okumaktır:
ifstream ifile("Notebook.dat", ios::binary); int konum = 49 * sizeof(Notlar); ifile aramak(konum); // 50. girişi arayın Notlar Not; //Notlar - yukarıda açıklanan "kayıt" yapısı ifile.read((char*)&Note, sizeof(Notes));
Bu tür arama işlemleri, dosya bilinen ve sabit boyuttaki kayıtlardan oluşuyorsa etkilidir. Rastgele bir girdinin içeriğini değiştirmek için çıktı akışını değiştirme modunda açmanız gerekir:
Ofstream ofile("Notebook.dat", ios::binary | ios::ate); int konum = 49 * sizeof(Notlar); ofile searchp(konum); // 50. notayı ara Notes Note50 = ("Yeltsin Boris Nikolaevich", "095-222-3322", 64); ofile.write((char*)&Not, sizeof(Notlar)); // yenisiyle değiştirme
ios::ate (veya ios::app) bayrağını belirtmezseniz, Notebook.dat ikili dosyasını açtığınızda, önceki içeriği silinecektir!
Son olarak, fstream akış sınıfının öncüllerinden miras aldığı yöntemleri kullanarak, bir dosyayı okuma/yazma için aynı anda açmak mümkündür. fstream sınıfı istream ve ostream'den (sırasıyla ifstream ve ofstream'in üst öğeleri) türetildiği için, daha önce bahsedilen yöntemlerin tümü uygulama için kullanılabilir hale gelir.
Aşağıdaki örnek, Notebook.dat dosyasındaki birinci ve üçüncü girdileri değiştirir.
#Dahil etmek
ios::in ve ios::out bayrakları, eşzamanlı okuma ve yazma işlemlerine izin vermek için dosya nesnesinin yapıcısında belirtilmelidir. Bu kodun yürütülmesi sonucunda Notebook.dat ikili dosyasının birinci ve üçüncü kayıtları değiştirilir.
Konuyla ilgili ek örnekler var.
Çoğu bilgisayar programı dosyalarla çalışır ve bu nedenle dosyaları oluşturmaya, silmeye, yazmaya, okumaya, açmaya ihtiyaç vardır. Dosya nedir? Dosya, bazı depolama aygıtlarında depolanabilen adlandırılmış bir bayt koleksiyonudur. Şimdi, bir dosyanın, .txt dosyası gibi kendine özgü bir adı olan bir bayt dizisi olduğu açıktır. Aynı ada sahip dosyalar aynı dizinde olamaz. Dosya adı yalnızca adı olarak değil, aynı zamanda bir uzantı olarak da anlaşılır, örneğin: file.txt ve file.dat — Aynı ada sahip olmalarına rağmen farklı dosyalar. Dosyaların tam adı diye bir şey vardır - bu, dosya adıyla birlikte dosya dizininin tam adresidir, örneğin: D:\docs\file.txt . Bu temel kavramları anlamak önemlidir, aksi takdirde dosyalarla çalışmak zor olacaktır.
Dosyalarla çalışmak için bir başlık dosyası eklemeniz gerekir
Dosya G/Ç, standart G/Ç'ye benzer, tek fark, G/Ç'nin ekrana değil bir dosyaya yapılmasıdır. Standart cihazlara giriş/çıkış cin ve cout nesneleri kullanılarak yapılıyorsa, dosya G/Ç'sini düzenlemek için cin ve cout operatörlerine benzer şekilde kullanılabilecek kendi nesnelerinizi oluşturmanız yeterlidir.
Örneğin, bir metin dosyası oluşturmanız ve içine C++'da Dosyalarla Çalışma satırını yazmanız gerekir. Bunu yapmak için aşağıdaki adımları yapmanız gerekir:
- akış sınıfının bir nesnesini yarat ;
- bir sınıf nesnesini yazılacak dosyayla ilişkilendirin;
- bir dosyaya bir satır yazın;
- dosyayı kapatın.
Neden ifstream sınıfı değil de ofstream sınıfından bir nesne yaratmak gerekiyor? Bir dosyaya yazmanız gerektiğinden ve bir dosyadan veri okumanız gerekirse, ifstream sınıfının bir nesnesi oluşturulur.
// akış dosyasına yazılacak bir nesne yarat /*nesne adı*/; // akış sınıfının nesnesi
Nesneyi çağıralım - fout , İşte olan şey:
Akış dışı maç;
Neden bir nesneye ihtiyacımız var? Nesnenin dosyaya yazabilmesi için gereklidir. Nesne zaten oluşturuldu, ancak dizenin yazılacağı dosyayla ilişkili değil.
fout.open("cppstudio.txt"); // nesneyi dosyayla ilişkilendir
Nokta işlemi ile parantez içinde dosya adını belirttiğimiz open() sınıf yöntemine erişiriz. Belirtilen dosya, programla birlikte geçerli dizinde oluşturulacaktır. Aynı ada sahip bir dosya varsa, mevcut dosya yenisiyle değiştirilecektir. Böylece dosya açılır, içine istenen satırı yazmak kalır. Şu şekilde yapılır:
Fout<< "Работа с файлами в С++"; // запись строки в файл
fout nesnesiyle bağlantılı olarak yayına aktarma işlemini kullanarak, C++'da Dosya İşleme dizesi bir dosyaya yazılır. Dosyanın içeriğini değiştirmek artık gerekli olmadığı için kapatılmalıdır, yani nesne dosyadan ayrılmalıdır.
fout.close(); // dosyayı kapat
Sonuç olarak, Working with files in C++ satırına sahip bir dosya oluşturuldu.
Adım 1 ve 2 birleştirilebilir, yani bir satırda bir nesne oluşturun ve onu bir dosyayla ilişkilendirin. Şu şekilde yapılır:
Akış dışı fout("cppstudio.txt"); // ofstream sınıfından bir nesne oluşturun ve onu cppstudio.txt dosyasıyla ilişkilendirin
Tüm kodları birleştirelim ve aşağıdaki programı elde edelim.
// file.cpp: konsol uygulaması için giriş noktasını tanımlar. #include "stdafx.h" #include
Programın doğru çalışmasını kontrol etmeye devam ediyor ve bunun için dosyayı açıyoruz. cppstudio.txt ve içeriğine bakın, olması gereken - C++'da dosyalarla çalışma.
- ifstream sınıfının bir nesnesini oluşturun ve onu okunacak dosyayla ilişkilendirin;
- dosyayı oku;
- dosyayı kapatın.
Program bir dosyadan okumanın iki yolunu gösterir, ilki akışa aktarım işlemini kullanmak, ikincisi işlevi kullanmaktır. hat almak() . İlk durumda, yalnızca ilk kelime okunur ve ikinci durumda, 50 karakterlik bir dize okunur. Ancak dosyada 50'den az karakter kaldığından, karakterler sonuncusu da dahil olmak üzere okunur. İkinci kez okumanın (17. satır) ilk kelime okunduğundan beri, baştan değil, ilk kelimeden sonra devam etti.14. satır. Programın sonucu Şekil 1'de gösterilmektedir.
C++'da Dosyalarla Çalışma Devam etmek için herhangi bir tuşa basın. . .
Şekil 1 - C++'da dosyalarla çalışma
Program doğru çalıştı, ancak her şey kodla uyumlu olsa bile bu her zaman böyle değildir. Örneğin var olmayan bir dosyanın adı programa geçirilmiş veya adında bir hata yapılmıştır. Sonra ne? Bu durumda, hiçbir şey olmayacak. Dosya bulunmayacak, bu da onu okumanın mümkün olmadığı anlamına geliyor. Bu nedenle derleyici, dosyanın değiştirildiği satırları yok sayar. Sonuç olarak, program doğru bir şekilde çıkacaktır, ancak ekranda hiçbir şey gösterilmeyecektir. Bunun böyle bir duruma tamamen normal bir tepki olduğu anlaşılıyor. Ancak basit bir kullanıcı, sorunun ne olduğunu ve neden dosyadan bir satırın ekranda görünmediğini anlamayacaktır. Bu nedenle, her şeyi açıklığa kavuşturmak için, C++ böyle bir işlev sağlar - is_open() , tamsayı değerleri döndürür: 1 - dosya başarıyla açıldıysa, 0 - dosya açılmadıysa. Dosyanın açılmasıyla programı sonlandıralım, öyle ki dosya açılmazsa ilgili mesaj ekrana gelsin.
// file_read.cpp: konsol uygulaması için giriş noktasını tanımlar. #include "stdafx.h" #include
Programın sonucu Şekil 2'de gösterilmektedir.
Dosya açılamıyor! Devam etmek için herhangi bir tuşa basın. . .
Şekil 2 - C++'da dosyalarla çalışma
Şekil 2'den de görebileceğiniz gibi program dosyanın açılamadığını bildirdi. Bu nedenle, program dosyalarla çalışıyorsa, dosyanın var olduğundan emin olsanız bile is_open() adlı bu işlevi kullanmanız önerilir.
Dosya açma modları
Dosya açma modları, dosyaların nasıl kullanıldığını belirler. Modu ayarlamak için ios_base sınıfı, dosya açma modunu belirleyen sabitler sağlar (bkz. Tablo 1).
Dosya açma modları, bir nesne oluşturulurken veya open() işlevi çağrılırken doğrudan ayarlanabilir. .
Akış dışı fout("cppstudio.txt", ios_base::app); // dosyanın sonuna bilgi eklemek için dosyayı açın fout.open("cppstudio.txt", ios_base::app); // dosyanın sonuna bilgi eklemek için dosyayı aç
Dosya açma modları, bit düzeyinde boole işlemi kullanılarak birleştirilebilir veya| , örneğin: ios_base::out | ios_base::trunc - temizledikten sonra bir dosyayı yazmak için açın.
ofstream sınıfının nesneleri, dosyalarla ilişkilendirildiğinde varsayılan olarak dosya açma modlarını içerir ios_base::out | ios_base::trunc . Yani, dosya yoksa oluşturulacaktır. Dosya varsa, içeriği silinecek ve dosyanın kendisi kayıt için hazır olacaktır. ifstream sınıfının nesneleri, bir dosyayla ilişkilendirildiğinde, varsayılan olarak dosya açma moduna sahiptir ios_base::in - dosya salt okunurdur. Dosya açma modu ayrıca bayrak olarak da adlandırılır, okunabilirlik için gelecekte bu terimi kullanacağız. Tablo 1 tüm bayrakları listelemiyor, ancak bunlar başlamanız için yeterli olmalıdır.
Lütfen not edin, ate ve app bayrakları açıklamada çok benzerdir, ikisi de işaretçiyi dosyanın sonuna taşır, ancak uygulama bayrağı yalnızca dosyanın sonuna yazmaya izin verir ve ate bayrağı bayrağı basitçe yeniden düzenler. dosyanın sonu ve kayıt alanını sınırlamaz.
Sizeof() işlemini kullanarak, C++'daki ana veri türlerinin özelliklerini hesaplayacak ve bir dosyaya yazacak bir program geliştirelim. Özellikler:
- veri türü için ayrılan bayt sayısı
- belirli bir veri türünün saklayabileceği maksimum değer.
Bir dosyaya yazma aşağıdaki biçimde olmalıdır:
/* veri türü bayt maksimum değer bool = 1 255,00 karakter = 1 255.00 kısa int = 2 32767.00 unsigned kısa int = 2 65535.00 int = 4 2147483647.00 unsigned int = 4 4294967295.00 long int = 4 2147483647.00 unsigned uzun int = 4 4294967485.00 float = 4 2 uzun kayan nokta = 8 9223372036854775800.00 çift = 8 9223372036854775800.00 */
Böyle bir program bölümün başlarında zaten geliştirilmiştir, ancak veri türleri hakkındaki tüm bilgiler standart çıktı aygıtına çıktı ve bilgilerin bir dosyaya yazılması için programı yeniden oluşturmamız gerekiyor. Bunu yapmak için, mevcut dosya bilgilerinin ön kesilmesi ile dosyayı yazma modunda açmanız gerekir ( 14. satır). Dosya oluşturulduktan ve başarıyla açıldıktan sonra (satır 16 - 20), cout ifadesi yerine 22. satır fout nesnesini kullanın. böylece bir ekran yerine veri türleri ile ilgili bilgiler bir dosyaya yazılacaktır.
// write_file.cpp: konsol uygulaması için giriş noktasını tanımlar. #include "stdafx.h" #include
Standart giriş/çıkış ve dosya giriş/çıkışlarının birebir aynı şekilde kullanılması sayesinde programdaki değişikliklerin minimum düzeyde olduğunu fark etmemek mümkün değil. Programın sonunda,hat 45Dosyayı açıkça kapattık, bu gerekli olmasa da iyi bir programlama uygulaması olarak kabul ediliyor. Standart girdi/çıktıları biçimlendirmek için kullanılan tüm işlevlerin ve manipülatörlerin dosya girdi/çıktıları için de geçerli olduğunu belirtmekte fayda var. Bu nedenle, operatör çalışırken herhangi bir hata oluşmadı. cout bir nesne ile değiştirildi fout.
Son güncelleme: 31.10.2015
System.IO ad alanındaki dizinlerle çalışmak üzere iki sınıf tasarlanmıştır: Directory ve DirectoryInfo .
dizin sınıfı
Directory sınıfı, dizinleri yönetmek için bir dizi statik yöntem sağlar. Bu yöntemlerden bazıları şunlardır:
CreateDirectory(path) : belirtilen yolda bir dizin oluşturur
Sil(yol) : verilen yoldaki dizini siler
Exists(path) : Belirtilen yoldaki dizinin mevcut olup olmadığını belirler. Varsa true, yoksa false döndürür.
GetDirectories(path) : Yoldaki dizinlerin bir listesini alır
GetFiles(path) : Dizin yolundaki dosyaların bir listesini alır
Taşı(sourceDirName, destDirName): dizini taşır
GetParent(path) : ana dizini al
DirectoryInfo sınıfı
Bu sınıf, oluşturma, silme, taşıma ve diğer dizin işlemleri için işlevsellik sağlar. Birçok yönden, Dizin'e benzer. Bazı özellikleri ve yöntemleri şunlardır:
Create() : bir dizin oluşturur
CreateSubdirectory(path) : belirtilen yolda bir alt dizin oluşturur
Delete() : bir dizini siler
Exists özelliği: dizinin var olup olmadığını belirler
GetDirectories() : Dizinlerin bir listesini alır
GetFiles() : dosyaların bir listesini alın
MoveTo(destDirName) : bir dizini taşır
Ana özellik: ana dizini alma
Kök özelliği: kök dizini alma
Bu sınıfların kullanımına ilişkin örneklere bakalım
Dosyaların ve alt dizinlerin bir listesini alma
string dirName = "C:\\"; if (Directory.Exists(dirName)) ( Console.WriteLine("Altdizinler:"); string dirs = Directory.GetDirectories(dirName); foreach (dizilerdeki dizgeler) ( Console.WriteLine(s); ) Console.WriteLine( ); Console.WriteLine("Files:"); string dosyaları = Directory.GetFiles(dirName); foreach (dosyalardaki stringler) ( Console.WriteLine(s); ) )Dosya adlarında eğik çizgi kullanımına dikkat edin. Ya çift eğik çizgi kullanırız: "C:\\" ya da tek bir çizgi, ancak sonra @ işaretini tüm yolun önüne koyarız: @"C:\Program Files"
Bir dizin oluşturun
string yolu = @"C:\SomeDir"; string subpath = @"program\avalon"; DirectoryInfo dirInfo = yeni DirectoryInfo(yol); if (!dirInfo.Exists) ( dirInfo.Create(); ) dirInfo.CreateSubdirectory(alt yol);İlk önce böyle bir dizin olup olmadığını kontrol ediyoruz çünkü varsa onu oluşturmak mümkün olmayacak ve uygulama hata verecektir. Sonuç olarak şu yolu elde edeceğiz: "C:\SomeDir\program\avalon"
Bir dizin hakkında bilgi alma
string dirName = "C:\\Program Dosyaları"; DirectoryInfo dirInfo = yeni DirectoryInfo(dirName); Console.WriteLine($"Dizin adı: (dirInfo.Name)"); Console.WriteLine($"Tam dizin adı: (dirInfo.FullName)"); Console.WriteLine($"Dizin oluşturma zamanı: (dirInfo.CreationTime)"); Console.WriteLine($"Kök dizin: (dirInfo.Root)");Bir dizini silme
Silme yöntemini, herhangi bir dosya veya alt dizin içeren boş olmayan bir klasöre uygularsak, uygulama bir hata verir. Bu nedenle, klasörün tüm içeriğiyle birlikte silinmesi gerektiğini gösterecek olan Delete yöntemine ek bir boole tipi parametre iletmemiz gerekiyor:
String dirName = @"C:\SomeFolder"; try ( DirectoryInfo dirInfo = new DirectoryInfo(dirName); dirInfo.Delete(true); Console.WriteLine("Dizin silindi"); ) catch (ex İstisna) ( Console.WriteLine(ex.Message); )
String dirName = @"C:\SomeFolder"; Directory.Delete(dirName, true);
Bir dizini taşıma
string oldPath = @"C:\SomeFolder"; string newPath = @"C:\SomeDir"; DirectoryInfo dirInfo = yeni DirectoryInfo(eskiYol); if (dirInfo.Exists && Directory.Exists(newPath) == false) ( dirInfo.MoveTo(newPath); )Taşınırken, eski dizinin tüm içeriğini taşımak istediğimiz yeni dizinin olmaması gerektiğini dikkate almalıyız.
Kullanım kolaylığı için, depolama aygıtlarındaki bilgiler dosya biçiminde saklanır.
Dosya, bir dizi veriyi depolamak için ayrılmış, adlandırılmış bir harici bellek alanıdır. Dosyalarda bulunan veriler çok çeşitli niteliktedir: algoritmik veya makine dilinde programlar; programların çalışması veya program yürütme sonuçları için ilk veriler; keyfi metinler; grafikler vb.
Dizin (klasör, dizin) - dosyaların organizasyonunu basitleştirmek için dosya sisteminde kullanılan, alt dizinlerin ve dosyaların adlarını içeren bir depolama ortamında adlandırılmış bir bayt koleksiyonu.
dosya sistemi dosyalar üzerinde işlem sağlayan işletim sisteminin işlevsel bir parçasıdır. Dosya sistemlerine örnek olarak FAT (FAT - Dosya Ayırma Tablosu, dosya ayırma tablosu), NTFS, UDF (CD'lerde kullanılır) verilebilir.
FAT'nin üç ana sürümü vardır: FAT12, FAT16 ve FAT32. Disk yapısındaki kayıtların bitliği bakımından farklılık gösterirler, yani. küme numarasını depolamak için ayrılan bit sayısı. FAT12 esas olarak disketler (4 KB'ye kadar), küçük diskler için FAT16, yüksek kapasiteli FLASH sürücüler (32 GB'a kadar) için FAT32 kullanılır.
Örnek olarak FAT32 kullanan dosya sisteminin yapısını düşünün.
FAT32 dosya yapısı
FAT32 sistemindeki harici bellek aygıtları bayt değil, blok adreslemedir. Bilgiler, bloklar veya sektörler halinde harici bir bellek aygıtına yazılır.
Sektör - harici depolama aygıtlarında adreslenebilir minimum bilgi depolama birimi. Tipik olarak, sektör boyutu 512 bayt olarak sabitlenir. Harici bellek aygıtlarının adres alanını artırmak için sektörler, küme adı verilen gruplar halinde birleştirilir.
Bir küme, belirli özelliklere sahip bağımsız bir birim olarak kabul edilebilecek birkaç sektörün bir birleşimidir. Bir kümenin ana özelliği, sektör sayısı veya bayt sayısı ile ölçülen boyutudur.
FAT32 dosya sistemi aşağıdaki yapıya sahiptir.
Dosya yazmak için kullanılan kümeler 2'den başlayarak numaralandırılır. Kural olarak, küme #2 kök dizin tarafından kullanılır ve küme #3'ten başlayarak veri dizisi depolanır. Kök dizinin üzerinde bilgi depolamak için kullanılan sektörler kümelenmez.
Diskteki minimum dosya boyutu 1 kümedir.
Önyükleme sektörü aşağıdaki bilgilerle başlar:
- EB 58 90 - koşulsuz şube ve imza;
- 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
- 00 02 - sektördeki bayt sayısı (genellikle 512);
- 1 bayt - kümedeki sektör sayısı;
- 2 bayt - yedek sektör sayısı.
Ayrıca, önyükleme sektörü aşağıdaki önemli bilgileri içerir:
- 0x10 (1 bayt) – FAT tablolarının sayısı (genellikle 2);
- 0x20 (4 bayt) - diskteki sektör sayısı;
- 0x2C (4 bayt) – kök dizin küme numarası;
- 0x47 (11 bayt) – birim etiketi;
- 0x1FE (2 bayt) - Önyükleme sektörü imzası (55 AA).
Dosya sistemi bilgi sektörü şunları içerir:
- 0x00 (4 bayt) – imza (52 52 61 41 );
- 0x1E4 (4 bayt) – imza (72 72 41 61);
- 0x1E8 (4 bayt) – serbest küme sayısı, bilinmiyorsa -1;
- 0x1EC (4 bayt) – son kaydedilen kümenin numarası;
- 0x1FE (2 bayt) - imza (55 AA).
FAT tablosu, diskteki her kümenin durumu hakkında bilgi içerir. FAT tablosunun alt 2 baytı, F8 FF FF 0F FF FF FF FF (0 ve 1 kümelerinin durumuna karşılık gelir, fiziksel olarak yoktur) depolar. Ayrıca, her kümenin durumu, mevcut dosyanın devam ettiği kümenin numarasını veya aşağıdaki bilgileri içerir:
- 00 00 00 00 – küme ücretsizdir;
- FF FF FF 0F, geçerli dosyanın sonudur.
- 8 bayt - dosya adı;
- 3 bayt - dosya uzantısı;
Kök dizin, aşağıdaki bilgileri içeren her dosya için bir dizi 32 bit bilgi kaydı içerir:
Uzun dosya adlarıyla (Rusça adlar dahil) çalışırken, dosya adı UTF-16 kodlama sisteminde kodlanır. Bu durumda, her karakterin kodlanması için 2 bayt tahsis edilir. Bu durumda dosya adı aşağıdaki yapı şeklinde yazılır:
- 1 bayt dizisi;
- 10 bayt, dosya adının alt 5 karakterini içerir;
- 1 bayt özniteliği;
- 1 bayt ayrılmış;
- 1 bayt - DOS adı sağlama toplamı;
- 12 bayt, dosya adının en alttaki 3 karakterini içerir;
- 2 bayt – ilk kümenin numarası;
- uzun adın kalan karakterleri.
C'de Dosyalarla Çalışmak
Programcı için açık bir dosya, okunan veya yazılan bir veri dizisi olarak temsil edilir. Bir dosya açıldığında, bununla ilişkilendirilir. G/Ç akışı. Çıkış bilgileri akışa yazılır, giriş bilgileri akıştan okunur.
G/Ç için bir akış açıldığında, stdio.h içinde tanımlanan FILE türünün standart yapısıyla ilişkilendirilir. FILE yapısı, dosya hakkında gerekli bilgileri içerir.
Bir dosyanın açılması, dosya üzerinde sonraki işlemler için kullanılabilecek FILE türünde bir yapıya bir işaretçi döndüren fopen() işlevi kullanılarak yapılır.
DOSYA *fopen(isim, tür);
name, açılacak dosyanın adıdır (yol dahil),
type, dosyaya nasıl erişildiğini tanımlayan bir karakter dizisine yönelik bir işaretçidir:
- "r" - dosyayı okumak için aç (dosya mevcut olmalıdır);
- "w" - yazmak için boş bir dosya açın; dosya varsa, içeriği kaybolur;
- "a" - sonuna kadar yazmak için dosyayı aç (eklemek için); dosya yoksa oluşturulur;
- "r+" - dosyayı okumak ve yazmak için açın (dosya mevcut olmalıdır);
- "w+" - okuma ve yazma için boş bir dosya açın; dosya varsa, içeriği kaybolur;
- "a+" - dosyayı okumak ve eklemek için açın, dosya yoksa oluşturulur.
Dönüş değeri, açık akışa yönelik bir işaretçidir. Bir hata bulunursa, NULL döndürülür.
fclose() işlevi, fopen() ile açılan dosyalarla ilişkili akışı veya akışları kapatır. Kapatılacak akış, fclose() işlevinin argümanı tarafından belirlenir.
Dönüş değeri: akış başarıyla kapatılmışsa 0 değeri; bir hata oluştuğunda EOF sabiti.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#Dahil etmek
int ana() (
DOSYA *fp;
karakter adı = "benim.txt" ;
if ((fp = fopen(isim, "r" )) == NULL )
{
yazdırf( "Dosya açılamadı");
getchar();
0 döndür;
}
// dosyayı açma başarılı
... // veriler üzerinde gerekli işlemler
fclose(fp);
getchar();
0 döndür;
}
Dosyadan karakter okuma:
char fgetc(akım);
İşlev bağımsız değişkeni, FILE türünde bir akışın işaretçisidir. İşlev, okunan karakterin kodunu döndürür. Dosyanın sonuna ulaşılırsa veya bir hata oluşursa, EOF sabiti döndürülür.
Dosyaya karakter yazma:
fputc(karakter, akış);
İşlevin argümanları, bir karakter ve FILE türündeki bir akışın işaretçisidir. İşlev, okunan karakterin kodunu döndürür.
fscanf() ve fprintf() işlevleri, scanf() ve printf() işlevlerine benzer, ancak veri dosyaları üzerinde çalışır ve ilk argüman olarak bir dosya işaretçisine sahiptir.
fscanf(akış, "InputFormat", argümanlar);