第1節是筆者基於公司的「祖傳」C語言操作模板上做相應修改的程式,當做自己以後使用C語言檔案操作的模板。
第2節與第3節是筆者之前需要配合團隊內的小夥伴做數據轉換,他需要我將儲存在.txt檔案內的字元數據(十六進制)轉換爲二進制,也需要我將.Bin檔案內的二進制數據轉換爲字元數據(十六進制)。當然這兩節程式有很大的優化空間,弊端爲每次讀取數據的量太小,需要頻繁IO操作,導致執行速度變得很慢。解決方法爲使用malloc函數一次性將檔案的內容讀取到記憶體空間上,可大幅提高程式的執行速度。
第4節是筆者一直很好奇32位元操作系統下的C語言的數據型別所佔空間進行測試的例子,方便自己在後面的開發中準確的使用數據型別,不至於讓數據小而空間大,或者數據大而空間小。
第5節是筆者想通過C語言爲工程專案中修改組態檔中的參數,通過匹配組態檔中指定的變數去替換參數。但該節程式最後並未用於工程專案中,筆者想表達,C語言實現真的好麻煩,這就是更高階的程式語言強大之處。
第6節是筆者想爲嵌入式Linux產品的開機Logo動態讀取指定路徑下的.ppm圖片,原本考慮修改Kernel中顯示Logo部分,將圖片的數據寫入相應的地方。但後面在內核原始碼中找不到內核編譯時怎麼將logo_linux_clut224.ppm編譯爲logo_linux_clut224.c的方法,不清楚.ppm檔案是怎麼將數據轉化到struct linux_logo結構體中的clut和data成員,後面不得不放棄這種想法。但也讓筆者改變思路,讓驅動程式讀取指定路徑下的組態檔,讓驅動定向執行。
第7節爲應用層的常規檔案操作。
第8節爲獲取掛載在檔案系統下節點的儲存情況。
第9節摘抄自《Linux程式設計 第4版》中第3、4節的C語言進行檔案/目錄、系統操作
第10節爲記錄程式執行的時間
下面 下麪的程式參考了網上的許多例子,測試可用,若需要使用,需要修改部分參數。
// 編譯與執行命令:
// gcc xxxx.c -o xxxx
// ./xxxx
#include <stdio.h>
#include <string.h>
int OpenFile(char *ReadFile, char *WriteFile, unsigned int *FileLength,
FILE **fpRead, FILE **fpWrite);
void CloseFile(FILE *fpRead, FILE *fpWrite);
int FileOperation(unsigned int FileLength, FILE *fpRead, FILE *fpWrite);
int main(int argc, char *argv[])
{
char ReadFile[] = "ReadFile.txt";
char WriteFile[] = "WriteFile.txt";
FILE *fpRead = NULL, *fpWrite = NULL;
unsigned int FileLength = 0;
int ret = 0;
// 開啓需要讀、寫的檔案
ret = OpenFile(ReadFile, WriteFile, &FileLength, &fpRead, &fpWrite);
if(ret < 0)
{
return 0;
}
// 檔案操作
FileOperation(FileLength, fpRead, fpWrite);
// 關閉檔案
CloseFile(fpRead, fpWrite);
return 0;
}
int OpenFile(char *ReadFile, char *WriteFile, unsigned int *FileLength,
FILE **fpRead, FILE **fpWrite)
{
// 開啓需要讀的檔案
*fpRead = fopen(ReadFile, "r+");
if(*fpRead == NULL)
{
printf("open %s error \n", ReadFile);
return -1;
}
// 開啓需要寫的檔案
*fpWrite = fopen(WriteFile, "wb");
if(*fpWrite == NULL)
{
printf("open %s error \n", WriteFile);
fclose(*fpRead);
return -1;
}
// 將讀檔案指針定位於檔案的末尾處,獲取檔案大小
fseek(*fpRead, 0, SEEK_END);
*FileLength = ftell(*fpRead);
printf("FileLength = %dB (%.2fMB) \n", *FileLength,
((double)*FileLength / (1024 * 1024)));
return 1;
}
void CloseFile(FILE *fpRead, FILE *fpWrite)
{
fclose(fpRead);
fclose(fpWrite);
}
int FileOperation(unsigned int FileLength, FILE *fpRead, FILE *fpWrite)
{
unsigned int i = 0;
unsigned char Array[3];
unsigned char CharLen = 2;
// 將讀、寫檔案指針指向檔案頭
fseek(fpRead, 0, SEEK_SET);
fseek(fpWrite, 0, SEEK_SET);
// 進行檔案讀寫
for(i = 0; i < FileLength; i += 2)
{
if((i != 0) && (i % 16 == 0))
{
fwrite("\n", sizeof(unsigned char), 1, fpWrite);
}
memset(Array, '\0', sizeof(Array));
fread(Array, sizeof(unsigned char), CharLen, fpRead);
fwrite(Array, sizeof(unsigned char), CharLen, fpWrite);
fwrite(" ", sizeof(unsigned char), 1, fpWrite);
}
return 1;
}
// 位於stdio.h,筆者在Linux底下找不到定義FILE結構體,只在Visual Studio內找到了定義
// 不同編譯器下的FILE結構體定義不一樣
// FILE結構是間接地操作系統的檔案控制塊 (FCB)來實現對檔案的操作
#ifndef _FILE_DEFINED
struct _iobuf {
char *_ptr; // 檔案輸入的下一個位置
int _cnt; // 當前緩衝區的相對位置
char *_base; // 指基礎位置(即是檔案的其始位置)
int _flag; // 檔案標誌
int _file; // 應該是檔案描述符,進入開啓檔案列表索引的整數
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
#define _FILE_DEFINED
#endif
// 編譯與執行命令:
// gcc xxxx.c -o xxxx -lm
// ./xxxx
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
char FilePath[] = "/mnt/hgfs/XXXX/";
char ReadFile[] = "File";
char WriteFile[] = "FileConvert";
char TxtUnit[] = ".txt";
char BinUnit[] = ".bin";
char ReadFilePath[80], WriteFilePath[80];
char ClearWriteFileCmd[160], TxtToJPEGCmd[160];
unsigned int FileLength = 0;
char array[4];
unsigned char DataBin = 0;
unsigned char DataTemp = 0;
int i = 0, j = 0;
FILE *fpRead = NULL, *fpWrite = NULL;
unsigned int NumRead = 0, NumWrite = 0;
unsigned int DataCount = 0;
int CharLen = 2; // 每次讀取檔案的兩個字元
memset(ReadFilePath, 0, 80 * sizeof(char));
memset(WriteFilePath, 0, 80 * sizeof(char));
memset(ClearWriteFileCmd, 0, 160 * sizeof(char));
memset(TxtToJPEGCmd, 0, 160 * sizeof(char));
sprintf(ReadFilePath, "%s%s%s", FilePath, ReadFile, TxtUnit);
sprintf(WriteFilePath, "%s%s%s", FilePath, WriteFile, TxtUnit);
sprintf(ClearWriteFileCmd, "dd if=/dev/null of=%s%s%s", FilePath, WriteFile, TxtUnit);
sprintf(TxtToJPEGCmd, "mv %s%s%s %s%s%s", FilePath, WriteFile, TxtUnit, FilePath, WriteFile, BinUnit);
// 開啓需要讀的檔案
fpRead = fopen(ReadFilePath , "r+");
if(fpRead == NULL)
{
printf("Open %s error \n", ReadFilePath);
return -1 ;
}
// 開啓需要寫的檔案
fpWrite = fopen(WriteFilePath , "wb");
if(fpWrite == NULL)
{
printf("Open %s error \n", WriteFilePath);
return -1 ;
}
printf("Open %s Success \n", ReadFilePath);
printf("Open %s Success \n", WriteFilePath);
system(ClearWriteFileCmd);
// 定位於檔案的末尾處,獲取檔案大小
fseek(fpRead, 0, SEEK_END);
FileLength = ftell(fpRead);
printf("FileLength = %d (%.2fK %.2fM) \n", FileLength, ((double)FileLength / 1024), ((double)FileLength / 1024 / 1024));
// 將檔案指針指向檔案頭
fseek(fpRead, 0, SEEK_SET);
fseek(fpWrite, 0, SEEK_SET);
NumRead = 0;
NumWrite = 0;
while(NumRead < FileLength)
{
memset(&array, '\0', 4 * sizeof(char));
fseek(fpRead, NumRead, SEEK_SET);
fread(array, sizeof(char), CharLen, fpRead);
// 判斷取出的值是否爲換行符、空格、製表符、回車符
//if((array[0] == '\n') || (array[0] == ' ') || (array[0] == '\t') || (array[0] == '\r'))
if(array[0] <= ' ')
{
NumRead += (1 * sizeof(char));
continue ;
}
NumRead += (CharLen * sizeof(char));
// 下面 下麪這句話不能寫,會大大拖慢速度,執行速度降低150倍左右
//fseek(fpWrite, NumWrite, SEEK_SET);
// 字元轉爲數據
for(DataBin = 0 , j = 0 ; j < CharLen ; j ++)
{
DataTemp = array[j] ;
if((DataTemp >= '0') && (DataTemp <= '9')) DataTemp = DataTemp - '0';
else if((DataTemp >= 'a') && (DataTemp <= 'z')) DataTemp = (DataTemp - 'a' + 10);
else if((DataTemp >= 'A') && (DataTemp <= 'Z')) DataTemp = (DataTemp - 'A' + 10);
//DataBin += (DataTemp * pow(16, (CharLen - 1 - j)));
DataBin += (DataTemp << (4 * (CharLen - 1 - j)));
}
fwrite(&DataBin, sizeof(char), 1, fpWrite);
NumWrite += (1 * sizeof(char));
DataCount ++ ;
}
fclose(fpRead);
fclose(fpWrite);
system(TxtToJPEGCmd);
return 0 ;
}
// 編譯與執行命令:
// gcc xxxx.c -o xxxx -lm
// ./xxxx
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <sys/time.h>
int FileConvert(char *FilePath, char *ReadFile, char *WriteFile);
int main(int argc, char *argv[])
{
char FilePath[] = "/mnt/hgfs/Share_Ubuntu/FileDispose/Bin01/";
char FileName[] = "rgb";
char ReadFile[50], WriteFile[50];
unsigned int FileCounter = 1, FileNum = 100;
int ret = 0;
while(FileCounter <= FileNum)
{
memset(ReadFile, 0, sizeof(ReadFile));
memset(WriteFile, 0, sizeof(WriteFile));
sprintf(ReadFile, "%s%02d", FileName, FileCounter);
sprintf(WriteFile, "%sConvert", ReadFile);
FileCounter++;
ret = FileConvert(FilePath, ReadFile, WriteFile);
if(ret < 0)
{
printf("Read and Write %s error \n", ReadFile);
continue;
}
}
return 0 ;
}
int FileConvert(char *FilePath, char *ReadFile, char *WriteFile)
{
FILE *fpRead = NULL, *fpWrite = NULL;
int CharLen = 1; // 每次讀取檔案的一個字元
unsigned char array[4];
unsigned char DataBin = 0;
unsigned char DataTemp = 0;
int i = 0, j = 0;
unsigned int DataCount = 0;
char TxtUnit[] = ".txt", JpgUnit[] = ".jpg", BinUnit[] = ".bin";
char ReadFilePath[80], WriteFilePath[80];
char ClearWriteFileCmd[160];
memset(ReadFilePath, 0, sizeof(ReadFilePath));
memset(WriteFilePath, 0, sizeof(WriteFilePath));
memset(ClearWriteFileCmd, 0, 160 * sizeof(char));
sprintf(ReadFilePath, "%s%s%s", FilePath, ReadFile, BinUnit);
sprintf(WriteFilePath, "%s%s%s", FilePath, WriteFile, TxtUnit);
sprintf(ClearWriteFileCmd, "dd if=/dev/null of=%s > /dev/null 2>1", WriteFilePath);
// 開啓需要讀的檔案
fpRead = fopen(ReadFilePath , "r+");
if(fpRead == NULL)
{
printf("Open %s error \n", ReadFilePath);
return -1 ;
}
// 開啓需要寫的檔案
fpWrite = fopen(WriteFilePath , "wb");
if(fpWrite == NULL)
{
printf("Open %s error \n", WriteFilePath);
return -1 ;
}
system(ClearWriteFileCmd);
printf("Open %s Success \n", ReadFilePath);
printf("Open %s Success \n", WriteFilePath);
unsigned int FileLength = 0;
// 定位於檔案的末尾處,獲取檔案大小
fseek(fpRead, 0, SEEK_END);
FileLength = ftell(fpRead);
printf("(%s) FileLength = %d B (%.2f KB, %.2f MB) \n", ReadFile,
FileLength,
((double)(FileLength >> 10)),
((double)(FileLength >> 20)));
// 將檔案指針指向檔案頭
fseek(fpRead, 0, SEEK_SET);
fseek(fpWrite, 0, SEEK_SET);
unsigned int NumRead = 0, NumWrite = 0;
while(NumRead < FileLength)
{
if((NumRead != 0) && (NumRead % 3 == 0))
{
fwrite(" ", sizeof(char), 1, fpWrite);
}
memset(&DataBin, '\0', sizeof(DataBin));
memset(array, '\0', sizeof(array));
fread(&DataBin, sizeof(unsigned char), CharLen, fpRead);
NumRead += (CharLen * sizeof(unsigned char));
array[0] = (DataBin & 0xF0) >> 4; // 提取十位
array[1] = (DataBin & 0x0F) >> 0; // 提取個位
// printf("DataBin = 0x%X, array[0] = 0x%X, array[1] = 0x%X \n", DataBin, array[0], array[1]);
// 二進制轉換爲字元的計算
for(j = 0 ; j < 2 ; j ++)
{
if((array[j] >= 0x0) && (array[j] <= 0x9)) array[j] = array[j] + '0';
else if((array[j] >= 0xA) && (array[j] <= 0xF)) array[j] = array[j] - 0xA + 'A';
}
fwrite(&array, sizeof(char), 2, fpWrite);
}
fclose(fpRead);
fclose(fpWrite);
}
當前目錄的檔案結構:
tree test/
test/
├── 1.h
├── a.c
├── b.c
├── c.c
└── Makefile
#ifndef __1_H
#define __1_H
#include <stdio.h>
#include <float.h>
#include <limits.h>
struct sData{
unsigned int uint32_data_1;
unsigned long long uint64_data_1;
unsigned char uint8_data_1;
unsigned char uint8_data_2;
unsigned int uint32_data_2;
unsigned short int uint16_data_1;
unsigned char uint8_data_3;
unsigned int uint32_data_3;
};
int b_fun(void);
int c_fun(void);
#endif
#include <stdio.h>
#include "1.h"
int main(int argc , char* argv[])
{
b_fun();
c_fun();
return 0;
}
#include "1.h"
#include "string.h"
int b_fun(void)
{
printf("\n== b_fun == \n");
printf("\n============ char ============\n");
printf("sizeof(char) = %d \n", sizeof(char)); // 1
printf("sizeof(unsigned char) = %d \n", sizeof(unsigned char)); // 1
printf("sizeof(signed char) = %d \n", sizeof(signed char)); // 1
printf("\n============ short int ============\n");
printf("sizeof(short int) = %d \n", sizeof(short int)); // 2
printf("sizeof(unsigned short int) = %d \n", sizeof(unsigned short int)); // 2
printf("sizeof(signed short int) = %d \n", sizeof(signed short int)); // 2
printf("\n============ int ============\n");
printf("sizeof(int) = %d \n", sizeof(int)); // 4
printf("sizeof(unsigned int) = %d \n", sizeof(unsigned int)); // 4
printf("sizeof(signed int) = %d \n", sizeof(signed int)); // 4
printf("\n============ long int ============\n");
printf("sizeof(long int ) = %d \n", sizeof(long int)); // 4
printf("sizeof(unsigned long int) = %d \n", sizeof(unsigned long int)); // 4
printf("sizeof(signed long int) = %d \n", sizeof(signed long int)); // 4
printf("\n============ long long ============\n");
printf("sizeof(long long) = %d \n", sizeof(long long)); // 8
printf("sizeof(signed long long) = %d \n", sizeof(signed long long)); // 8
printf("sizeof(unsigned long long) = %d \n", sizeof(unsigned long long)); // 8
printf("\n============ float ============\n");
printf("sizeof(float) = %d \n", sizeof(float)); // 4
printf("\n============ double ============\n");
printf("sizeof(double) = %d \n", sizeof(double)); // 8
printf("\n\n");
unsigned char uint8_Array[10];
unsigned short int uint16_Array[10];
unsigned int uint32_Array[10];
unsigned long long uint64_Array[10];
float float32_Array[10];
double float64_Array[10];
memset(uint8_Array, '\0', 10 * sizeof(unsigned char));
memset(uint16_Array, '\0', 10 * sizeof(unsigned short int));
memset(uint32_Array, '\0', 10 * sizeof(unsigned int));
memset(uint64_Array, '\0', 10 * sizeof(unsigned long long));
memset(float32_Array, '\0', 10 * sizeof(float));
memset(float64_Array, '\0', 10 * sizeof(double));
printf("sizeof(uint8_Array) = %d \n", sizeof(uint8_Array));
printf("sizeof(uint16_Array) = %d \n", sizeof(uint16_Array));
printf("sizeof(uint32_Array) = %d \n", sizeof(uint32_Array));
printf("sizeof(uint64_Array) = %d \n", sizeof(uint64_Array));
printf("sizeof(float32_Array) = %d \n", sizeof(float32_Array));
printf("sizeof(float64_Array) = %d \n", sizeof(float64_Array));
printf("\n\n");
uint8_Array[0] = '1';
printf("strlen(uint8_Array) = %d \n", strlen(uint8_Array));
printf("\n\n");
struct sData data1;
printf("==~~ sizeof(data1) = %d, add sizeof( ... + ...) = %d ~~== \n", sizeof(data1),
sizeof(data1.uint32_data_1) + sizeof(data1.uint8_data_1) +
sizeof(data1.uint8_data_2) + sizeof(data1.uint32_data_2) +
sizeof(data1.uint16_data_1) + sizeof(data1.uint8_data_3) +
sizeof(data1.uint32_data_3) + sizeof(data1.uint64_data_1)
);
printf("\n\n");
return 1;
}
#include "1.h"
int c_fun(void)
{
printf("\n== c_fun == \n");
printf("\n============ char min max dig ============\n");
printf("CHAR_MIN( char MinValue ) = 0x%X \n", CHAR_MIN);
printf("CHAR_MAX( char MaxValue ) = 0x%X \n", CHAR_MAX);
printf("\n============ int min max dig ============\n");
printf("INT_MIN( int MinValue ) = 0x%X \n", INT_MIN);
printf("INT_MAX( int MaxValue ) = 0x%X \n", INT_MAX);
printf("\n============ float min max dig ============\n"); // %E
printf("FLT_MIN( float MinValue ) = %f \n", FLT_MIN);
printf("FLT_MAX( float MaxValue ) = %f ( %E )\n", FLT_MAX, FLT_MAX);
printf("FLT_DIG( float PrecisionValue ) = %d \n", FLT_DIG);
printf("\n============ double min max dig ============\n");
printf("DBL_MIN( double MinValue ) = %f \n", DBL_MIN);
printf("DBL_MAX( double MaxValue ) = %f ( %E ) \n", DBL_MAX, DBL_MAX);
printf("DBL_DIG( double PrecisionValue ) = %d \n", DBL_DIG);
unsigned long long FloatConvert = 0;
unsigned long long DoubleConvert = 0;
FloatConvert = (unsigned long long)FLT_MAX;
DoubleConvert = (unsigned long long)DBL_MAX;
printf("FloatConvert = 0x%llX, DoubleConvert = 0x%llX \n\n", FloatConvert, DoubleConvert);
unsigned int x = 0x87654321; // 高位爲8,低位爲1
unsigned char *p = (unsigned char *)&x;
int i = 0;
// 數據最左爲高位,最右爲低位
// 小端模式:低地址低位數據,高地址高位數據
// 大端模式:低地址高位數據,高地址低位數據
printf("x = 0x%X \n", x);
for(i = 0; i < 4; i++)
{
printf("0x%X(Addr) = 0x%X \n", (unsigned int)(p + i), p[i]);
}
if(*p == 0x21)
{
printf("Little endian mode!\n\n");
}
else
{
printf("Big endian mode!\n\n");
}
return 1;
}
# 目標檔案的執行平臺: ARM x86 MIPS RISC
#RUN_ARCH := x86
RUN_ARCH := ARM
# 目標檔名,輸入任意你想要的執行檔名
TARGET_FILE := TestSizeof_MF
TARGET_PATH := ~/nfs/
# 編譯工具
ifeq ($(RUN_ARCH), ARM)
CROSS := /opt/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/arm-linux-gnueabihf-
else ifeq ($(RUN_ARCH), x86)
CROSS :=
endif
# CROSS = arm-linux-gnueabihf-
export CC = $(CROSS)gcc
export CXX = $(CROSS)g++
export AR := $(CROSS)ar
export AS := $(CROSS)as
export STRIP := $(CROSS)strip
export CPP = $(CC) -E
export OBJCOPY = $(CROSS)objcopy
export OBJDUMP = $(CROSS)objdump
export NM = $(CROSS)nm
export LD = $(CROSS)ld
# 原始檔,自動找所有.c和.cpp檔案,並將目標定義爲同名.o檔案
SOURCE := $(wildcard *.c) $(wildcard *.cpp)
OBJS := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
# 編譯參數
LIBS := #-L /Path -lname
LDFLAGS :=
DEFINES :=
INCLUDE := #-I /Path/include/
CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE)
CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
# 下面 下麪的基本上不需要做任何改動了
.PHONY : everything objs clean veryclean rebuild
everything : $(TARGET_FILE)
all : $(TARGET_FILE)
objs : $(OBJS)
rebuild: veryclean everything
clean :
rm -rf *.o $(TARGET_FILE)
veryclean : clean
rm -rf $(TARGET_FILE)
$(TARGET_FILE) : $(OBJS)
$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
# 應用程式需要刪掉的編譯中間檔案
rm -rf *.o
# 拷貝目標檔案
cp $(TARGET_FILE) $(TARGET_PATH)
#if 0
程式思路:
1. 先比較新、舊字串的長度,判斷偏移位置的長度與方向
2. 查詢目標行,假如找到,則讀取目標行往後至文字結束的所有數據到Buffer
3. 替換目標行的數據
4. 將Buffer的數據匯入替換完目標行的數據後面
5. 假如舊字串數據比新字串數據長,則截斷多餘文字長度
筆者注:
該程式主要用於工程專案中修改組態檔中的參數,通過匹配組態檔中指定的變數去替換參數。
程式親測可用,替換的本質是對指定行的字串替換,字串的長度不限制,可過長也可過短,
也可不變,因此有一定的侷限性。
程式優點:執行過程中不建立新的文字,減少對NandFlash的擦除與進入。
後面過來學習的同學可以對程式進行修改,直到功能滿足自己的需求
#endif
# 原文字(程式執行前的)內容
$ cat ChangeFile.txt
[This is a Configuration File]
Parameter_A=0123456789
Parameter_B=0123456789
Parameter_C=0123456789
Parameter_D=0123456789
Parameter_E=0123456789
Parameter_F=0123456789
Parameter_G=0123456789
# 程式執行後的內容
$ cat ChangeFile.txt
[This is a Configuration File]
Parameter_A=0123456789
Parameter_B=0123456789
Parameter_C=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Parameter_D=0123456789
Parameter_E=0123456789
Parameter_F=0123456789
Parameter_G=0123456789
// 程式:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
// 用於消除警告fgets、fread、ftruncate等函數的編譯警告
// 適合喜歡「0 errors, 0 warnings」的同學
char *pEliminateWarn = NULL;
int EliminateWarn = 0;
int OpenFile(char *ChangeFile, unsigned int *FileLength, FILE **fp);
int FileOperation(unsigned int FileLength, FILE *fp, char *OldStr,
char *NewStr, int StrDiffer);
void CloseFile(FILE *fp);
void SetFileLength(char *ChangeFile, unsigned int FileLength, int StrDiffer);
int main(int argc, char *argv[])
{
char ChangeFile[] = "ChangeFile.txt";
char OldStr[] = "Parameter_C=0123456789";
char NewStr[] = "Parameter_C=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int StrDiffer = 0; // OldStr 與 NewStr 之差
FILE *fp = NULL;
unsigned int FileLength = 0;
int ret = 0;
// StrDiffer > 0 說明文字後面的數據需要往前移動,且舊文字比新文字 長,
// 文字末尾需要 截斷 StrDiffer 個字元長度;
// StrDiffer < 0 說明文字後面的數據需要往後移動,且舊文字比新文字 短
// 文字末尾需要 增長 StrDiffer 個字元長度;
// StrDiffer = 0 說明文字後面的數據不需要移動,且舊文字與新文字 等長
// 文字末尾 不變。
StrDiffer = strlen(OldStr) - strlen(NewStr);
// 1.開啓需要修改的檔案
ret = OpenFile(ChangeFile, &FileLength, &fp);
if(ret < 0)
{
return 0;
}
// 2.檔案操作
FileOperation(FileLength, fp, OldStr, NewStr, StrDiffer);
// 3.關閉檔案
CloseFile(fp);
// 4.如果(OldStr > NewStr),需截斷文字末尾的空餘,即設定文字長度
if(StrDiffer > 0)
{
SetFileLength(ChangeFile, FileLength, StrDiffer);
}
return 0;
}
int OpenFile(char *ChangeFile, unsigned int *FileLength, FILE **fp)
{
// 開啓需要修改的檔案
*fp = fopen(ChangeFile, "rwb+");
if(*fp == NULL)
{
printf("open %s error \n", ChangeFile);
return -1;
}
// 將檔案指針定位於檔案的末尾處,獲取檔案大小
fseek(*fp, 0, SEEK_END);
*FileLength = ftell(*fp);
printf("FileLength = %dB (%.2fMB) \n", *FileLength,
((double)*FileLength / (1024 * 1024)));
return 1;
}
void CloseFile(FILE *fp)
{
fclose(fp);
}
void SetFileLength(char *ChangeFile, unsigned int FileLength, int StrDiffer)
{
int fd = 0;
unsigned int length = 0;
fd = open(ChangeFile, O_RDWR);
length = FileLength - StrDiffer;
EliminateWarn = ftruncate(fd, length);
printf("==== length = %d === \n", length);
close(fd);
}
int FileOperation(unsigned int FileLength, FILE *fp, char *OldStr,
char *NewStr, int StrDiffer)
{
// 將檔案指針指向檔案頭
fseek(fp, 0, SEEK_SET);
// 進行相應的檔案操作
unsigned int RemainFileLength = 0; // 剩餘的長度
unsigned int CurrentFileLength = 0; // 當前的長度
unsigned char *RemainFileData = NULL; // 剩下的文字數據
char Array[500]; // 儲存文字的行數據
int ArrayLength = 0; // 記錄該行數據的長度
while(1)
{
// 1.提取文字的行數據
memset(Array, '\0', sizeof(Array));
if(fgets(Array, sizeof(Array), fp) == NULL)
{
break;
}
// 2.記錄文字的行數據長度
ArrayLength = strlen(Array);
// 3.比較該行是否爲目標行
if(strncmp(Array, OldStr, ArrayLength - 1) == 0)
{
// 4.定位文字中在OldStr後第1位(即「\n」)的位置
CurrentFileLength = ftell(fp);
// 5.讀取出文字中在OldStr後面不需要修改的文字數據 到 RemainFileData
RemainFileLength = FileLength - CurrentFileLength;
RemainFileData = (unsigned char *)malloc(RemainFileLength + 1);
memset(RemainFileData, 0, (RemainFileLength + 1));
EliminateWarn = fread(RemainFileData, sizeof(unsigned char), (RemainFileLength), fp);
// 6.將檔案指針指向OldStr前第1位(即「\n」)的位置,將NewStr替換OldStr
memset(Array, '\0', sizeof(Array));
strcpy(Array, NewStr);
fseek(fp, (CurrentFileLength - ArrayLength), SEEK_SET);
fprintf(fp, "%s", Array);
// 7.在文字中NewStr後第1位補上換行符(「\n」)
fwrite("\n", sizeof(unsigned char), 1, fp);
// 8.將RemainFileData中的數據匯入到文字NewStr後,並釋放RemainFileData
fwrite(RemainFileData, sizeof(unsigned char), RemainFileLength, fp);
free(RemainFileData);
// 9.重新將檔案指針定位到一開始的位置
fseek(fp, CurrentFileLength, SEEK_SET);
}
}
return 1;
}
// 筆者對內核態下的檔案操作只停留在驅動程式讀取文字內容,根據讀取組態檔的資訊,
// 驅動載入時進行定向執行,但深入的應用並不瞭解
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/slab.h>
int __init driver_file_init(void)
{
mm_segment_t fs;
struct file *fpRead = NULL, *fpWrite = NULL;
struct kstat *StatRead = NULL;
char *pFileBuf = NULL;
loff_t PosRead = 0, PosWrite = 0;
unsigned long long FileLength = 0;
const char ReadFile[] = "/tmp/ReadFile.txt";
const char WriteFile[] = "/tmp/WriteFile.txt";
printk("driver_file enter \n");
// 1.獲取內核態預設的記憶體地址限制,設定記憶體地址限制覆蓋到使用者空間
fs = get_fs();
set_fs(KERNEL_DS);
// 2.獲取相應檔案的大小
StatRead = (struct kstat *)kmalloc(sizeof(struct kstat), GFP_KERNEL);
memset(StatRead, 0, sizeof(struct kstat));
vfs_stat(ReadFile, StatRead);
FileLength = StatRead->size;
kfree(StatRead);
// 3.開啓讀、寫檔案
fpRead = filp_open(ReadFile, O_RDWR | O_CREAT, 0644);
if(IS_ERR(fpRead))
{
printk("Open %s read file error \n", ReadFile);
goto open_read_file_fail;
}
fpWrite = filp_open(WriteFile, O_RDWR | O_CREAT, 0644);
if(IS_ERR(fpWrite))
{
printk("Open %s write file error \n", WriteFile);
goto open_write_file_fail;
}
// 4.清空Buffer
pFileBuf = (char *)kmalloc(FileLength * sizeof(char) + 1, GFP_KERNEL);
memset(pFileBuf, 0, FileLength * sizeof(char) + 1);
// 5.將讀檔案的內容匯入到Buffer,再把Buffer的內容匯入到寫檔案
PosWrite = PosRead = 0;
vfs_read(fpRead, pFileBuf, (FileLength * sizeof(char)), &PosRead);
vfs_write(fpWrite, pFileBuf, (FileLength * sizeof(char)), &PosWrite);
printk(KERN_INFO "==== pFileBuf = %s ==== \n", pFileBuf);
// 6.釋放Buffer
kfree(pFileBuf);
// 7.關閉讀寫檔案
filp_close(fpRead, NULL);
filp_close(fpWrite, NULL);
// 8.設定內核態的記憶體地址限製爲預設的記憶體地址限制
set_fs(fs);
return 0;
open_write_file_fail:
filp_close(fpRead, NULL);
open_read_file_fail:
set_fs(fs);
return -1;
}
void __exit driver_file_exit(void)
{
printk("driver_file exit \n");
}
module_init(driver_file_init);
module_exit(driver_file_exit);
MODULE_LICENSE("GPL");
struct kstat結構體位於 include/linux/stat.h,Linux 3.10.31-LTSI
struct kstat {
u64 ino; // inode number,inode節點號
dev_t dev; // ID of device containing file,檔案所在裝置的ID
umode_t mode; // protection,保護模式
unsigned int nlink; // number of hard links,鏈向此檔案的連線數(硬連線)
kuid_t uid; // user ID of owner,user id
kgid_t gid; // group ID of owner,group id
dev_t rdev; // device ID (if special file),裝置號,針對裝置檔案
loff_t size; // total size, in bytes,檔案大小,位元組爲單位
struct timespec atime; // time of last access,最近存取時間
struct timespec mtime; // time of last modification,最近修改時間
struct timespec ctime; // time of last status change,建立時間
unsigned long blksize; // blocksize for filesystem I/O,系統塊的大小
unsigned long long blocks; // number of blocks allocated,檔案所佔塊數
};
int Temp;
// 將檔案指針定位到檔案頭
fseek(fp, 0, SEEK_SET);
while(1)
{
// 從指定的流 stream 獲取下一個字元(一個無符號字元),並把位置識別符號往前移動。
Temp = fgetc(fp);
// 該判斷只適合fgetc
if(Temp == EOF)
{
// 把檔案流裡的所有未寫出數據立刻寫出
fflush(fp);
printf("\n");
printf("File point have reached the end of file Or Read error \n");
sleep(5);
}
// 該判斷具有通用性,測試一個檔案流的檔案尾標識
if(feof(fp))
{
// 把檔案流裡的所有未寫出數據立刻寫出
fflush(fp);
printf("\n");
printf("File point have reached the end of file \n");
sleep(5);
}
printf("%c", Temp);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/vfs.h> // statfs、fstatfs函數
#include <mntent.h> // setmntent、getmntent、endmntent函數
char MountPath[] = "/proc/mounts"; // proc系統中的mount檔案
struct sStoragreSize
{
// 容量、使用、可用,單位爲 KB
unsigned int Size_KB;
unsigned int Used_KB;
unsigned int Available_KB;
// 掛載標誌位:爲0,沒有掛載;爲1,有掛載。
unsigned char MountFlag;
};
void ReadStoragreSize(char *DevicePath, struct sStoragreSize *pStoragre)
{
FILE *fpMount = NULL;
struct mntent *mnt = NULL;
struct statfs diskInfo;
pStoragre->MountFlag = 0;
// 開啓proc系統中的mount檔案
fpMount = setmntent(MountPath, "r");
if(fpMount == NULL)
{
printf("== Open %s error == \n", MountPath);
return;
}
// 判斷是否有掛載相應的裝置,並標記有掛載的裝置
while(1)
{
mnt = getmntent(fpMount);
if(strncmp(mnt->mnt_dir, DevicePath, (sizeof(DevicePath)) - 1) == 0)
{
pStoragre->MountFlag = 1;
break;
}
}
endmntent(fpMount);
if(pStoragre->MountFlag)
{
memset(&diskInfo, 0, sizeof(struct statfs));
statfs(DevicePath, &diskInfo);
// 一定要強制轉化爲unsigned long long(64位元),若地址超過4G,會導致數據溢位
// 右移10位是爲了方便儲存數據,只需要用unsigned int(32位元)就可以儲存
pStoragre->Size_KB = ((unsigned long long)diskInfo.f_bsize *
(unsigned long long)diskInfo.f_blocks) >> 10;
pStoragre->Used_KB = ((unsigned long long)diskInfo.f_bsize *
(unsigned long long)(diskInfo.f_blocks -
diskInfo.f_bfree)) >> 10;
pStoragre->Available_KB = ((unsigned long long)diskInfo.f_bsize *
(unsigned long long)diskInfo.f_bavail) >> 10;
}
else
{
pStoragre->Size_KB = pStoragre->Used_KB = pStoragre->Available_KB = 0;
}
}
int main(int argc, char *argv[])
{
int i = 0;
char DevicePath[15];
struct sStoragreSize Storagre;
char MachinePath[] = "/home"; // 機身儲存的掛載路徑
char SDCardPath[] = "/mnt/sdcard"; // SD卡的掛載路徑
char UdiskPath[] = "/mnt/udisk"; // U盤的掛載路徑
for(i = 0; i < 3; i++)
{
memset(DevicePath, 0, sizeof(DevicePath));
memset(&Storagre, 0, sizeof(struct sStoragreSize));
switch(i)
{
case 0:
memcpy(DevicePath, MachinePath, sizeof(MachinePath));
break;
case 1:
memcpy(DevicePath, SDCardPath, sizeof(SDCardPath));
break;
case 2:
memcpy(DevicePath, UdiskPath, sizeof(UdiskPath));
break;
}
ReadStoragreSize(DevicePath, &Storagre);
if(Storagre.MountFlag)
{
printf("DevicePath = %s \n", DevicePath);
printf("Size = %.3f GB \n", ((double)Storagre.Size_KB / (1024 * 1024)));
printf("Used = %.3f GB \n", ((double)Storagre.Used_KB / (1024 * 1024)));
printf("Available = %.3f GB \n\n", ((double)Storagre.Available_KB /
(1024 * 1024)));
}
}
return 0;
}
// struct statfs結構體位於 /usr/include/i386-linux-gnu/bits/statfs.h
struct statfs
{
__fsword_t f_type; // 檔案系統型別
__fsword_t f_bsize; // 經過優化的傳輸塊大小
#ifndef __USE_FILE_OFFSET64
__fsblkcnt_t f_blocks; // 檔案系統數據塊總數
__fsblkcnt_t f_bfree; // 可用塊數
__fsblkcnt_t f_bavail; // 非超級使用者可獲取的塊數
__fsfilcnt_t f_files; // 檔案結點總數
__fsfilcnt_t f_ffree; // 可用檔案結點數
#else
__fsblkcnt64_t f_blocks; // 檔案系統數據塊總數
__fsblkcnt64_t f_bfree; // 可用塊數
__fsblkcnt64_t f_bavail; // 非超級使用者可獲取的塊數
__fsfilcnt64_t f_files; // 檔案結點總數
__fsfilcnt64_t f_ffree; // 可用檔案結點數
#endif
__fsid_t f_fsid; // 檔案系統標識
__fsword_t f_namelen; // 檔名的最大長度
__fsword_t f_frsize;
__fsword_t f_flags;
__fsword_t f_spare[4]; // spare for later
};
// struct stat結構體位於 /usr/include/i386-linux-gnu/asm/stat.h
#ifdef __i386__
struct stat {
unsigned long st_dev; // 檔案的裝置編號
unsigned long st_ino; // 節點
unsigned short st_mode; // 檔案的型別和存取的讀寫執行許可權
unsigned short st_nlink; // 連到該檔案的硬連線數目,剛建立的檔案值爲1
unsigned short st_uid; // 使用者ID
unsigned short st_gid; // 組ID
unsigned long st_rdev; // (裝置型別)若此檔案爲裝置檔案,則爲其裝置編號
unsigned long st_size; // 檔案位元組數(檔案大小)
unsigned long st_blksize; // 塊大小(檔案系統的I/O 緩衝區大小)
unsigned long st_blocks; // 檔案所佔塊數
unsigned long st_atime; // 最後一次存取時間
unsigned long st_atime_nsec; //
unsigned long st_mtime; // 最後一次修改時間
unsigned long st_mtime_nsec; //
unsigned long st_ctime; // 最後一次改變時間(指屬性)
unsigned long st_ctime_nsec; //
unsigned long __unused4; //
unsigned long __unused5; //
};
#else /* __i386__ */
struct stat {
__kernel_ulong_t st_dev;
__kernel_ulong_t st_ino;
__kernel_ulong_t st_nlink;
unsigned int st_mode;
unsigned int st_uid;
unsigned int st_gid;
unsigned int __pad0;
__kernel_ulong_t st_rdev;
__kernel_long_t st_size;
__kernel_long_t st_blksize;
__kernel_long_t st_blocks; // 分配的512位元組塊數。
__kernel_ulong_t st_atime;
__kernel_ulong_t st_atime_nsec;
__kernel_ulong_t st_mtime;
__kernel_ulong_t st_mtime_nsec;
__kernel_ulong_t st_ctime;
__kernel_ulong_t st_ctime_nsec;
__kernel_long_t __unused[3];
};
#endif
stat、fstat和lstat函數:
https://www.cnblogs.com/xj626852095/p/3648237.html
# 共同點:
xx_ino // inode節點號
xx_dev // 檔案的裝置ID
xx_mode // 檔案的型別和存取的讀寫執行許可權
xx_nlink // 連到該檔案的硬連線數
xx_uid // 使用者ID
xx_gid // 組ID
xx_rdev // 若此檔案爲裝置檔案,則爲其裝置編號
xx_size // 檔案大小,位元組爲單位
xx_blksize // 系統塊大小(檔案系統的I/O 緩衝區大小)
xx_blocks // 檔案所佔塊數
xx_atime // 最近存取時間,包含sec和nsec
xx_mtime // 最近修改時間,包含sec和nsec
xx_ctime // 建立時間,包含sec和nsec
# 不同點:
__unused_xx // 沒有使用的
# 總結:
基本上是一樣的……
// 《Linux程式設計 第4版》,Neil Matthew、Richard Stones 著 的第3章與第4章
// 3.7 C語言檔案和目錄維護
// chmod 系統呼叫
int chmod(const char *path, mode_t mode);
// chown 系統呼叫
int chown();
// unlink、link和symlink系統呼叫
int unlink();
int link();
int symlink();
// mkdir和rmdir系統呼叫
int mkdir();
int rmdir();
// chdir系統呼叫和getcwd函數
int chdir();
char *getcwd();
// 3.8 C語言檔案和目錄維護
// opendir函數
DIR *opendir();
// readdir函數
struct dirent *readdir();
// telldir函數
long int telldir();
// seekdir函數
void seekdir();
// closedir函數
int closedir();
// 3.9 C語言錯誤處理
// strerror函數
char *strerror();
// perror函數
void perror();
// 3.10 /proc檔案系統
// 3.11 C語言fcntl和mmap函數
// 4
// 4.1 int main(int argc, char *argv[])
// 4.1.1 getopt函數
int getopt();
// 4.1.1 getopt_long函數
int getopt_long();
// 4.2 環境變數
char *getenv();
int putenv();
// 4.2.2 environ變數
extern char *environ;
// 4.3 時間和日期
time_t time();
double difftime();
struct tm *gmtime();
struct tm *localtime();
time_t mktime();
time_t asctime();
time_t ctime();
size_t strftime();
char *strptime();
// 4.4 臨時檔案
char *tmpnam();
FILE *tmpfile();
char *mktemp();
int mkstemp();
// 4.5 使用者資訊
uid_t getuid();
char *getlogin();
struct passwd *getpwuid();
struct passwd *getpwnam();
void endpwent();
struct passwd *getpwent();
void setpwent();
uid_t geteuid();
gid_t getgid();
gid_t getegid();
int setuid();
int setgid();
// 4.6 主機資訊
int gethostname();
int uname();
long gethostid();
// 4.7 日誌
void syslog();
void closelog();
void openlog();
int setlogmask();
// 4.8 資源和限制(硬體的限制、系統策略的限制、具體實現的限制)
int getpriority(); // 優先順序
int setpriority();
int getrlimit(); // 限制
int setrlimit();
int getrusage(); // 資源資訊
struct timeval TimeVal_1, TimeVal_2;
gettimeofday(&TimeVal_1, NULL);
// ***** 一頓操作 1 *****
// ***** 一頓操作 2 *****
// ***** 一頓操作 3 *****
gettimeofday(&TimeVal_2, NULL);
double Time1_s = (TimeVal_1.tv_sec) + ((double)TimeVal_1.tv_usec / (1000 * 1000));
double Time2_s = (TimeVal_2.tv_sec) + ((double)TimeVal_2.tv_usec / (1000 * 1000));
double Time1_ms = (TimeVal_1.tv_sec * 1000) + ((double)TimeVal_1.tv_usec / 1000);
double Time2_ms = (TimeVal_2.tv_sec * 1000) + ((double)TimeVal_2.tv_usec / 1000);
printf("Running %.2f min (%.2fs %.1f ms) \n\n", (Time2_s - Time1_s) / 60,
(Time2_s - Time1_s), (Time2_ms - Time1_ms));