嵌入式 Linux 文件IO操作

简介: 嵌入式 Linux 文件IO操作

Linux 文件操作

1 Linux 系统环境文件操作概念

 Linux 中一切皆文件,对目录和设备的操作都是文件操作。文件分为普通文件,管道文件,目录文件,链接 文件和设备文件。

普通文件:也称磁盘文件,并且能够进行随机的数据存储(能够自由 seek 定位到某一个位置);

管道文件:是一个从一端发送数据,另一端接收数据的数据通道;

目录文件:它包含了保存在目录中文件列表的简单文件。

设备文件:Linux 下各种硬件设备都是文件,该类型的文件提供了大多数物理设备的接口。它又分为两种类 型:字符型设备和块设备。字符型设备一次只能读出和写入一个字节的数据,包括调制解调器、终端、打印机、 声卡以及鼠标;块设备必须以一定大小的块来读出或者写入数据,块设备包括 CD-ROM、RAM 驱动器和磁盘驱 动器等,一般而言,字符设备用于传输数据,块设备用于存储数据。

套接字文件:在 Linux 中,套接字也可以当作文件来进行处理。

对文件进行的操作有打开文件,关闭文件,读写文件。其中打开文件是第一步,是为后续操作做准备的。

2 缓冲 IO 文件操作

 文件指针:每打开一个文件,就返回一个指针(FILE*类型),称为文件指针。这个指针指向了这个文件相关 的所有信息,即我们就可以用这个指针代表这个文件,通过这个指针可以对这个打开的文件进行各种操作。

缓冲区:输入输出的数据并不是一下子直接到电脑内存和显示器中,输入的数据先暂时存放在键盘缓冲区中, 然后程序从该缓冲区中读取数据。输出的数据先暂时存放在输出缓冲区中,然后再把该数据输出到屏幕中。本节 介绍的输入输出相关函数都是要用到缓冲区的。

1 文件的创建,打开与关闭

相关函数声明在 stdio.h 文件中,编写程序时候需要 #include 。

 FILE *fopen(const char *path,const char *mode); //文件名模式 
FILE *fdopen(int filds,const char *mode);
FILE *freopen(const char *path,const char *mode, FILE *stream); 
int fclose(FILE *stream); 

前面三个打开文件相关的函数都有一个参数 mode,这个参数是指定打开模式,具体意义如下表所示。

表 5.1 可选模式 在 Linux 系统中,mode 里面的’b’(二进制)可以去掉,但是为了保持与其他系统的兼容性,建议不要去掉。ab 和 a+b 为追加模式,在此两种模式下,无论文件读写点定位到何处,在写数据时都将是在文件末尾添加,所以比 较适合于多进程写同一个文件的情况下保证数据的完整性。

fopen 函数函数

原型:FILE *fopen(const char *path,const char *mode);

功能:fopen 以 mode 的方式打开或创建文件,如果成功,将返回一个文件指针,失败则返回 NULL。

参数:  path:要打开的文件

mode:打开模式,Linux 系统中有下列几种形态字符串:

r 打开只读文件,该文件必须存在。

r+ 打开可读写的文件,该文件必须存在。

w 打开只写文件,若文件存在则文件长度清为 0,即该文件内容会消失。

若文件不存在则建立该文件。

w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。

若文件不存在则建立该文件。

a 以附加的方式打开只写文件。

若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件 尾,即文件原先的内容会被保留。

a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到 文件尾后,即文件原先的内容会被保留。

上述的形态字符串都可以再加一个 b 字符,如 rb、w+b 或 ab+等组合,加入 b 字符用来告诉函数库打开的 文件为二进制文件,而非纯文字文件。

不过在 POSIX 系统,包含 Linux 都会忽略该字符。

返回: 成功:指向该流的文件指针就会被返回。 失败:则返回 NULL,并把错误代码存在 errno 中。

打开文件后可以执行文件读取或写入的动作,若开文件失败,接下来的读写动作也无法顺利进行,所以在 fopen()后请作错误判断及处理。

附加说明:由 fopen()所建立的新文件会具有 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)权限,此文件权限也会参考 umask 值。

示例代码:打开时候创建一个不存在的文件 以下代码输入到 fopen.c 中

 #include int main(void) {
  FILE *fil; fil = fopen("myfirstfile.txt", "a+"); 
    if(fil == NULL) 
   { 
     printf("open error!\r\n"); 
      return; 
   } fclose(fil); 
     return 0; 
   } 

终端执行:

[root@localhost 01_fopen]# touch fopen.c 
[root@localhost 01_fopen]# gedit fopen.c& 
[1] 6145 
[root@localhost 01_fopen]# gcc -o fopen fopen.c 
[root@localhost 01_fopen]# ./fopen

2 freopen 函数

原型:FILE *freopen(const char *path,const char *mode, FILE *stream);

功能:实现重定向,把预定义的标准流文件定向到由 path 指定的文件中。

标准流文件具体是指 stdin、stdout 和 stderr。其中 stdin 是标准输入流,默认为键盘;stdout 是标准输出流,默认为屏幕;stderr 是标准错误流,一般把屏幕设为默认。

参数: path: 文件名,用于存储输入输出的自定义文件名。

mode: 文件打开的模式。和 fopen 中的模式(如 r-只读, w-写)相同。

stream: 一个文件,通常使用标准流文件。

返回: 成功:返回一个 path 所指定文件结构指针;

失败:返回 NULL。(一般可以不使用它的返回值)

实例代码:重定向标准输入,标准输出流

以下代码输入到freopen.c当中;

#include <stdio.h> 
int main() 
{ 
 int a,b; 
 freopen("in.txt","r",stdin); //输入重定向,输入数据将从 in.txt 文件中读取
 freopen("out.txt","w",stdout); //输出重定向,输出数据将保存在 out.txt 文件中
 while(scanf("%d %d",&a,&b)!=EOF) 
 printf("%d\n",a+b); 
 fclose(stdin);//关闭文件
 fclose(stdout);//关闭文件
 return 0; 
}

编译测试:

[root@localhost 02_freopen]# touch in.txt out.txt freopen.c
[root@localhost 02_freopen]# echo 1 2 3 4 5 6 7 8 9 10 >in.txt 
[root@localhost 02_freopen]# cat in.txt 
1 2 3 4 5 6 7 8 9 10
[root@localhost freopen]# gedit freopen.c &
[1] 6474
[root@localhost freopen]# gcc freopen.c 
[1]+ Done gedit freopen.c
[root@localhost freopen]# ./a.out 
[root@localhost freopen]# cat out.txt 
3 <-- a=1,b=2 ,即从 in.txt 中读取第 1 和第 2 个字节
7 <-- a=3,b=4 ,即从 in.txt 中读取第 3 和第 4 个字节
11
15
19
[root@localhost freopen]#

3、fdopen函数

原型:FILE *fdopen(int filds,const char *mode);

功能:函数说明 fdopen()会将参数 fildes 的文件描述词,转换为对应的文件指针后返回。参数 mode 字符串 则代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同。关于 mode 字符串格式请参考 fopen()。

返回值: 成功:返回指向该流的文件指针。 失败:NULL,并把错误代码存在 errno 中。 说明:这个函数比较少用,一般用来打开某些不能直接用 fopen 方式打开的文件,比如管道和网络套接字文 件。

例子:把标准输出文件描述符0转换成文件流

#include<stdio.h>
int main(void)
{
 FILE * fp =fdopen(0,"w+");
 fprintf(fp,"%s\n","hello!");
 fclose(fp);
return 0;
}

终端测试:

[root@localhost 03_fdopen]# touch fdopen.c
[root@localhost 03_fdopen]# gedit fdopen.c &
[1] 3400
[root@localhost 03_fdopen]# gcc -o fdopen fdopen.c
[1]+ Done gedit fdopen.c
[root@localhost 03_fdopen]# ./fdopen 
hello!
[root@localhost 03_fdopen]#

4、fclose函数

int fclose(FILE *stream); 功能:关闭 stream 指向的文件。

1 判断文件结尾函数 feof

原型:int feof(FILE * stream);

功能:feof 函数检查文件流是否读到了文件尾

参数:stream 文件指针

返回:返回非零值代表已到达文件尾

2 数据块写函数 fwrite

原型:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以二进制形式对文件进行操作,从 ptr 指向的内存中读取 nmemb 个元素,每个元素 size 个字节,写 到文件流 stream 中。

参数:

ptr:这是一个 void 型指针,指出要将写入数据存放在其中的存储区首地址

size:指出一个数据块的字节数,即一个数据块的大小尺寸

nmemb:指出一次写入多少个数据块(size)

stream:输出数据流指针

返回: 正常:实际写入数据块的个数,即 nmemb 。 异常:如果文件中剩下的数据块个数少于参数中 size 指出的个数,或者发生了错误,返回 0 值。此时可以用 feof()和 ferror()来判定到底出现了什么情况。 说明:写入到文件的哪里? 这个与文件的打开模式有关,如果是 w+,则是从文件指针指向的地址开始写, 替换掉之后的内容,文件的长度可以不变,stream 的位置移动 size 个数;如果是 a+,则从文件的末尾开始添加, 文件长度加大。

3 数据块读函数 fread

原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:以二进制形式对文件进行操作,从文件流 stream 中读取 nmemb 个元素,每个元素 size 个字节,存放 到 ptr 指向的数据缓冲区中。

参数:

ptr:这是一个 void 型指针,指出要将读入数据存放在其中的存储区首地址

size:指出一个数据块的字节数,即一个数据块的大小尺寸

nmemb:指出一次读入多少个数据块(size)

stream:输入数据流指针

返回: 正常:大于 0,返回真实读取的元素数

异常:小于 nmemb,此时可以用 feof()和 ferror()来判定到底出现了什么情况。

4、读写文件块实例:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
 char buf1[50] = {0};
 char buf[50] = {'h','e','l','l','o'};
 FILE *p; //定义一个 FILE 结构体类型的指针 p
 p = fopen("a.txt", "r+b"); //p 这个指针此时就和文件 a.txt 关联起来了。
 if(!p){
 perror("fopen");
 exit(0);
 }
 fwrite(buf, 1, 5, p); //把 buf 里面的内容写到 p 指向的文件中。
 fseek(p,0,SEEK_SET); //移动光标到文件开头
 fread(buf1, 1, 5, p); //读出上一步写入的数据
 printf("buf1:%s\n", buf1);
 fclose(p); //关闭 p 代表的文件 a.txt
 return 0;
}

5、格式化读写

fprintf 函数

原型:int fprintf(FILE *stream, const char *format, ...);

功能:格式化数据输出到一个文件中 stream 指向的文件

参数:

stream 一个 FILE 型的指针

format 输出格式,和 printf 函数的参数一样

返回: 正数:成功格式化的字节数

负数:格式化转换失败

实例:使用fprintf格式化数据输出到文件

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ret;
 int i = 10;
 double fp = 1.5;
 char *s = "this is a string";
 char c = '\n';
 FILE* stream;
 stream = fopen("fprintf.out", "w");
 if(!stream)
 {
 perror("fopen");
 return -1;
 }
 ret = fprintf(stream, "%s%c", s, c);
printf("ret=%d\r\n",ret);
 ret = fprintf(stream, "%d\n", i);
printf("ret=%d\r\n",ret);
 ret = fprintf(stream, "%f\n", fp);
printf("ret=%d\r\n",ret);
 fclose(stream);
 return 0;
}

fscanf函数

原型:int fscanf(FILE *stream, const char *format, …);

功能:从一个流中执行格式化输入,fscanf 遇到空格和换行时结束,注意空格时也结束。这与 fgets 有区别, fgets 遇到空格不结束。

参数: stream 一个 FILE 型的指针

format 输出格式,和 printf 函数的参数一样

返回: 正数:成功则返回参数数目(不是字节数) -1 :失败,错误原因存于 errno 变量中

示例:使用 fscanf 从特定数据格式的文件中读取内容到内存变量中

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
 int ret = 0;
 char name[100]={0};
 double price;
 FILE* stream;
 stream = fopen("data.in", "r");
 if(!stream)
 {
 perror("fopen");
 return -1;
 }
 while(!feof(stream)){
 ret = fscanf(stream, "%s%lf\n",name,&price);
 printf("ret:%d\r\n",ret);
 printf("name:%s,price:%0.2lf\r\n",name,price);
 }
 fclose(stream);
 return 0;
}

6、单个字符读写

单字符读函数

使用下列函数可以一次读一个字符:

int fgetc(FILE *stream);

int getc(FILE *stream);

功能: fgetc 从这个流中读取下一个字符,读取成功后文件读写位置值增 1,并把读取到的字符以 int 类型的值返回 发生了错误或者已经位于文件尾部,fgetc 返回 EOF。在这种情况下,程序员应使用 feof 函数来判断是否真 正的达到了文件尾。

getc 的功能与 fgetc 相同,但为了提高效率,它一般被实现为宏。

参数:stream 文件结构指针

返回: 正数:读取的字符 ASIIC 值

负数:读取失败,值为 EOF,程序员应使用 feof 函数来判断是否真正的达到了文件尾。

单字符写函数

使用下列函数可以一次写一个字符:

int fputc(int c, FILE *stream);

int putc(int c, FILE *stream);

功能:这两个函数作用相同,用于向 stream 所指向的文件的当前读写位置写入一个字符,成功写入一个字 符后,文件读写位置指针向后移动一个字节。

参数:

c 要写入的字符

stream 文件指针

返回: 正数:写入的字符 ASIIC 值

负数:写入失败,值为 EOF

单字符读写函数实例:

使用单字符读写函数实现文件复制功能

#include<stdio.h>
//测试时候先自己创建 data.in,并且 输入测试内容
int main (void)
{
 FILE * pFile;
 FILE * pOut;
 int n = 0;
 int ch;
 pFile = fopen ("data.in","rb"); //源文件
 if (pFile==NULL){
 perror ("Error opening file");
 }
 pOut = fopen ("data.out","w+"); //目标文件
 if (pOut==NULL){
 perror ("Error opening file");
 }
 while ( (ch=fgetc(pFile)) != EOF) {
 ++n;
 fputc(ch,pOut);
 }
 if (feof(pFile)) {//when EOF
 puts ("End-of-File reached.");
 printf ("Total number of bytes read: %d\n", n);
 } else { //when error 
 puts ("End-of-File was not reached.");
 }
 fclose (pFile);
 fclose (pOut);
 return 0;
}

字符串读取函数

原型:char *fgets(char * string, int size, FILE *stream);

功能:该函数从 stream 所指的文件中读取以'\n'结尾的一行(包括'\n'在内)存到缓冲区 string 中,并且在该 行末尾添加一个'\0'组成完整的字符串。

参数:

string 为一个字符数组,用来保存读取到的字符。

size 为要读取的字符的个数。如果该行字符数大于 size-1,则读到 size-1 个字符时结束,并在最后补充' \0'; 如果该行字符数小于等于 size-1,则读取所有字符,并在最后补充 '\0'。即,每次最多读取 size-1 个字符。

stream 为文件结构指针。

返回: 非 NULL:成功,读取到的字符串,即参数 string 的值;

NULL:失败或读到文件结尾。必须通过 feof()函数或者 ferror()函数来判断是错误还是到文件结尾了

fgets 读取一行字符时,保留行尾的换行符。

fputs 不会在行尾自动添加换行符,但是 puts 会在标准输出流中自动添加一换行符。

字符串读写函数

原型:int fputs(char * string, FILE * stream);

功能:用于将指定的字符串写入到文件流中,缓冲区 string 中保存的是以'\0'结尾的字符串,fputs 将该字符 串写入文件 stream,但并不写入结尾的'\0'。与 fgets 不同的是,字符串中可以有'\n'也可以没有'\n'。

参数:

string 为将要写入的字符串

stream 为文件流指针

返回:>0 成功返回非负数,失败返回 EOF。

字符串读取函数实例:

示例 1:测试 data.in 文件中读取最多少于一行的字符以及多于 1 行的字符的效果。

//测试时候先自己创建 data.in,并且 输入测试内容
#include <stdio.h>
int main()
{
 FILE * pFile;
 char buf [100];
 pFile = fopen ("data.in" , "r");
 if (pFile == NULL){
 perror ("Error opening file");
}
 printf("-6------------------------\r\n");
 if ( fgets (buf , 6 , pFile) != NULL )
 puts (buf);
 //注意,这里没有移动文件指针,接着上面的位置读取
 printf("-50------------------------\r\n");
 if ( fgets (buf , 50 , pFile) != NULL )
 puts (buf);
 fclose (pFile);
 return 0;
}

7、文件定位

文件定位指读取或设置文件当前读写点,所有的通过文件指针读写数据的函数,都是从文件的当前读写点读 写数据的。

常用的函数有:

#include

int feof(FILE * stream); //通常的用法为 while(!feof(fp))

int fseek(FILE *stream, long offset, int whence);//设置当前读写点到偏移 whence 长度为 offset 处 long ftell(FILE *stream); //用来获得文件流当前的读写位置

void rewind(FILE *stream); //把文件流的读写位置移至文件开头 fseek(fp, 0, SEEK_SET);

feof 判断是否到达文件末尾的下一个(注意到达文件末尾之后还会做一次)

fseek 设置当前读写点到偏移 whence 长度为 offset 处,whence 可以是:

SEEK_SET (文件开头 0)

SEEK_CUR (文件当前位置

SEEK_END (文件末尾 2)

ftell 获取当前的读写点

rewind 将文件当前读写点移动到文件头

实例:

#include <stdio.h>
int main()
{
 char buf[50] = {'h','e','l','l','o'};
 FILE *p;
 p = fopen("a.txt", "r+b");
 fwrite(buf, 1, 5, p);
char buf1[50] = {0};
 fseek(p, 0, SEEK_SET);
 fread(buf1, 1, 5, p);
 printf("buf1:%s\n", buf1);
 fclose(p);
 return 0;
}

标准输入输出流

系统为每个进程预先打开了三个特殊的文件,对应的三个文件指针分别为:stdin(标准输入)、stdout(标准输 出)、stderr(标准出错)。定义在头文件中。

在进程一开始运行,就自动打开了三个对应设备的文件,它们是标准输入、输出、错误流,分别用全局文件 指针 stdin、stdout、stderr 表示,它们都是 FILE *类型。stdin 具有可读属性,缺省情况下是指从键盘的读取输入, stdout 和 stderr 具有可写属性,缺省情况下是指向屏幕输出数据。

实例:操作stdin,stdout,stderr以及缓冲效果

#include <stdio.h>
int main(void)
{
 char szBuf[1024];
 printf("Input string:"); 
 fread(szBuf, 1, 5, stdin);
 printf("stdout--------------------\r\n"); 
 fwrite(szBuf, 1, 5, stdout);
 printf("stderr--------------------\r\n"); 
 fwrite(szBuf, 1, 5, stderr);
 printf("--------------------\r\n"); 
 //演示缓冲效果,上面如果输入超过 5 字符,超过部分会流在缓冲中,下次会读到
 fread(szBuf, 1, 1, stdin);
 fwrite(szBuf, 1, 1, stdout);
 return 0;
}

8、标准目录文件

获取当前工作目录getcwd函数

原型:char *getcwd(char *buf, size_t size);

头文件:#include

功能:getcwd()会将当前工作目录的绝对路径复制到参数 buffer 所指的内存空间中,参数 size 为 buffer 的空间 大小。

参数: buf::存放工作路径缓冲区指针 size:size 为 buf 的空间大小

补充说明:

  1. buf 所指的内存空间要足够大,则当前路径被复制到 buf 中
  2. 当前工作目录绝对路径的字符串长度超过参数 size 大小,则回值 NULL,errno 的值则为 ERANGE。
  3. buf 为 NULL,getcwd()会依参数 size 的大小自动配置内存(使用 malloc()),
  4. buf,size 都为 0,则 getcwd()会依工作目录绝对路径的字符串长度来决定所配置的内存大小,进程可以

在使用完此字符串后自动利用 free()来释放此空间。所以常用的形式:getcwd(NULL, 0); 返回值:成功则返回当前工作目录字符串指针,失败返回 NULL。

改变目录chdir函数

原型:int chdir(const char *path);

头文件:#include

功能:修改当前工作路径,相当于 cd

参数:path 新工作路径

返回: 0:成功; -1:

失败,并且把失败错误码保存在全局变量 erron 中

实例:

#include<unistd.h>
main()
{
chdir("/tmp");
printf("current working directory: %s\n",getcwd(NULL,0));
}

改变目录或文件的访问权限chrmod函数

原型:int chmod(const char* path, mode_t mode); /

头文件:#include

功能:修改一个目录或文件的访问权限

参数:path 目录或文件路径字符串指针

mode:使用数字表示的权限值,mode 形如:0777

创建目录 mkdir 函数

原型:int mkdir(const char *pathname, mode_t mode); //创建目录,

mode 是目录权限,

头文件: #include #include #include

功能:创建一个指定权限的目录

删除目录 rmdir 函数

原型为: int rmdir(const char *pathname);

打开目录

原型:DIR *opendir(const char *name); //打开一个目录

头文件: #include #include

功能:打开一个目录

返回:非 NULL:成功打开的目录流,NULL:打开失败

重定位到目录 rewinddir 函数

void rewinddir(DIR *dir); //重新定位到目录文件的头部

设置目录流目前的读取位置

void seekdir(DIR *dir,off_t offset);//用来设置目录流目前的读取位置

获得目录流当前的读取位置 telldir 函数

off_t telldir(DIR *dir); //返回目录流当前的读取位置

关闭目录 closedir 函数

int closedir(DIR *dir); //

读取目录信息的步骤为: 用 opendir 函数打开目录;

使用 readdir 函数迭代读取目录的内容,如果已经读取到目录末尾,又想重新开始读,则可以使用 rewinddir 函数将文件指针重新定位到目录文件的起始位置;

用 closedir 函数关闭目录 opendir()用来打开参数 name 指定的目录,并返回 DIR*形态的目录流,和文件操作函数 open()类似,接下来 对目录的读取和搜索都要使用此返回值。函数失败则返回 NULL;

readdir()函数用来读取目录的信息,并返回一个结构体指针,该指针保存了目录的相关信息。有错误发生或 者读取到目录文件尾则返回 NULL;dirent 结构体如下:

struct dirent
{
ino_t d_ino; /* inode number(此目录进入点的 inode) */
off_t d_off; /* offset to the next dirent(目录开头到进入点的位移 */
unsigned short d_reclen; /* length of this record(目录名的长度) */
char d_name[256]; /* filename(文件名) */
};

seekdir()函数用来设置目录流目前的读取位置,再调用 readdir()函数时,便可以从此新位置开始读取。参数 offset 代表距离目录文件开头的偏移量。 telldir()函数用来返回目录流当前的读取位置。

实例:

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char * argv[])
{
struct dirent * pDirInfo;
DIR * pDir;
if (argc < 2)
pDir = opendir(".");
else
pDir = opendir(argv[1]);
if (NULL == pDir)
{
perror("open dir fail!");
return -1;
}
while ((pDirInfo = readdir(pDir)) != NULL)
printf("%s\n", pDirInfo->d_name);
closedir(pDir);
return 0;
}

9、非缓冲IO文件操作

文件描述符

一个程序(进程)可以在运行的过程中同时打开多个文件,每个程序运行起来后,系统中就有一个记录表专门 记录这个程序打开的各个文件。每打开一个文件,记录表就会用一个新的结构体变量来保存这个文件的相关信息。 如果打开多个文件,记录表中就会有多个这样的结构体变量分别保存多个文件的相关信息,它们构成了一个结构 体数组,而数组的每一个元素的下标就是所谓的文件描述符。 所以文件描述符是一个较小的非负整数(0—1023),它代表记录表的一项,即上面说的数组中的某个元素的 下标。通过文件描述符和一组基于文件描述符的文件操作函数,就可以实现对文件的打开、关闭、读写、删除等 操作。常用基于文读、写、创建、文件描述符的函数有 open(打开)、creat(创建)、close(关闭)、read(读取)、 write(写入)、ftruncate(改变文件大小)、lseek(定位)、fsync(同步)、fstat(获取文件状态)、fchmod(权限)、 flock(加锁)、fcntl(控制文件属性)、dup(复制)、dup2、select 和 ioctl。基于文件描述符的文件操作并非 ANSI C(标准 C)的函数,而是 Linux 的系统调用,即 Linux 下的 API 函数。 如果不清楚某个函数的具体实现形式,可以通过下面的方式查询 man 函数名,即可查看该函数的帮助信息。 如果要复制里面的内容,按 Ctrl+Insert 键,再粘贴的话用:Shift+Insert 键。

打开、创建、关闭文件

open 和 creat 都能打开和创建文件,原型为 #include //头文件 #include #include int open(const char *pathname, int flags); //文件名 打开方式 int open(const char *pathname, int flags, mode_t mode);//文件名 打开方式 权限 int creat(const char *pathname, mode_t mode); //文件名 权限 //现在已经不常用了 creat 函数等价于open(pathname,O_CREAT|O_TRUNC|O_WRONLY,mode); int close(int fd);//fd 表示文件描述符 open 和 creat 函数出错时返回-1,成功则返回一个整数,这个整数就是和这个打开的文件相对应的文件描述 符。通过这个返回的文件描述符我们可以对这个文件进行读写等各种操作。 相关参数如下: flags 和 mode 都是一组掩码的合成值,flags 表示打开或创建的方式,mode 表示文件的访问权限。 对于 open 函数来说,第三个参数 mode 仅当创建新文件时(即使用了 O_CREAT 时)才使用,即只有在建 立新文件时才会生效,用于指定文件的访问权限位。如果打开一个已有的文件,但是又使用了第三个参数指定了 权限,那第三个参数将不会生效,等于没有。

mode 的可选项有:

  1. S_IRWLRY 00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
  2. S_IRUSR 或 S_IREAD,00400 权限,代表该文件所有者具有可读取的权限。
  3. S_IWUSR 或 S_IWRITE,00200 权限,代表该文件所有者具有可写入的权限。
  4. S_ILRYSR 或 S_IEXEC,00100 权限,代表该文件所有者具有可执行的权限。
  5. S_IRWXG 00070 权限,代表该文件用户组具有可读、可写及可执行的权限。
  6. S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
  7. S_IWGRP 00020 权限,代表该文件用户组具有可写入的权限。
  8. S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
  9. S_IRWXO 00007 权限,代表其他用户具有可读、可写及可执行的权限
  10. S_IROTH 00004 权限,代表其他用户具有可读的权限 S_IWOTH 00002 权限,代表其他用户具有可写入的权限。 S_IXOTH 00001 权限,代表其他用户具有可执行的权限。

读写文件

读写文件的函数原型为:

#include ssize_t read(int fd, void *buf, size_t count);//文件描述词 缓冲区 长度

ssize_t write(int fd, const void *buf, size_t count);

对于 read 和 write 函数,出错返回-1,读取完了之后,返回 0, 其他情况返回读写的个数

实例:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
 int fd;
 char buf[32] = {0};
 fd = open("a.txt", O_RDWR);
 read(fd, buf, 6);
 printf("%s\n", buf);
 strcpy(buf, "hello");
 write(fd, buf, 6);
 close(fd);
 return 0;
}

改变文件大小

#include int ftruncate(int fd, off_t length);

函数 ftruncate 会将参数 fd 指定的文件大小改为参数 length 指定的大小。

参数 fd 为已打开的文件描述词,而 且必须是以写入模式打开的文件。如果原来的文件大小比参数 length 大,则超过的部分会被删去。

返回值 执行成功则返回 0,失败返回-1。

实例:

int main()
{
 int fd = open("a.txt", O_WRONLY);
 ftruncate(fd, 1000);
 close(fd);
 return 0;
}

文件定位

函数 lseek 将文件指针设定到相对于 whence,偏移值为 offset 的位置 #include #include off_t lseek(int fd, off_t offset, int whence);//fd 文件描述词 whence 可以是下面三个常量的一个 SEEK_SET 从文件头开始计算 SEEK_CUR 从当前指针开始计算 SEEK_END 从文件尾开始计算 利用该函数可以实现文件空洞(对一个新建的空文件,可以定位到偏移文件开头 1024 个字节的地方,在写 入一个字符,则相当于给该文件分配了 1025 个字节的空间,形成文件空洞)通常用于多进程间通信的时候的共 享内存。

 

int main()
{
 int fd = open("c.txt", O_WRONLY | O_CREAT);
 lseek(fd, 1024, SEEK_SET);
 write(fd, "a", 1);
 close(fd);
 return 0;
}


相关文章
|
14天前
|
Java 测试技术 Maven
Maven clean 提示文件 java.io.IOException
在使用Maven进行项目打包时,遇到了`Failed to delete`错误,尝试手动删除目标文件也失败,提示`java.io.IOException`。经过分析,发现问题是由于`sys-info.log`文件被其他进程占用。解决方法是关闭IDEA和相关Java进程,清理隐藏的Java进程后重新尝试Maven clean操作。最终问题得以解决。总结:遇到此类问题时,可以通过任务管理器清理相关进程或重启电脑来解决。
|
18天前
|
Linux 开发工具 Perl
在Linux中,有一个文件,如何删除包含“www“字样的字符?
在Linux中,如果你想删除一个文件中包含特定字样(如“www”)的所有字符或行,你可以使用多种文本处理工具来实现。以下是一些常见的方法:
39 5
|
18天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
36 6
|
18天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
53 6
|
19天前
|
监控 Linux Perl
Linux 命令小技巧:显示文件指定行的内容
在 Linux 系统中,处理文本文件是一项常见任务。本文介绍了如何使用 head、tail、sed 和 awk 等命令快速显示文件中的指定行内容,帮助你高效处理文本文件。通过实际应用场景和案例分析,展示了这些命令在代码审查、日志分析和文本处理中的具体用途。同时,还提供了注意事项和技巧,帮助你更好地掌握这些命令。
34 4
|
25天前
|
网络协议 Linux
linux系统重要文件目录
本文介绍了Linux系统中的重要目录及其历史背景,包括根目录、/usr、/etc、/var/log和/proc等目录的结构和功能。其中,/etc目录下包含了许多关键配置文件,如网卡配置、DNS解析、主机名设置等。文章还详细解释了各目录和文件的作用,帮助读者更好地理解和管理Linux系统。
46 2
|
24天前
|
缓存 监控 Linux
|
4月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
5月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
3月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。