06 Xuat Nhap File
06 Xuat Nhap File
scanf(“%d”, &score); A…
while (score != 0) {
printf(“%d \n”, score);
scanf(“%d”, &score);
}
Trang 1
Giá Trị Trả Về Của Hàm scanf
• scanf trả về giá trị có kiểu nguyên
– Cho biết số giá trị đã được nhập vào thành công
– Có thể được dùng để kiểm tra xem liệu đã nhập đủ số giá trị mong
muốn hay chưa, nếu chưa đủ thì yêu cầu nhập tiếp hoặc thông báo
lỗi
• Chương trình đơn giản in ra dòng lệnh vào (ngoại trừ argv[0]).
4
Kỹ Thuật Lập Trình
(Ngôn Ngữ Lập Trình C)
Xuất/Nhập File
Tại Sao Cần Xuất/Nhập File?
• Lượng lớn dữ liệu đầu vào.
• Lượng lớn dữ liệu đầu ra.
• Khả năng lưu trữ dữ liệu lâu dài
• Truyền dữ liệu cho các chương trình khác.
• Các dòng xuất/nhập diễn ra đồng thời.
Trang 6
File
• File là một tập hợp của dữ liệu ghi trên đĩa
– Được quản lý bởi người dùng và hệ điều hành
– Có thể lưu giữ dữ liệu lâu dài
• Tên file là phương tiện để người dùng và hệ điều hành nhận biết
file
– Tuân theo quy tắc đặt tên 8.3 trong DOS
• Chúng ta sẽ ôn lại các file dùng trong quá trình biên dịch; ôn lại
việc xuất/nhập qua bàn phím, màn hình; và xem xét việc dùng
các file text trong chương trình C.
• Nhưng trước hết, chúng ta tìm hiểu các file dữ liệu.
Trang 7
File IO
8
Ôn Lại: File Dùng Khi Biên Dịch
• File nguồn
– .c file: chương trình và hàm viết trên C
– .h file: khai báo
– Các dự án trong thực tế có thể có hàng trăm file .c và .h
• File được dịch ra (tên tùy thuộc vào từng hệ thống)
– File đối tượng (object): file đã được dịch và chờ để liên kết
– File thư viện (library): tập hợp các hàm đã được dịch sẵn
– File thi hành (executable): file mã máy đã được liên kết, sẵn sàng
để chạy trong bộ nhớ máy tính
Trang 9
File Tiêu Đề (.h)
• Tệp tiêu đề thường được sử dụng để chứa
– Định nghĩa kiểu (sử dụng typedef)
– Nguyên mẫu hàm
stdio.h hw.c vector.h vector.c
– Hằng số tượng trưng
– Khai báo biến toàn cục
compiler compiler
other libs
.exe file
Trang 10
Thư Viện
• Là các file chứa các hàm được viết và dịch sẵn
– Giảm phụ thuộc vào hệ thống
– Sử dụng lại mã đã có
– Tăng tính khả chuyển
Standard
ANSI C
Libraries
MSCV local
libraries libraries
Trang 11
Xuất/Nhập Ký Tự Với File
• Bàn phím / màn hình là những trường hợp đặc biệt của các
dòng xuất/nhập các ký tự
error\n
abc12 12
program
variables 12, 13, 13
hx119 8s
Trang 12
Có Gì Trong File stdio.h
• Nguyên mẫu của các hàm xuất/nhập
• Định nghĩa các hằng số hữu dụng
– Ví dụ EOF
• Định nghĩa cấu trúc FILE để biểu diễn thông tin các file sử
dụng trong chương trình C
– Biến file trong C là các con trỏ tới cấu trúc FILE
FILE *myfile;
Trang 13
Mở File
• Mở file: tạo ra một mối liên kết giữa hệ điều hành (tên file) và
chương trình C (biến file)
– Hàm thư viện fopen
– Xác định tham số “r” để đọc file và “w” để ghi file
• Chú ý “r” chứ không phải ‘r’
Trang 14
Ví Dụ Về Mở File
/*usually done only once in a program*/
/*usually done near beginning of program*/
Trang 15
Ví Dụ Về Đóng File
• Thường chỉ được làm một lần trong chương trình.
• Thường được làm cuối chương trình.
• Bạn cần phải đóng các file dữ liệu nếu không dữ liệu có thể sẽ
bị mất.
FILE *infilep; /*file variable*/
...
infilep = fopen(“Student_Data”, “r”);
.../*process the file */
.../*when completely done with the file:*/
fclose(infilep);
Trang 16
Kết Thúc File (EOF)
• Được định nghĩa trong file stdio.h
• #define EOF (một giá trị âm nào đó)
– Thông thường là -1
– Các hàm thư viện xuất/nhập dùng EOF để biểu thị kết thúc file
– Chương trình của bạn cùng có thể dùng EOF
• Chú ý: EOF là trạng thái, không phải là giá trị đầu vào.
Trang 17
Bốn Hàm Xuất/Nhập File Cơ Bản
• fopen và fclose: đã nêu ở các trang trước
• fscanf: giống như hàm scanf, tuy nhiên tham số thứ nhất là một
biến file
status = fscanf(filepi, “%...”, &var,...);
/* fscanf returns EOF on end of file */
• fprintf: giống như hàm printf, tuy nhiên tham số thứ nhất là
một biến file
fprintf(filepo, “%...”, var,...);
• File phải được mở trước khi bạn gọi hàm fscanf hoặc fprintf
Trang 18
Các thao tác với file
• Khi file được mở, thì các hoạt động cho file sẽ diễn ra từ đầu
đến hết file
• 4 kiểu cơ bản khi làm việc với file
– Từng ký tự (Character by character).
– Từng dòng (Line by line).
– Định dạng vào ra (Formatted IO).
– Vào ra nhị phân (Binary IO).
19
Gửi ký tự ra
• Các hàm gửi ký tự ra:
int fputc(int c, FILE *fp);
int putc(int c, FILE *fp);
int putchar(int c);
• putchar(c) tương đương putc(c, stdout).
• putc()và fputc() là hoàn toàn giống nhau.
• Giá trị trả vể:
– Nếu thành công: ký tự được viết vào
– Nếu lỗi: EOF.
20
Đọc ký tự vào
• Hàm đọc ký tự vào:
int fgetc(FILE *fp);
int getc(FILE *fp);
int getchar(void);
• getchar() tương đương với getc(stdin).
• getc() và fgetc() giống nhau.
• Giá trị trả về:
– Thành công: ký tự tiếp theo trong luồng dữ liệu
– Nếu lỗi: EOF.
– Nếu hết file: EOF.
• Phân biệt EOF, bằng lời gọi hàm feof() or ferror().
• Bạn có thể đẩy ký tự trỏ lại luồng dữ liệu vào thông qua hàm ungetc().
int ungetc(int c, FILE *fp);
21
Định dạng vào ra IO
int fprintf(FILE *fp, const char *format, ...);
int fscanf(FILE *fp, const char *format, ...);
22
Nhập vào dòng
• Đọc cả dòng vào như sau:
char *fgets(char *buf, int max, FILE *fp);
• Giá trị trả về
– Đọc vào nhiều nhất là max-1 ký tự từ file.
– Đọc cả ký tự a \n.
– Kiểm tra cả hết file và lỗi
• Giá trị trả về:
– Nếu thành công: con trỏ tới buf. Lưu ý fgets()tự động thêm \0 vào cuối
xâu.
– Nếu dòng cuối file: NULL.
– Gặp lỗi: NULL.
• Sử dụng feof() và ferror() để xác định nếu lỗi
23
Gửi dòng ký tự ra file
• Chuỗi ký tự có thể gửi ra file như sau
int fputs(const char *str, FILE *fp);
24
Vào ra nhị phân
• Khi đọc và ghi file nhị phân, chương trình làm việc trực tiếp với
đối tượng mà không chuyển đổi đối tượng này thành xâu ký tự
• Vào ra nhị phân gồm:
size_t fread(void *ptr, size_t size, size_t nobj, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE
*fp);
25
Các thao tác khác với file
• C cung cấp các hàm khác để có thể làm việc với file không
thông qua tuần tự.
• 3 hàm cơ bản:
long ftell(FILE *fp);
int fseek(FILE *fp, long offset, int from);
void rewind(FILE *fp);
26
Xây Dựng Ứng Dụng Với File
• Với các hàm fopen, fclose, fscanf và fprintf bạn có thể viết rất
nhiều ứng dụng liên quan đến file
• Bạn có thể gặp nhiều lỗi và các trường hợp ngoại lệ khi dùng
file
– Một chương trình bền vững phải kiểm soát được lỗi
– Bạn sẽ dần học được kỹ năng này
Trang 27
Đối số theo dòng lệnh
• C cho phép nhập lệnh ngay từ lời gọi chương trình command-line
arguments
• Cấu trúc hàm hàm main có thể main():
int main(void)
int main(int argc, char *argv[])
• argc argument count và argv argument vector.
• argc là số lượng đối số trong dòng lệnh (bao gồm cả tên chương trình).
Các lệnh cách nhau bởi dấu cách
• Argv là con trỏ tới mảng của các xâu, với mỗi xâu là một lệnh. Độ dài
của mảng là argc + 1 vì argv[argc]= NULL.
28
Ví Dụ Sao Chép File
/* Problem: copy an input file to an output file */
/* Technique: loop, copying one char at a time until
EOF, files must already be open before this */
status = fscanf(infilep, “%c”, &ch);
while (status != EOF) {
fprintf(outfilep, “%c”, ch);
status = fscanf(infilep, “%c”, &ch);
}
printf(“File copied.\n”);
fclose(infilep);
fclose(outfilep);
Trang 29
Ví Dụ Sao Chép File
/* Many C programmers use this style */
...
while (fscanf(infilep, “%c”, &ch) != EOF)
fprintf(outfilep, “%c”, ch);
printf(“File copied.\n”);
fclose(infilep);
fclose(outfilep);
Trang 30
Ví Dụ Truy Vấn Cơ Sở Dữ Liệu
#include <stdio.h>
int main(void) {
FILE *inp, *outp;
int age, j; Equivalent query in SQL
char name[20], ssn[9], ch; database language:
inp = fopen(“db_file”, “r” );
outp = fopen(“result_file”, “w”);
/* loop till the end-of-file */ SELECT NAME, SSN
while (fscanf(inp, “%c”, &name[0]) != EOF) { FROM DB_FILE
/* read name, ssn, age */ WHERE AGE > 20;
for (j = 1; j < 20; j++)
fscanf(inp, “%c”, &name[j]);
for (j = 0; j < 9; j++)
fscanf(inp, “%c”,&ssn[j]);
fscanf(inp, “%d”, &age);
/* read line feed character */
fscanf(inp, “%c”, &ch);
/* copy name, ssn to output if age > 20 */
if (age > 20) {
for (j = 0; j < 20; j++)
fprintf(outp, “%c”, name[j]);
for (j = 0; j < 9; j++)
fprintf(outp, “%c, ssn[j]);
fprintf(outp, ”\n”);
}
}
fclose(inp); fclose(outp);
return (0);
}
Trang 31
Ví Dụ Mở Rộng Tab
#include <stdio.h>
int main(void) {
FILE *infilep, *outfilep; Input: a b \t c
char ch; d \t e f
int column = 0; Output: a b c
/* Open input and output files */ d ef
infilep = fopen(“prog.c”, “r”);
outfilep = fopen(“tabless-prog.c”, “w”);
/* process each input character */
while (fscanf(infilep, “%c”, &ch) != EOF){
if (ch == ‘\n’ || ch == ‘\r’) {
/* end of line: reset column counter */
column = 0;
fprintf(outfilep, “%c”, ch);
} else if (ch == ‘\t’) {
/* tab: output one or more spaces, */
/* to reach the next multiple of 8. */
do {
fprintf(outfilep, “%c”, ‘ ‘) ;
column++;
} while ((column % 8) != 0);
} else {
/* all others: count it, and copy it out */
column ++;
fprintf(outfilep, “%c”, ch);
}
}
fclose(infilep); fclose(outfilep);
return 0;
} Trang 32
Ví Dụ Nối Hai File Có Thứ Tự
#include <stdio.h>
#define MAXLINE 10000 /*ASSUMES no line longer*/
int main(void) {
FILE *in1p, * in2p, *outp;
char buffer1[MAXLINE], buffer2[MAXLINE];
char *stat1, *stat2;
in1p = fopen(“sorted-file1”, “r”);
in2p = fopen(“sorted-file2”, “r”);
outp = fopen(“merged-file”, “w”);
stat1 = fgets(buffer1, MAXLINE, in1p);
stat2 = fgets(buffer2, MAXLINE, in2p);
while (stat1 != NULL && stat2 != NULL) {
if (strcmp(buffer1, buffer2) < 0) {
fprintf(outp, “%s”, buffer1);
stat1 = fgets(buffer1, MAXLINE, in1p);
} else {
fprintf(outp, “%s”, buffer2);
stat2 = fgets(buffer2, MAXLINE, in2p);
}
}
while (stat1 != NULL) {
fprintf(outp, “%s”, buffer1);
stat1 = fgets(buffer1, MAXLINE, in1p);
}
while (stat2 != NULL) {
fprintf(outp, “%s”, buffer2);
stat2 = fgets(buffer2, MAXLINE, in2p);
}
fclose(in1p); fclose(in2p); fclose(outp);
return 0;
} Trang 33