C/C++ 文件寫入讀取

C 文件基本操作

1. 文件基本寫入

要想實現一個文件的基本寫入需要用到下面三個函數(基本流程):

步驟 函數 說明 備註
第一步 fopen() 打開文件 fopen(“文件路徑+文件名”, “模式(wb/ab/rb)”) 返回FILE* fp指針
第二步 fwrite() 寫入文件 fwrite(“寫入的內容”, 1, “內容的大小(字節)”, “FILE* 指針對象”);
第三步 fclose() 關閉文件 fclose(“FILE* 指針對象”); 對文件進行寫入/讀取之後都需要關閉文件
  • fopen()函數中常用的三種模式: wb/ab/rb
    • wb模式:寫入文件,寫入的時候每次都會清空文件原有的內容
    • ab模式:寫入文件,每次寫入內容都是追加到原文件的內容之後(不會清空原文件內容)
    • rb模式:讀取文件

示列:

wb模式寫入

#include<stdio.h>
#include<stdlib.h>

// 文件寫入:使用wb模式(清空內容之後再寫入)
void file_fwrite_wb();

int main() {

	file_fwrite_wb();
	
	return 0;
}

// 文件寫入:使用wb模式(清空內容之後再寫入)
void file_fwrite_wb() {

	// 文件路徑
	const char fileName[] = "F:/C++/file/a.txt";

	// 打開文件
	FILE* fp = fopen(fileName, "wb");

	if (fp == NULL) {
		printf("文件打開失敗,文件路徑不存在\n ");
		return;
	}
	
	// 要寫入的字符
	char buf[] = "hello,world";

	// 返回寫入的字節數
	int res = fwrite(buf, 1, 11, fp);

	// 關閉文件
	fclose(fp);
}

ab模式只需要把wb替換成ab就可以了,其它代碼一樣

// 打開文件
FILE* fp = fopen(fileName, "ab");

以字符串的方式寫入int類型數據

#include<stdio.h>
#include<stdlib.h>

// 以字符串的方式寫入int類型數據
void file_fwrite_str();

int main() {
	file_fwrite_str();
	return 0;
}

// 以字符串的方式寫入int類型數據
void file_fwrite_str() {

	// 文件路徑
	const char fileName[] = "F:/C++/file/a.txt";

	// 打開文件
	FILE* fp = fopen(fileName, "wb");

	if (fp == NULL) {
		printf("文件打開失敗,文件不存在\n ");
		return;
	}

	// 要寫入的字符
	int buf[3] = { 0xA1, 0xB1, 0xC1 };

	for (int i = 0; i < 3; i++)
	{
		char text[12];
		// 加了一個,號分割數組的存儲
		sprintf(text, "%d,", buf[i]);
		fwrite(text, 1, strlen(text), fp);
	}

	// 關閉文件
	fclose(fp);
}

2. 文件讀取

2.1 讀取全部內容

#include<stdio.h>
#include<stdlib.h>

// 讀取文件內容(讀取全部內容)
void read_all_content();

int main() {

	read_all_content();
	
	return 0;
}

// 讀取文件內容(讀取全部內容)
void read_all_content() {

	// 文件路徑
	const char fileName[] = "F:/C++/file/a.txt";

	// 打開文件
	FILE* fp = fopen(fileName, "rb");

	if (fp == NULL) {
		printf("文件打開失敗,文件不存在\n ");
		return;
	}

	// 第一種方式讀取(直接讀取):
	char buf[12];
	// 我的文件內容爲: 161,177,193,
	int n = fread(buf, 1, 12, fp);
	// 可調試+斷點,打開局部變量窗口查看buf的值
	fclose(fp);
}

2.2 順序讀取

#include<stdio.h>
#include<stdlib.h>

// 順序讀取
void read_buf_content();

int main() {

	read_buf_content();
	
	return 0;
}

// 順序讀取
void read_buf_content() {
	// 文件路徑
	const char fileName[] = "F:/C++/file/a.txt";

	// 打開文件
	FILE* fp = fopen(fileName, "rb");

	if (fp == NULL) {
		printf("文件打開失敗,文件路徑不存在\n ");
		return;
	}

	// 我的文件內容爲: 161,177,193, 一共12個字節
	// 所以我創建一個字節緩衝區(4個字節),下面分3次讀取
	char buf[4];

	// 順序讀取(文件流):
	// 如果文件很大,則無法一次性讀完,可以採用順序讀取,每次讀取一定長度,直到讀取完
	while (! feof (fp))
	{
		// 每次讀取4個字節
		int n = fread(buf, 1, 4, fp);
		if (n > 0) { // n 讀取到字節數
			printf("read %d bytes \n", n);
			// 下一次讀取會覆蓋上次讀取(buf緩衝區)的內容,斷點+調試
		}
	}

	// 注意: feof()函數是檢測文件是否已經讀取到末尾
	fclose(fp);
}

3. 隨機訪問

隨機訪問:比如MP3、MP4等文件拖動快進時就是隨機讀取( fseek()函數))
功能 示列
調到第100個字節位置 fseek(fp, 100, SEEK_SET);
調到倒數100個字節的位置 fseek(fp, 100, SEEK_END);
調到當前位置往前100個字節 fseek(fp, -100, SEEK_CUR);
調到當前位置的往後100個字節 fseek(fp, 100, SEEK_CUR);
#include<stdio.h>
#include<stdlib.h>

// 隨機訪問讀取
void random_read_content();

int main() {

	random_read_content();
	
	return 0;
}

// 隨機訪問讀取
void random_read_content() {
	
	// 文件路徑+文件名
	const char fileName[] = "F:/C++/file/a.txt";

	FILE* fp = fopen(fileName, "rb");

	if (fp == NULL) {
		printf("文件打開失敗,文件路徑不存在\n ");
		return;
	}

	// 我的文件內容爲: 161,177,193, 一共12個字節
	// 讀取文件內容的buf緩衝區
	unsigned char buf[4];

	// 從第8個字節開始讀取,讀取四個
	fseek(fp, 8, SEEK_SET);
	// n 返回的字節數
	int n = fread(buf, 1, 4, fp);

	fclose(fp);
}

4. 文本形式存儲與讀寫

4.1 以文本形式存儲(按行存儲,就是在結尾加一個\n)

#include<stdio.h>
#include<stdlib.h>

// 以文本形式存儲(按行存儲,就是在結尾加一個\n)
void file_fwrite_text();

int main() {

	file_fwrite_text();
	
	return 0;
}

// 以文本形式存儲(按行存儲,就是在結尾加一個\n)
void file_fwrite_text() {

	// 文件路徑+文件名
	const char fileName[] = "F:/C++/file/text.txt";

	FILE* fp = fopen(fileName, "wb");

	if (fp == NULL) {
		printf("文件打開失敗,文件路徑不存在\n ");
		return;
	}

	// 比如我需要保存服務器的IP和端口號到配置文件(按行存儲)
	char ip[] = "192.169.0.1";
	int port = 8080;

	// 定義一行的緩衝區
	char line[256];

	// 保存ip
	sprintf(line, "ip=%s\n", ip);
	fwrite(line, 1, strlen(line), fp);
	// 保存端口號
	sprintf(line, "port=%d\n", port);
	fwrite(line, 1, strlen(line), fp);

	fclose(fp);
}

4.2 按行讀取、解析數據

使用fgets()函數,內部會檢查,如果都到\n時,停止讀取。返回實際讀取的字節

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

// 按行讀取、解析數據(fgets()函數,內部會檢查,如果都到\n時,停止讀取。返回實際讀取的字節)
void read_line_content();

int main() {

	read_line_content();
	
	return 0;
}

// 按行讀取、解析數據
void read_line_content() {

	// 文件路徑+文件名
	const char fileName[] = "F:/C++/file/text.txt";

	FILE* fp = fopen(fileName, "rb");

	if (fp == NULL) {
		printf("文件打開失敗,文件不存在\n ");
		return;
	}
	// 我的文本數據
	//ip=192.169.0.1
	//port=8080


	// 按行讀取數據的緩衝區(一行最多512個字節)
	char buf[512];

	// feof()函數是檢測文件是否已經讀取到末尾
	while (! feof(fp))
	{
		char* line = fgets(buf, 512, fp);
		if (line) {

			//printf("got: %s \n", line);
			// 解析字符串 (sscanf()只適提取數字,不適合字符串), 需要自己解析(比較麻煩)

			// 字符串爲指定char的下標
			int eq = 0;
			
			// 獲取字符串長度
			int len = strlen(line);

			// 動態創建新的字符串對象
			char* copy = (char*)malloc(len + 1);
			// copy字符創的下標
			int count = 0;
			
			for (int i = 0; i < len; i++)
			{
				char ch = line[i];
				// 等於換行符的時候跳過
				if (ch == '\n') continue;
				// 如果當下邊的char等於'='是。獲取'='的下標,賦值給eq
				if (ch == '=')
					eq = i;
				if (eq && i > eq) {
					copy[count] = line[i];
					count++;
				}
			}
			// 字符串結束(爲什麼len - (eq + 1) -1)
			// 因爲len是原本字符串的長度,我們截取之後長度不夠; 
			// eq + 1 = 下標是從0開始的; 爲什麼還要 -1呢, '\n'也算一個字節;
			copy[len - (eq + 1) - 1] = 0;
			// 解析之後賦值給當前的line
			strcpy(line, copy);
			// 釋放
			free(copy);

			printf("read: %s \n", line);
		}
	}
	
	fclose(fp);
}

寫入到文本的數據:
寫入到文本的數據
解析文本數據:
解析文本數據

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章