1. Trang chủ
  2. » Công Nghệ Thông Tin

Xuất nhập C++ nâng cao

42 1,1K 2
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 42
Dung lượng 85,56 KB

Nội dung

Xuất nhập C++ nâng cao

Trang 1

Chương 8

Nhập/Xuất C++ nâng cao

• Tạo Bộ thao tác Nhập/Xuất

• Nhập/Xuất File

• Nhập/Xuất File nhị phân không định dạng

• Các hàm Nhập/Xuất nhị phân

• Truy cập ngẫu nhiên

• Kiểm tra trạng thái Nhập/Xuất

• Nhập/Xuất theo đơn đặt hàng và các File

• Nhập/Xuất theo mảng

Trang 3

I/ Tạo Bộ thao tác Nhập/Xuất

Ngoài bộ chèn và bộ chiết, có thể sửa đổi hệ thống nhập/xuất của C++ bằng cách

tạo ra bộ thao tác nhập/xuất tự tạo Nó có hai lý do :

* một bộ thao tác có thể hợp nhất một dãy các thao tác nhập/xuất thành một bộ thao tác tự tạo

* một bộ thao tác nhập/xuất tự tạo cần thiết khi nhập/xuất trên các thiết bị không chuẩn (máy in đặc biệt hay hệ thống nhận dạng quang học)

Có hai loại bộ thao tác, một dùng cho các stream nhập, một dùng cho các stream

xuất Ngoài ra người ta còn phân thành hai nhóm : bộ thao tác có tham số và bộ thao

tác không có tham số, chúng khác nhau về cách tạo ra bộ thao tác Việc tạo ra bộ thao tác có tham số không thuộc phạm vi bài giảng này

Dạng tổng quát của các bộ thao tác xuất không có tham số :

ostream &manip_name(ostream &stream)

{

// program codes

return stream

}

manip_name tên của bộ thao tác được tạo ra

Lưu ý : bộ thao tác trên có đối số là một tham chiếu đến stream mà nó thao tác, khi gọi bộ này, không được kèm theo tên bộ thao tác bất kỳ một đối số nào

Dạng tổng quát của các bộ thao tác nhập không có tham số :

istream &manip_name(istream &stream)

{

// program codes

return stream

}

Trang 4

Một bộ thao tác nhập nhận một tham chiếu đến stream mà nó thao tác Stream này phải được trả về bởi bộ thao tác

Ví dụ 1.1 Chương trình tạo ra bộ thao tác xuất setup() Khi được gọi, bộ này sẽ thiết lập độ rộng trường là 10, độ chính xác là 4 và dấu "* " là ký tự lấp đầy

Trang 5

cout << atn << "High voltage circuit\n";

cout << note << "Turn off all lights\n";

// A simple input manipulator

istream &getpass(istream &stream)

{

cout << '\a'; // sound bell

cout << "Enter password: ";

Trang 6

3 Hãy tạo một bộ thao tác mới tên là skipchar() dùng để đọc và bỏ qua mười ký tự liên tiếp từ một stream nhập

Trang 7

II/ Nhập/Xuất File

Trong C++, một file được mở bằng cách liên kết nó với một stream Có ba loại stream

: nhập, xuất và nhập/xuất Trước khi mở file phải tạo ra stream tương ứng

Để tạo một stream nhập, cần khai báo stream đó thuộc lớp ifstream

Để tạo một stream xuất, cần khai báo stream đó thuộc lớp ofstream

Đối với stream thực hiện cả thao tác nhập và xuất, cần khai báo stream đó thuộc lớp

fstream

Ví dụ

ifstream in; // input stream

ofstream out; // output stream

fstream io; // input and output stream

2/ Mở file

a/ Sau khi tạo ra một stream, có thể mở file gắn với stream đó bằng hàm open()

Hàm này là hàm thành phần của ba stream nói trên, dạng tổng quát :

void open(const char *filename, int mode, int access);

filename tên của file cần mở, có thể đi kèm với đường dẫn

mode xác định chế độ của file được mở

access xác định cách truy cập file

@ Các giá trị nguyên của mode, có thể là một hay nhiều giá trị (được kế thừa bởi

fstream.h)

Chế độ ios::app làm cho kết xuất được thêm vào cuối của file Dùng cho các

file xuất

Trang 8

Chế độ ios::ate cho phép chuyển đến vị trí cuối file ngay sau khi file được mở

Lưu ý, mặc dù đang ở vị trí cuối file, các thao tác nhập/xuất vẫn có thể xuất hiện ở bất cứ vị trí nào của file

Chế độ ios::in xác định file được mở là file nhập Chế độ ios::out xác định file

được mở là file xuất

Tuy nhiên, việc tạo ra một stream bằng các khai báo nó thuộc lớp ifstream ngầm định nó là một stream nhập, cũng như khai báo stream thuộc lớp ofstream ngầm định nó là một stream xuất Trong hai trường hợp trên, không cần phải xác định các giá trị ios::in và ios::out khi mở file

Chế độ ios::binary làm cho file được mở ở chế độ nhị phân

Theo mặc định, tất cả các file được mở ở chế độ văn bản (text mode) Trong chế độ

văn bản, sẽ có một số trường hợp ký tự sẽ bị chuyển đổi Ví dụ, ký tự tạo dòng mới ( '\n' ) sẽ được chuyển thành chuổi liên tiếp nhau của hai ký tự xuống dòng (carriage

return, mã 13), và thêm một dòng (line-feed, mã 10)

Khi hoạt động ở chế độ nhị phân, sẽ không có bất kỳ một trường hợp chuyển đổi ký tự

nào Bất kỳ một file nào đều có thể hoạt động ở hai chế độ văn bản hay nhị phân

Chế độ ios::nocreate làm cho việc gọi hàm open() bị thất bại nếu file được mở là một file mới (chưa có sẵn trên điã) Còn ios::noreplace làm cho việc gọi hàm

open() bị thất bại nếu file được mở đã có sẵn trên điã

Chế độ ios::trunc làm cho khi file có sẵn trùng tên với file được mở sẽ bị xoá

sạch nội dung

Có thể sử dụng kết hợp hai hay nhiều chế độ ở trên bằng phép toán OR

@ Các giá trị của đối số access xác định cách truy cập file

Giá trị ngầm định của đối số này là filebuf::openprot (filebuf là lớp cha của các

lớp stream) Trong môi trường UNIX nó có giá trị 0x644 đối với các file thông thường

Trong môi trường DOS/WINDOWS giá trị của đối số access qui định mã thuộc tính của file, bao gồm :

Trang 9

Thuộc tính Ý nghiã

0 Archive File bình thường : ghi / đọc (mặc định)

1 Read only File chỉ đọc

Có thể sử dụng kết hợp hai hay nhiều thuộc tính ở trên bằng phép toán OR

• Ví dụ đoạn chương trình sau minh hoạ việc mở file bình thường trong DOS/WINDOWS

ofstream out ; // khai báo stream xuất

out.open ("test.txt", ios::out, 0) ;

hoặc out.open("test.txt") ; // lời gọi ngắn gọn, thông thường

• Để mở file nhập/xuất, cần phải xác định cả hai chế độ ios::in và ios::out cho đối số mode, được minh hoạ sau đây Lưu ý, không có giá trị mặc định cho trường hợp này

fstream mystream; // khai báo stream xuất

mystream.open ("test.txt", ios::in | ios::out) ;

Nếu hàm open() không thực thi được, stream được trả về sẽ mang giá trị không Do đó, cần kiểm tra lại việc mở file có thành công hay không, trước khi truy xuất nó Ví dụ :

Trang 10

Thông thường, không cần dùng hàm open() để mở file, vì các lớp ifstream, ofstream và fstream đã có sẵn các hàm tạo dùng để mở file một cách tự động Các

hàm tạo này có các đối số giống hệt như của hàm open() Dạng thông thường mở file

để nhập :

ifstream mystream("test.txt");

Cần kiểm tra lại việc mở file có thành công hay không, trước khi truy xuất nó

3/ Đóng file

Dùng hàm void close() Hàm này không có đối số và không trả về giá trị nào cả

Ví dụ đóng một file đang gắn với stream mystream, cần gọi :

mystream.close();

• Để kiểm tra tình trạng hết file dùng hàm eof()

int eof();

Hàm trả về giá trị ≠ 0 khi đang ở tình trạng cuối file

giá trị = 0 ngược lại

Ví dụ mystream.eof();

4/ Truy xuất nội dung trên file

Toán tử xuất << và toán tử nhập >> được sử dụng để truy xuất nội dung trên file, cần phải thay các stream cin và cout bằng stream liên kết với file

Thông tin lưu trên file có cùng định dạng như khi nó được trình bày trên màn hình

Do đó, các file tạo ra bằng toán tử xuất << và các file được đọc vào bằng toán tử nhập >> đều là các file văn bản có định dạng

Ví dụ 2.1 Tạo một file xuất, ghi lên file, đóng file Mở file đó như một file nhập, đọc nội dung của file

#include <iostream.h>

#include <fstream.h>

Trang 12

Hello!

100 64

Ví dụ 2.2 Chương trình đọc từ bàn phím một chuổi ký tự, ghi lên file, đóng file Chương trình kết thúc khi nhập một dòng trống Mở file đó như một file nhập, đọc nội dung của file

// WRITE.CPP

#include <iostream.h>

#include <fstream.h>

#include <iomanip.h>

int main(int argc, char *argv[]) // argc : số các tham số ,

// *argv[] : chứa nội dung các tham số {

if(argc!=2) {

cout << "Usage: WRITE <filename> \n";

// argv[0] = '\<path>\WRITE.EXE' // argv[1] = '<filename>'

Trang 13

ifstream fin(argv[1]); // open input file to read

ofstream fout(argv[2]); // create output file to write

Trang 14

2 Viết chương trình để ghi bảng dữ liệu sau đây vào một file có tên là phone.txt

Nguyễn Công Trứ 08.8980168

Phạm Ngũ Lão 04.2325678

Trần Nguyên Hãn 04.6781234

3 Viết chương trình đếm số lượng từ có trong một text file bất kỳ

III/ Nhập/Xuất File nhị phân không định dạng

Việc nhập/xuất file nhị phân không định dạng linh động hơn nhập/xuất text file

Trang 15

1/ Các hàm nhập/xuất cấp thấp

• Đọc ghi từng ký tự

Dạng phổ biến của chúng :

istream &get (char &ch);

ostream &put(char ch);

Hàm get() đọc một ký tự từ stream tương ứng và gán ký tự đó vào nội dung của ch Hàm trả về một tham chiếu đến stream, nó sẽ là NULL nếu đến cuối file

Hàm put() ghi (xuất) nội dung của ch ra một stream và trả về một stream

• Đọc ghi các khối dữ liệu nhị phân

istream &read(unsigned char *buf, int num);

ostream &write(const unsigned char *buf, int num);

Hàm read() đọc một số lượng num các byte từ stream tương ứng và ghi lên một vùng đệm được trỏ bởi buf

Hàm write() ghi một số lượng num các byte ở vùng đệm được trỏ bởi buf đến stream

tương ứng

Nếu file được đọc hết trước khi đủ num ký tự, hàm read() hoàn tất bình thường và vùng đệm chứa hết số ký tự của lần đọc cuối Để biết lần cuối này có bao nhiêu ký tự được đưa ra vùng đệm, dùng hàm gcount() có dạng

int gcount();

Hàm sẽ trả về giá trị là tổng số ký tự đọc được ở lần đọc cuối ngay trước khi hết file

Lưu ý : việc thiết lập chế độ ios::binary chỉ nhằm mục đích ngăn ngừa việc chuyển

đổi ký tự Khi sử dụng các hàm nhập/xuất file nhị phân không định dạng, không cần

mở file ở chế độ ios::binary

Ví dụ 3.1 Chương trình xuất nội dung của một file bất kỳ ra màn hình

// PR.CPP

Trang 17

Lưu ý : chương trình dùng hàm get() để đọc ký tự từ stream cin vào Nếu dùng toán

tử << các ký tự khoảng cách sẽ bị bỏ qua, trong khi sử dụng hàm get() các ký tự

khoảng cách vẫn được nhận vào

Ví dụ 3.3 Chương trình dùng hàm write() để ghi một số thực kiểu double và một

chuỗi ký tự lên một file có tên là test.txt

Trang 18

char str[] = "This is a test";

out.write((char *) &num, sizeof(double));

out.write(str, strlen(str));

out.close();

return 0;

}

Lưu ý : việc khai báo linh hoạt (char *) khi gọi hàm write() là cần thiết khi vùng

đệm không được định nghiã là một dãy ký tự Do C++ kiểm tra kiểu rất kỹ, nên một con trỏ chỉ đến kiểu dữ liệu này không thể được tự động đổi thành một con trỏ của kiểu khác

Ví dụ 3.4 Chương trình dùng hàm read() để đọc nội dung text file test.txt từ ví dụ

Trang 19

Ví dụ 3.5 Chương trình ghi một mảng các giá trị kiểu double một file và sau đó

đọc lại nội dung file Chương trình còn thông báo số lượng các ký tự đã đọc

Trang 20

Bài tập III

1 Viết lại chương trình trong các bài tập 1 và 3 phần II chương 8, thay bằng các hàm get(), put(), read() hoặc write() sao cho phù hợp nhất

2 Cho lớp sau đây, viết chương trình ghi nội dung của lớp lên một file, sử dụng bộ chèn

Trang 21

}

// create inserter here

};

IV/ Các hàm Nhập/Xuất nhị phân

Hai dạng quá tải hàm get() thường dùng :

istream &get(char *buf, int num, char delim = '\n') ;

Hàm get() đọc các ký tự vào một dãy được chỉ bởi buf, với số lượng là num ký tự hoặïc khi đọc vào một ký tự phân cách delim

Nếu trong đối số của hàm không có đối số delim, giá trị mặc định của ký tự phân

cách là ký tự sang dòng mới '\n' Nếu ký tự phân cách xuất hiện trong stream nhập, ký tự sẽ không bị lấy ra, thay vào đó, ký tự này sẽ ở trong stream cho đến khi gặp thao tác nhập khác

int get() ;

Hàm get() trả về ký tự kế tiếp trong stream Nếu gặp tình trạng hết file, hàm trả về giá trị EOF (giống như hàm getc() trong ngôn ngữ C)

istream &getline(char *buf, int num, char delim = '\n') ;

Hàm getline() cũng thực hiện nhập dữ liệu, đọc và bỏ các ký tự phân cách ra khỏi

stream (nhập được một chuỗi) Các đối số tương tự như hàm get() ở trên

int peek() ;

Hàm peek() có thể lấy ký tự tiếp theo trong stream nhập mà không cần phải đưa nó

ra khỏi stream Hàm trả về giá trị là ký tự tiếp theo của stream, nếu hết file, hàm trả về giá trị EOF

istream &putback(char ch) ;

Hàm putback() trả lại giá trị vừa đọc vào stream Đối số ch là ký tự vừa được đọc

vào từ stream

Trang 22

ostream &flush() ;

Mỗi khi thao tác xuất được thực hiện, dữ liệu không được đưa ra ngay thiết bị vật lý liên kết với stream, mà thông tin đó được đưa vào vùng đệm Khi vùng đệm bị đầy,

dữ liệu của vùng đệm mới được xuất ra điã Tuy nhiên, nếu muốn thông tin xuất ra

điã trước khi đầy vùng đệm, có thể dùng hàm flush()

Nên dùng hàm này khi máy tính hoạt động với nguồn điện hoạt động không ổn định

Ví dụ 4.1 Dùng hàm getline() nhập vào một chuỗi bất kỳ

// Use getline() to read a string that contains spaces

cout << "Enter your name: ";

cin.getline(str, 79); // tương tự như hàm gets(str) ;

cout << str << '\n';

return 0;

}

Ví dụ 4.2 Dùng hàm peek() và putback() trợ giúp xử lý dễ dàng khi không biết

ược kiểu của thông tin nhập vào

Trang 23

out << 123 << "this is a test" << 23;

out << "Hello there!" << 99 << "sdf" << endl;

while(isdigit(*p = in.get() ) ) p++; // read integer

in.putback(*p); // return char to stream

cout << "Integer: " << atoi(str);

}

else if(isalpha(ch)) { // read a string

while(isalpha(*p = in.get() ) ) p++;

cout << "String: " << str;

}

Trang 24

3 Viết chương trình minh hoạ hoạt động của hàm flush() ?

V/ Truy cập ngẫu nhiên

• C++ cung cấp việc truy cập ngẫu nhiên một file qua các hàm :

istream &seekg(streamoff offset, seek_dir origin) ;

ostream &seekp(streamoff offset, seek_dir origin) ;

streamoff là kiểu định nghiã trong iostream.h, nó có thể lưu trữ được giá trị hợp lệ

lớn nhất mà offset có thể nhận được

seek_dir là một kiểu hằng liệt kê với các giá trị như sau :

Giá trị Ý nghiã ios::beg tìm từ vị trí đầu file ios::cur tìm từ vị trí hiện hành ios::end tìm từ vị trí cuối file

Hàm seekg() dời con trỏ get của file tương ứng một đoạn bằng offset byte từ một vị

trí được xác định bằng origin

Trang 25

Hàm seekp() dời con trỏ put của file tương ứng đi một đoạn bằng offset byte tính từ

vị trí được xác định bởi origin

• Hệ thống nhập/xuất của C++ sử dụng hai con trỏ để quản lý một file

Thứ nhất là con trỏ get để trỏ đến vị trí sẽ được đưa vào nếu file được thực hiện một

tác vụ nhập nữa

Thứ hai là con trỏ put xác định vị trí của file mà một tác vụ xuất tiếp theo sẽ đọc ra

từ đó

Mỗi khi thực hiện thao tác nhập/xuất file con trỏ sẽ được tự động tăng lên để chỉ vào

vị trí kế tiếp Tuy nhiên, vẫn có thể dùng hàm seekg() và seekp() để truy cập file một cách ngẫu nhiên

Có thể xác định vi trí hiện hành của các con trỏ get và put bằng các hàm :

streampos tellg() ;

streampos tellp() ;

streampos là kiểu định nghiã trong iostream.h, nó có thể lưu trữ được giá trị

lớn nhất mà hàm có thể trả về được

Ví dụ 5.1 Dùng hàm seekp() cho phép đổi một ký tự xác định của file Tham số của chương trình gồm tên file, số thứ tự của byte cần thay thế và ký tự cần thay

Ngày đăng: 04/09/2012, 15:12

TỪ KHÓA LIÊN QUAN

w