# File I/O
[toc]
## 開啟檔案
```c=
FILE *fptr;
fptr = fopen("filename.txt" , "mode");
```
### **FILE \*fptr**
- 宣告一個變數,名稱為fptr,類型為FILE
- \* (pointer) 代表fptr指向檔案存取的位址
### **filename.txt**
- 第一個參數代表我們要開啟的檔案,
- 預設路徑為cpp source code存放位址
- 回傳值為該檔案的位址
### **mode**
- 代表我們想要對該檔案執行的動作類型
- 常見類型:
| mode | meaning |
|:-------- |:--------|
| "r" | **read:** 開啟檔案作為輸入來源 |
| "w" | **write:** 建立一個新檔案儲存輸出資訊,如果同樣檔名的檔案已經存在,則該檔案內容會被捨棄並被視為一個empty file |
| "a" | **append:** 開啟一個檔案做為輸出並在該檔案的最後一行新增輸出資訊。如果該檔案不在則會新增一個檔案 |
## 處理檔案
### 讀取檔案中的字
跟`scanf()`類似,只不過需要多一個參數:file pointer
- fscanf( )
- ``fscanf(file pointer, “datatype”, data variable)``
- 從檔案中讀取資料並存在指定類型的變數中
- fgetc( )
- ``variable = fgetc(filepointer)``
- 讀取目前filepointer所在位址的一個字元,並回傳該字元
- fgets( )
- ``fgets(string, num, file pointer)``
- 讀取目前filepointer所在位址的一串字元,直到讀取了``num-1``個字元為止,並將其作為string儲存
**Example**:
```c=
int main()
{
FILE *fptr;
fptr = fopen("input.txt","r");
int num1 = 0, num2 = 0;
char c1, c2;
char str[5];
// check whether the file is open
if(fptr != NULL)
{
fscanf(fptr, "%d %d", &num1, &num2);
printf("%d %d\n", num1, num2);
c1 = fgetc(fptr);
c2 = fgetc(fptr);
printf("%c %c\n", c1, c2);
fgets(str, 5 , fptr);
printf("%s\n", str);
}
else
{
printf("fail to open 'input.txt'.");
}
fclose(fptr);
}
```
### 在檔案上寫字
跟`printf()`類似,只不過需要多一個參數:file pointer
- fprintf()
- `fprintf(file pointer, “datatype”, data variable)`
- 在檔案上pointer的位址輸出標準字串
- fputc()
- `fputc(char, file pointer)`
- 在檔案上pointer的位址輸出一個字元
- fputs()
- `fputs(string, file pointer)`
- 在檔案上pointer的位址輸出一個字串
**Example**:
```c=
int main()
{
FILE *fptr;
fptr = fopen("output.txt","w");
int num 25;
// check whether the file is open
if(fptr != NULL)
{
fprintf(fptr,"Below are your message:\n%d\n",num);
fputc('~',fptr);
fputs("I want to sleep all day.",fptr);
}
else
{
printf("fail to open 'output.txt'.");
}
fclose(fptr);
}
```
### 重新設置字串位置指標
- fseek()
- `fseek(file pointer, offset, reference position)`
- 根據參考位址以及數值,重新設定file pointer位址
| reference position | meaning |
|:------------------- |:-------- |
| SEEK_SET | 檔案的開頭 |
| SEEK_CUR | 檔案目前的位址 |
| SEEK_END | 檔案目前的尾端 |
**Example**:
- 檔案:
<img style="margin:20px auto;padding:1px;border:1px #eee;width:20%;" src="https://i.imgur.com/lvJv3Nk.png" />
- 未使用fseek()
```c=
int main()
{
FILE *fptr;
fptr = fopen("input.txt","r");
char c1;
// check whether the file is open
if(fptr != NULL)
{
while(c1 = fgetc(fptr) != EOF)
{
c1 = fgetc(fptr);
printf("%c", c1);
}
}
}
```
- 使用fseek()
```c=
int main()
{
FILE *fptr;
fptr = fopen("input.txt","r");
char c1;
// check whether the file is open
if(fptr != NULL)
{
while(c1 = fgetc(fptr) != EOF)
{
fseek(fptr,-1,SEEK_CUR);
c1 = fgetc(fptr);
printf("%c", c1);
}
}
}
```
- 輸出:左:未使用`fseek( )`;右:使用`fseek( )`
<img style="margin:28px auto;padding:1px;border:5px #eee;width:40%;" src="https://i.imgur.com/xr6p7ab.png" /> <img style="margin:28px auto;padding:1px;border:5px #eee;width:36%;" src="https://i.imgur.com/BDD8cvX.png" />
## 關閉檔案
### fclose(fptr)
- 關閉檔案
- 釋出記憶體空間
- 不把檔案關閉的話可能會造成fprintf()的異常
:::info
:bulb: 同時開的檔案數量有限,因此我們需要關閉不必要的檔案以節省記憶體空間
:::
:::success
## :bulb:Exercise 1.
```c=
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* fptr;
fptr = fopen("input.txt", "r");
int n=0, m=0;
char arr[50][50];
if (fptr != NULL)
{
fscanf(fptr, "%d %d", &n, &m);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
arr[i][j] = 'H';
}
}
int k;
fscanf(fptr, "%d", &k);
int r, c;
for (int i = 0; i < k; i++)
{
fscanf(fptr, "%d %d", &c, &r);
arr[c][r] = ' ';
}
}
else
{
printf("fail to open 'input.txt'.");
}
FILE* fptr2;
fptr2 = fopen("output.txt", "w");
if (fptr2 != NULL)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
fprintf(fptr2, "%c", arr[i][j]);
}
fputc('\n', fptr2);
}
}
else
{
printf("fail to open 'output.txt'.");
}
fclose(fptr2);
}
```
:::
:::info
## :bulb:Homework 1.
```c=
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE* fptr;
FILE* fptr2;
fptr = fopen("input.txt", "r");
fptr2 = fopen("output.txt", "w");
int num;
char spec[15][15],input;
scanf("%d", &num);
for (int i = 0; i < num; i++)
{
scanf("%s", spec[i]);
}
int result = 1;
bool bo = 0;
if (fptr != NULL && fptr2 != NULL)
{
char c;
while (fgetc(fptr) != EOF)
{
char str[15];
fseek(fptr, -1, SEEK_CUR);
for(int j=0 ; j<15 ; j++)
{
c = fgetc(fptr);
if (((int)c >= 65 && (int)c <= 90) || ((int)c >= 97 && (int)c <= 122))
{
str[j] = c;
}
else
{
str[j] = '\0';
if (j == 0)
{
fputc(c,fptr2);
break;
}
for (int k = 0; k < num; k++)
{
result = strcmp(str, spec[k]);
if (result == 0)
{
break;
}
}
if (result == 0)
fprintf(fptr2, "***%c", c);
else
fprintf(fptr2, "%s%c", str, c);
break;
}
}
}
}
else
{
printf("Failed to open 'input.txt' or 'output.txt'.");
}
fclose(fptr);
fclose(fptr2);
}
```
:::