嵌入式 Linux 文件IO操作

news2025/1/11 21:46:53

 

目录

 

Linux 文件操作

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

2 缓冲 IO 文件操作

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

 fopen 函数函数

2 freopen 函数

3、fdopen函数

4、fclose函数

 5、格式化读写

6、单个字符读写

7、文件定位

8、标准目录文件

9、非缓冲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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/379829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十二、MyBatis的高级映射及延迟加载

1 数据库表的准备 准备数据库表&#xff1a;一个班级对应多个学生。班级表&#xff1a;t_clazz。学生表&#xff1a;t_stu 2 环境搭建 创建模块 打包方式&#xff1a;jar 引入依赖&#xff1a;mybatis依赖、mysql驱动依赖、junit依赖、logback依赖 配置文件&#xff1a;…

C#/.net程序调用python

C#/.net程序调用python C#的优势在于window下的开发&#xff0c;不仅功能强大而且开发周期短。而python则有众多的第三方库&#xff0c;可以避免自己造轮子&#xff0c;利用C#来做界面&#xff0c;而具体实现使用python来实现可以大大提高开发效率。本文介绍如何使用pythonnet…

Kubernetes初始化容器

初始化容器 之前了解了容器的健康检查的两个探针&#xff1a;liveness probe&#xff08;存活探针&#xff09;和readiness probe&#xff08;可读性探针&#xff09;的使用方法&#xff0c;我们说在这两个探针是可以影响容器的生命周期的&#xff0c;包括我们之前提到的容器的…

如何或者无插件Web页面监控播放软件LiveNVR的固定视频流地址,实现大屏上墙、播放、视频分析等目的

1、LiveNVR介绍 LiveNVR的安防监控的视频直播&#xff0c;可以按标准的Onvif/RTSP协议接入监控设备&#xff0c;也可以通过海康、大华、天地伟业等厂家私有SDK接入监控&#xff0c;实现web页面的播放和录像回放。 可以分发HTTP-FLV、WS-FLV、WebRTC、RTMP、HLS(M3U8)、RTSP等多…

Linux安装Tomcat9

默认Linux已经安装了JDK 并且已经配置好了环境变量 下载链接 Tomcat9 下载完成如下图 &#xff0c;这个下载完成需要看一下&#xff0c;有的包里bin目录内缺少bootstrap.jar文件&#xff0c;因此下载包的时候要看看bin目录下的是不是有这个文件&#xff0c;如果没有启动Tomcat…

CHAPTER 1 Linux 集群

集群1 集群介绍2 集群分类1. 高可用性集群&#xff08;High Availability Cluster&#xff09;HA2. 负载均衡集群&#xff08;Load Balance Cluster&#xff09;LB3. 高性能集群&#xff08;High Performance Computing Cluster&#xff09;HPC3 HA集群逻辑架构1. 信息层/基础架…

Qt页面菜单栏、工具栏、状态栏

1、菜单栏 QMenu *editMenu ui->menuBar->addMenu("编辑(&E)");2、编辑菜单栏及工具栏内容 QAction *action_copy editMenu->addAction(QIcon("copy.png"),QString("复制(&c)"));action_copy->setShortcut(QKeySequence(…

数学建模竞赛的一些心得体会

1.数学建模经验首先简要的介绍一下我的情况。数学建模我也是在大一暑假开始接触的&#xff0c;之前对其没有任何的了解。我本身对数学也有相对较厚的兴趣&#xff0c;同时我也是计算机专业的学生&#xff0c;因此&#xff0c;我觉得我可参加数学建模的这个比赛。大一的暑假参加…

Linux->进程终止和等待

目录 1. 进程终止场景 1.1 进程退出码 1.2 进程常见退出方式 2. 进程等待 2.1 进程等待的必要性 2.2 进程等待的方式 wait()方式 waitpid()方式 options参数 status参数 1. 进程终止场景 代码运行完毕&#xff0c;结果正确 代码运行完毕&#xff0c;结果不正确 代码异…

【编程架构实践】关于技术栈和架构

架构是什么&#xff1f;老生常谈了。那就看看ChatGPT怎么说&#xff1a;软件架构是软件工程师在设计一个软件系统时&#xff0c;定义系统架构结构的一种科学方法。它指的是软件系统在软件工程师关注功能、性能和安全等质量属性的条件下&#xff0c;组织系统的方式。换句话说&am…

Flask源码篇:wsgi、Werkzeug与Flask启动工作流程

目录1 wsgi介绍2 使用wsgi实现一个web应用3 Werkzeug介绍4 Flask工作流程分析&#xff08;1&#xff09;创建Flask app&#xff08;2&#xff09;启动Falsk app&#xff08;3&#xff09;分析run_simple方法&#xff08;4&#xff09;分析make_server方法&#xff08;5&#xf…

内容分发网络

介绍 CDN 内容分发网络&#xff08;英语&#xff1a;Content Delivery Network 或 Content Distribution Network&#xff0c;缩写&#xff1a;CDN&#xff09;是建立并覆盖在承载网上&#xff0c;由不同区域的服务器组成的分布式网络。将源站资源缓存到全国各地的边缘服务器&…

【数据库视图】简单学习视图,了解一些视图的简单功能

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#x1f345;&#x1f345;&#x1f345;&#xff0c;今天我想带大家去了解一下数据库的视图,虽然视图这个东西在很多地方(各种公司以及项目)已经不再用了,但是许多大学生在考试的时候涉及,&#x1f6f4;&#x1f6f4;&#x1f…

【c++】STL常用容器5—list容器

文章目录list基本概念list构造函数list赋值和交换list大小操作list插入和删除list数据存取list反转和排序list基本概念 功能&#xff1a;将数据进行链式存储。 链表&#xff08;list&#xff09;是一种物理存储单元上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链…

京东物流实时风控实践

摘要&#xff1a;本文整理自京东风控数据产品组架构师周文跃&#xff0c;在 FFA 2022 实时风控专场的分享。本篇内容主要分为六个部分&#xff1a;1. 京东物流业务介绍2. 物流风控场景概括3. 物流风控平台建设4. Flink 赋能5. 技术挑战6. 未来规划Tips&#xff1a;点击「阅读原…

操作系统权限提升(二十)之Linux提权-计划任务提权

系列文章 操作系统权限提升(十八)之Linux提权-内核提权 操作系统权限提升(十九)之Linux提权-SUID提权 计划任务提权 计划任务提权原理 linux计划任务提权是因为权限配置不当&#xff0c;计划任务以root权限运行&#xff0c;低权限的用户可以修改计划任务的文件&#xff0c;…

docker启动容器服务之后访问失败

关于docker启动容器服务之后&#xff0c;宿主机访问失败&#xff08;解决方法&#xff09; 注&#xff1a;在进行docker容器启动宿主机进行容器访问时&#xff0c;无需进行网络的配置&#xff0c;docker容器在启动时会自动解决 第一种原因及修改方法 在进行启动的时候&#…

JVM虚拟机概述(1)

1.JVM概述 1.1为什么要学习JVM 通过学习JVM ( java Virtual Machine )可以帮助我们理解java程序运行的过程&#xff0c;了解虚拟机中各种机制的实现原理。为后期写出优质的代码做好准备&#xff0c;为向更高的层次提升打好基础。 1.2虚拟机 虚拟机的本质就是在windows中&…

深入浅出的学习傅里叶变换

学习傅里叶变换需要面对大量的数学公式&#xff0c;数学功底较差的同学听到傅里叶变换就头疼。事实上&#xff0c;许多数学功底好的数字信号处理专业的同学也不一定理解傅里叶变换的真实含义&#xff0c;不能做到学以致用&#xff01; 事实上&#xff0c;傅里叶变换的相关运算…

敏捷-期末

什么是敏捷开发&#xff1f; 敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。 怎么理解呢&#xff1f;它不是一门技术&#xff0c;它是一种开发方法&#xff0c;也就是一种软件开发的流程&#xff0c;它会指导我们用规定的环节去一步一步完成项目的开…