第7章 Linux下的文件编程(一)

很久没有发文章了,这次把Linux系统下的文件编程整理了一下,太久不写的话,人会变懒的所以还是得坚持哈。

第7章 Linux下的文件编程(一)

在Linux操作系统中,一切皆看成文件。Linux会将目录、设备当作特殊文件来处理。这种处理方法的意义体现在从程序设计人员的角度看所有与文件相关的系统调用是完全一样的,其接口也是一致的,使用起来非常方便,程序完全可以像使用文件一样使用磁盘、串行口、打印机及其他硬件设备。本章主要介绍Linux系统下的文件I/O操作,即基于文件描述符的文件操作,包括open、read、write、close、lseek、mkdir、opendir、readdir、rmdir等文件处理函数的详细讲解。

7.1 概述

在Linux中,针对文件的操作有两种方式,一种是通过调用C语言的库函数实现,另一种是通过系统调用实现,前者不依赖于操作系统,可以知道任何操作系统上运行;后者依赖于操作系统,对文件的操作实际上是通过系统内核提供的“接口”来实现的,不同的操作系统内核提供了不同的系统调用方法,本章主要介绍Linux之下的系统调用。

7.1.1 Linux下的系统调用

所谓系统调用是指操作系统提供好给用户程序的一种“特殊”接口,用户程序可以通过这组特殊接口来获得操作系统内核提供的特殊服务。

在Linux中,用户程序不能直接访问内核提供的服务,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间,它们分别运行在不同的级别上,在逻辑上是相互隔离的,如图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h8PN7WpJ-1655306226829)(https://files.mdnice.com/user/22712/a9e75985-cfac-4f71-8f75-cbca7ce26ba9.png)]
在Linux中,用户编程接口(API)是遵循了在UNIX中最流行的应用编程标准——统一的编程接口规范(Portable Operating System Interface,POSIX)。POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称。

7.1.2 基本I/O函数

在Linux中,read和write是基本的系统级IO函数,当应用层进程使用read和write读写Linux的文件时,进程会从用户态进入内核态,通过I/O操作读取文件中的数据。内核态(内核模式)和用户态(用户模式)是Linux的一种机制,用于限制应用可以执行的指令和可访问的地址。空间进程处于用户模式下,不允许发起I/O操作,因此,必须通过系统调用进入内核模式才能对Linux文件进行读取操作。

大多数Linux文件I/O操作用到5个函数:open ,read,write,lseek以及close。

注:要查看这些函数的帮助在命令行输入 man 2 read(函数名)

7.1.3 文件描述符

对于系统内核而言,所有打开的文件都由文件描述符引用。当打开一个现成文件或创建一个新文件时,内核就会向进程返回一个文件描述符。描述符文件描述符是一个非负整数。当进程启动时,系统会自动为其打开三个文件:标准输入、标准输出和标准错误输出,这三个文件分别对应文件描述符STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,对应的值为0、1、2

在C语言中,进程启动时,系统同样自动打开三个文件:标准输入、标准输出、标准错误输出。这三个文件都与终端相关联,因此,在不打开终端文件的情况下就可以在终端进行输入和输出操作。下表列出了文件描述符和文件指针的区别。

项目标准输入(键盘)标准输出(显示器)标准出错(显示器)
文件指针stdinstdoutstderr
文件描述符STDIN_FILENOSTDOUT_FILENOSTDERR_FILENO
文件描述符对应值012
文件指针和文件描述符的区别如下:
1.数据类型不一致

stdin、stdout和stderr类型为FILE*

STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO类型为int

使用stdin的函数主要有:fread、fwrite、fclose等,基本上都以f开头

使用STDIN_FILENO的函数有:read、write、close等。

2.本质不同

标准I/O是ANSI C建立的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定义,具有一定的可移植性。标准I/O默认采用缓冲机制,例如调用fopen函数,不仅打开一个文件,而且建立了一个缓冲区(读写模式下将建立两个缓冲区),并创建了一个包含文件和缓冲区相关数据的数据结构。当用fwrite函数向磁盘写数据时,先把数据写入流缓冲区中,当达到一定条件时,比如流缓冲区满了,或者刷新流缓冲,这时才会把数据一次送往内核提供的块缓冲,再经块缓冲写入磁盘(双重缓冲)。写入过程是:数据流->流缓冲区->内核缓存->磁盘。

STDIN_FILENO等是文件描述符。I/O操作一般没有缓冲,需要自己创建缓冲区,不过在Linux或UNIX系统中,都会使用称为内核缓冲的技术用于提高效率,读写调用是在内核缓冲区和进程缓冲区直接按进行的数据复制,在unistd.h头文件中进行定义。写入过程是:数据流->内核缓存->磁盘

每个进程都可以打开多个文件从而拥有多个文件描述符,能打开的文件数量取决于操作系统,Linux中的每个进程最多可以打开1024个文件。可以在终端输入命令ulimit -n来查看当前操作系统下启动的进程最多能打开的文件数量。

7.2 基本I/O操作

本节将详细介绍文件打开、读取、写入、关闭以及移动文件读写指针操作。使用文件操作基本函数,必须将相关头文件引入到程序中,作为初学者,可以使用man手册来查看相关的头文件。

7.2.1 open函数

open函数的功能是打开或者创建文件,对文件进行读写操作之前都需要打开文件,所以open是对文件数据进行存取必须完成的系统调用。由于open本身也是shell命令,所以要查看open函数的帮助信息,要输入man 2 open,表示在手册的第二节找到相关信息。下面详细介绍函数所需头文件、函数原型以及函数返回值。

open函数所需头文件:

#includ e <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

open函数的原型有两种:

第一种为int open(const char *pathname,int flags,mode_t  mode);
第二种为int open(const char *pathname,int flags)。
当使用open创建一个新文件时,使用第一种有三个参数的open函数;当使用open打开一个文件时,使用第二种有两个参数的open函数。

其中,参数pathname是要创建文件或打开文件的路径(绝对路径/相对路径)。
注:这里创建的文件是文本文件。

参数flags用来标识打开方式。由两组符号常数进行或运算构成flags参数(这些常数定义在<fcntl.h>头文件中)下表列出了构成flags参数的两组符号常数。

第一组(打开方式)说明第二组(其他选项)说明
O_RDONLY以只读方式打开文件O_CREAT需要创建新文件时加上该参数,使用open函数三个参数的原型
O_WRONLY以只写方式打开文件O_EXCL此参数可测试文件是否存在。若文件存在时而使用了O_CREAT和O_EXCL,那么返回值为-1,errno的值为17,对应的错误描述应该是File Exist
O_RDWR以读写方式打开文件O_APPEND每次进行写入操作时,将新内容追加到文件尾部
O_TRUNC每次进行写入操作时,先将文件内容清空,再将文件指针移到文件头。

上述两组参数之间用”|“符号进行连接,open函数的第三个参数mode是在创建文件时使用的,用来指定文所创建文件的存取权限,其符号常量和八进制值的对应关系如下表。对于mode,可以使用符号常量,也可以使用按位进行或运算来计算权限。

知识补充1

文件权限是针对三类用户进行的,三类用户分别是文件属主(u)、文件属组用户(g)和其他用户(o)。

权限类型分为三种,读®、写(w)、执行(x),对应的加权值为4,2,1。

例如:新建文件的权限设置为642,则表示属主对文件的操作权限为6=4+2,意味着对文件具有读写权限;属组用户对文件的操作权限为4,意味着对文件具有读权限;其他用户对文件的操作权限为1,意味着对文件具有执行权限

mode参数说明
符号常量说明
S_IRUSR属主拥有读权限
S_IWUSR属主拥有写权限
S_IXUSR属主拥有执行权限
S_IRGRP属组拥有读权限
S_IWGRP属组拥有写权限
S_IXGRP属组拥有执行权限
S_IROTH其他用户拥有读权限
S_IWOTH其他用户拥有写权限
S_IXOTH其他用户拥有执行权限

知识补充2

在使用open函数打开一个文件时,除了设置打开方式外,还要考虑文件本身的存取许可。见例7-1.

open函数返回值:如果调用成功则返回文件描述符,若出错则返回-1.通过返回值可以判断系统调用是否成功,从而实现对程序的逻辑控制。

注:在vim编辑器中按原格式粘贴的办法,在命令行模式下输入: set paste 然后回车粘贴。

例7-1

在当前目录下创建名为open_test的文件,以只读的方式打开,并设置其权限为:属主可读可写可执行,属组用户可读,其他用户无任何权限。

open函数的原型有两种:
第一种为int open(const char *pathname,int flags,mode_t  mode);
第二种为int open(const char *pathname,int flags)。
//1.open函数所需头文件
#includ e <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//2.输入输出头文件
#include<stdio.h>

//3.调用open函数创建open_test文件
int main()
{
	int fd;//4.声明变量fd,保存文件描述符
	fd=open("open_test",O_RDONLY|O_CREAT,740);//在当前目录下创建open_test文本文件
	//如果是open_test.txt就是在源程序同级目录下创建文本文件open_test.txt,可以加后缀标识文件类型
	//5.通过open函数返回值来判断文件创建是否成功
	if(fd==-1)
	{
		perror("创建失败!");//6.perror函数可以将errno中的错误信息输出
		return -1}
	else
	{
		printf("创建成功!");
		printf("%d\n",fd);
	}	
		
}

实验步骤:

  • 首先创建一个空的文件夹dotest进行测试,在该文件夹下创建test.c文件
  • 执行gcc test.c -o a.out指令,编译test.c文件,执行gcc命令后,出现a.out的可执行文件
  • 执行./a.out执行可执行文件,然后会创建一个open_test文件夹。
  • 查看文件的权限,ls -l open_test
[zsh@localhost test1]$ ls
test.c
[zsh@localhost test1]$ gcc test.c -o a.out
[zsh@localhost test1]$ ls
a.out  test.c
[zsh@localhost test1]$ ./a.out
创建成功!3
[zsh@localhost test1]$ ls
a.out  open_test  test.c
[zsh@localhost test1]$ ls -l open_test
--wxr--r-T 1 zsh zsh 0 5月  26 18:02 open_test
[zsh@localhost test1]$ 

注:Linux权限分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1nOTCunt-1655306226838)(https://files.mdnice.com/user/22712/8e285059-1fa2-488a-a5bc-c1a525a00901.png)]

例 7-2

使用open函数将上例中创建的open_test以读写的方式打开,若打开成功则输出“打开成功”的字符串,若失败请分析原因。

#includ e <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>

int main()
{
    int fd;
    fd=open("open_test",O_RDWR);
    if(fd==-1)
    {
      perrno("打开失败");
      return -1;
    }
    else 
    {
      printf("打开成功%d",fd);
    }
    return 0;
}
[zsh@localhost test1]$ vi open.c
[zsh@localhost test1]$ gcc open.c -o open.out
[zsh@localhost test1]$ ls
a.out  open.c  open.out  open_test  test.c
[zsh@localhost test1]$ ./open.out 
打开失败: Permission denied
#查看打开失败的原因,权限不够,不能读文件夹
[zsh@localhost test1]$ ls -l open_test 
--wxr--r-T 1 zsh zsh 0 526 18:02 open_test
[zsh@localhost test1]$ chmod u+r open_test  #给属主用户添加r读权限
[zsh@localhost test1]$ ./open.out 
打开成功3[zsh@localhost test1]$   #现在打开成功了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uU9n4j2D-1655306226839)(https://files.mdnice.com/user/22712/494109c1-d6f2-4400-bf0b-64e8b1ca0718.png)]

7.2.2 close函数

close函数的功能是关闭一个已经打开的文件。

close函数所需的头文件:#include<unistd.h>

close函数的原型:int close(int fd);其中fd是文件描述符。返回值若是0,表示执行成功;返回值若是-1,则表示执行失败。

当一个进程终止时,它所有的打开文件都由内核自动关闭。很多程序都使用这一功能而不显示地用close关闭打开文件。

示例:修改open.c文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include<unistd.h>  //close函数所需的头文件

int main()
{
    int fd;
    fd=open("open_test",O_RDWR);
    if(fd==-1)
    {
      perror("打开失败");
      return -1;
    }
    else
    {
      printf("打开成功%d",fd);
      int result;
      result=close(fd);//调用关闭函数
      printf("关闭成功%d",result);
    }
    return 0;
}
[zsh@localhost test1]$ gcc open.c -o open.out
[zsh@localhost test1]$ ./open.out
打开成功3关闭成功0[zsh@localhost test1]$ 

7.2.3 write函数

write函数的功能是向已打开的文件写数据。

write函数需要包含的头文件:#include<unistd.h>

write函数的原型:

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

其中,fd为文件描述符。buf表示写入文件的数据缓冲区地址。count表示写入的字节数。

返回值:若调用成功,则返回已经写入的字节数;若失败,返回-1。常见的出错原因是磁盘空间已满或者超过了文件大小的限制。

例 7-3

使用open函数将open_test以读写方式打开后,使用write函数向文件中写入数据。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
	int fd;
	fd=open("open_test",O_RDWR);
	if(fd==-1)
	{
		perror("打开失败!");
		return -1;
	}
	else
	{
		//使用write函数向文件open_test中写入字符串
		int ssize=write(fd,"hello,myname is Codersong,也叫西里小诸葛",5);
        //int ssize=write(fd,"hello,myname is Codersong,也叫西里小诸葛",40);
		if(ssize==-1)
		{
			perror("写入失败");
			return -1;
		}
		else
		{
			printf("写入成功,写入字节:%d",ssize);
		}
	}
	return 0;
}

编译运行的结果:

[zsh@localhost test1]$ vi write_test.c
[zsh@localhost test1]$ gcc write_test.c -o write_test.out
[zsh@localhost test1]$ ls
open.c  open.out  open_test  test.c  test.out  write_test.c  write_test.out
[zsh@localhost test1]$ ./write_test.out
写入成功,写入字节:5  #写入字节5,所以超出5字节的内容没有写入
[zsh@localhost test1]$ ls
open.c  open.out  open_test  test.c  test.out  write_test.c  write_test.out
[zsh@localhost test1]$ cat open_test
hello[zsh@localhost test1]$ ./write_test.out
写入成功,写入字节:5
[zsh@localhost test1]$ cat open_test   #第二次执行还是只显示一行的hello,说明是覆盖了原文件
hello
#修改写入字节数
[zsh@localhost test1]$ ./write_test.out
写入成功,写入字节:50[zsh@localhost test1]$ 
[zsh@localhost test1]$ cat open_test
hello,myname is Codersong,也叫西里小诸葛

编译上述源程序,执行后,使用vi(或者cat)查看open_test的内容是hello…西里小诸葛

思考:若运行n次后,open_test的内容是什么?是一个hello还是n个hello?

解读:这个思考实际上是看写入的方式是追加还是覆盖。经过测试:默认写入方式是覆盖。

知识补充:

用open函数打开文件后,对文件后续的读和写操作都是从文件指针所指向的位置开始的,每次打开文件后,文件指针默认指向文件头,所以上例中每次的写入操作都是从头开始,因此无论运行多少次,open_test内容都是最后一次写入的"hello"字符串。

如果希望将每次写入的内容追加到文件尾,则需要使用open函数中的O_APPEND。将函数调用语句改成:

fd=open("open_test",O_RDWR|O_APPEND);

重新对更改后的源文件进行编译、链接,运行后查看open_test为"hellohello",实现了将内容追加到文件尾的目的。

如果希望每次写入内容前清空文件内容,则需要使用open函数中的O_TRUNC。将函数调用语句改成:

fd=open(“open_test”,O_RDWR|O_TRUNC);

[zsh@localhost test1]$ cat open_test
hello
[zsh@localhost test1]$ ./write_test.out
写入成功,写入字节:5
[zsh@localhost test1]$ cat open_test
hellohello
例 7-4

编写程序,实现在当前目录下创建10个文件,文件名为1.dat,2.dat,…,10.dat,并将整数1,2,3…10分别写入文件。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
	int fd,i;
	char filename[10];
	for(i=1;i<=10;i++)
	{
		sprintf(filename,"%d.dat",i);
		fd=open(filename,O_RDWR|O_CREAT,644);
		if(fd==-1)
		{
			perror("创建失败\n");
			return -1;
		}
		int ssize=write(fd,&i,sizeof(int));
		if(ssize==-1)
		{
			perror("写入失败!");
			return -1;
		}
	}
}

注:查看二进制文件可使用od命令。例如:od 1.dat

本例中的sprintf函数的功能是把格式化的数据写入字符数组。执行结果如下:

[zsh@localhost test1]$ gcc test2.c -o test2.out #编译源代码
[zsh@localhost test1]$ ls
open.c  open.out  open_test  test2.c  test2.out  test.c  test.out  write_test.c  write_test.out
[zsh@localhost test1]$ ./test2.out #执行可执行程序
[zsh@localhost test1]$ ls  #此时多了10个.dat文件
10.dat  2.dat  4.dat  6.dat  8.dat  open.c    open_test  test2.out  test.out      write_test.out
1.dat   3.dat  5.dat  7.dat  9.dat  open.out  test2.c    test.c     write_test.c
[zsh@localhost test1]$ od 1.dat
od: 1.dat: 权限不够
[zsh@localhost test1]$ ls -l 1.dat
--w----r-T 1 zsh zsh 4 527 00:23 1.dat
[zsh@localhost test1]$ chmod u+r 1.dat  #权限不够给文件属主添加读权限
[zsh@localhost test1]$ od 1.dat
0000000 000001 000000
0000004
[zsh@localhost test1]$ chmod u+r 2.dat
[zsh@localhost test1]$ od 2.dat
0000000 000002 000000
0000004
7.2.4 read函数

read函数的功能是向已打开的文件读取数据。

read函数需要包含的头文件:#include<unistd.h>

read函数的原型:

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

其中,fd为文件描述符;buf表示读出数据缓冲区地址;count表示读出的字节数。

返回值:若调用成功,则返回读到的字节数;若失败,返回-1;若已经达到文件尾,则返回0.因此读到的字节数可能小于count的值。

例 7-5

将例7-4中文件的数据读出并输出到屏幕上。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
	int fd,i,j;
	char filename[10];
	for(i=1;i<=10;i++)
	{
		sprintf(filename,"%d.dat",i); //把格式化的数据写入字符数组
		fd=open(filename,O_RDWR);
		if(fd==-1)
		{
			perror("打开文件失败\n");
			return -1;
		}
		read(fd,&j,sizeof(int));
        printf("%d\n",j);
	}
}

结果:

[zsh@localhost test1]$ vi read_test.c
[zsh@localhost test1]$ gcc read_test.c -o read_test.out
[zsh@localhost test1]$ ./read_test.out
1
2
打开文件失败
: Permission denied
[zsh@localhost test1]$ chmod u+r ./*.dat
[zsh@localhost test1]$ ./read_test.out
1 2 3 4 5 6 7 8 9 10 
例 7-6

将例7-4中的文件数值加1

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
	int fd,i,j;
	char filename[10];
	for(i=1;i<=10;i++)
	{
		sprintf(filename,"%d.dat",i); //把格式化的数据写入字符数组,字符数组存储了10个文件名
		fd=open(filename,O_RDWR);
		if(fd==-1)
		{
			perror("打开文件失败\n");
			return -1;
		}
		read(fd,&j,sizeof(int));//读取文件的数据存放在变量j中。
        j++;
        write(fd,&j,sizeof(int));
	}
    return 0;
}
#结果
[zsh@localhost test1]$ vi read_test.c
[zsh@localhost test1]$ gcc read_test.c -o read_test.out
[zsh@localhost test1]$ ./read_test.out
2 3 4 5 6 7 8 9 10 11 

程序运行后,用od命令查看.dat文件的内容发现,变量j的值追加到文件尾,而不是覆盖原先的值。具体如下所示:

[zsh@localhost test1]$ od 2.dat
0000000 000002 000000 000003 000000
0000010

原因是read函数被调用后,文件指针也从文件头向右偏移了读取的字节数(这里是一个整型所占的字节数),那么调用write函数时,写入操作是从当前文件指针位置开始的,因此.dat文件中就出现了两个数据,如何解决这个问题呢,请见7.2.5 lseek函数

总结文件描述符fd就是描述文件状态的,fd实际上是一个int值,我们根据文件描述符fd对文件进行读写改操作,不同的返回值就反应了操作的正确与否。

7.2.5 lseek函数

所有打开的文件都有一个当前文件的偏移量(又叫文件指针),文件指针通常是一个非负整数,用于表示文件开始处到文件当前位置的字节数。因此,文件偏移量以字节为单位。

对文件的读写操作开始于文件偏移量,并且使文件偏移量增大,增量为读写的字节数。文件被打开时,文件偏移量为0,即文件指针指向文件头(在打开时使用O_APPEND除外)。

lseek函数的功能就是设置偏移量的值,即可以改变文件指针的位置,从而实现对文件的随机存取。

lseek函数所需头文件:

#include<sys/types.h>

#include<unistd.h>

lseek函数的原型:off_t lseek(int fd, off_t offset, int whence);

其中,fd为文件描述符。

offset:偏移量,指的是每一读写操作所需移动距离,以字节为单位,可正可负,正值表示向文件尾方向移动,负值表示向文件首方向移动。

whence:当前位置的基点,主要有以下三个基点符号常量,通常前两个基点用得比较多。

SEEK_SET,将该文件的位移量设置为距文件开始处offset个字节。

SEEK_CUR,将该文件的位移量设置为其当前值加offset,offset可为正或负。

SEEK_END,将该文件的位移量设置为文件长度offset,offset可为正或为负。

那么例7-6出现的问题就可以使用lseek函数移动指针的方法来解决。代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
	int fd,i,j;
	char filename[10];
	for(i=1;i<=10;i++)
	{
		sprintf(filename,"%d.dat",i); //把格式化的数据写入字符数组,字符数组存储了10个文件名
		fd=open(filename,O_RDWR);
		if(fd==-1)
		{
			perror("打开文件失败\n");
			return -1;
		}
		read(fd,&j,sizeof(int));//读取文件的数据存放在变量j中。
        j++;
        //或者lseek(fd,-4,SEEK_CUR),目的是将文件指针移动到文件首,整型类型占4个字节。
        lseek(fd,0,SEEK_SET);
        write(fd,&j,sizeof(int));
	}
    return 0;
}

#结果:
[zsh@localhost test1]$ vi test2.c
[zsh@localhost test1]$ gcc test2.c -o test2.out
[zsh@localhost test1]$ ./test2.out
[zsh@localhost test1]$ ls
10.dat  2.dat  4.dat  6.dat  8.dat  
1.dat   3.dat  5.dat  7.dat  9.dat  test2.c   test2.out
[zsh@localhost test1]$ od 1.dat
0000000 000002 000000
0000004
例 7-7

在a.dat中依次写入’a’到’z’,然后使用lseek定位读取’c’并输出。

//seek_test.c文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
    int fd;
    fd=open("a.dat",O_RDWR);
    if(fd==-1)
    {
    	perror("打开失败\n");
    	return -1;
    }
    char c;
    for(c='a';c<='z';c++)
    {
    	write(fd,&c,sizeof(char));
    }
    lseek(fd,2,SEEK_SET);
    char read_c;
    read(fd,&read_c,1);//字符型数据在内存中占1个字节
    printf("读取的字符为%c",read_c);
}
//output输出
[zsh@localhost test]$ ls
a.dat  seek_test.c
[zsh@localhost test]$ gcc seek_test.c -o seek_test.out
[zsh@localhost test]$ ls
a.dat  seek_test.c  seek_test.out
[zsh@localhost test]$ ./seek_test.out
读取的字符为c
[zsh@localhost test]$ od a.dat
0000000 061141 062143 063145 064147 065151 066153 067155 070157
0000020 071161 072163 073165 074167 075171
0000032
[zsh@localhost test]$ vi a.dat
[zsh@localhost test]$ cat a.dat
abcdefghijklmnopqrstuvwxyz[zsh@localhost test]$
例 7-8

在a.dat中依次写入数字1-100,然后使用lseek定位读取28并输出

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
    int fd;
    fd=open("a.dat",O_RDWR);
    if(fd==-1)
    {
    	perror("打开失败\n");
    	return -1;
    }
    int i;
    for(i=1;i<=100;i++)
    {
    	write(fd,&i,sizeof(int));
    }
    lseek(fd,108,SEEK_SET);//108=(28-1)*4
    int read_i;
    read(fd,&read_i,4);//整型数据在内存中占4个字节
    printf("读取的字符为%d",read_i);
}
//output
[zsh@localhost test]$ vi seek_test.c
[zsh@localhost test]$ gcc seek_test.c -o seek_test.out
[zsh@localhost test]$ ./seek_test.out
读取的字符为28

看到这里的小伙伴,相信你已经对Linux下的文件编程有进一步的了解了,快去Linux系统试一试吧,检验一下你的学习成果。


狂肝了6000多字,创作不易,麻烦各位小伙伴多转发,多点赞,加关注、收藏,一起加油!如果有小伙伴在公众号CoderSong上看到一样的文章的话,不用怀疑,那就是我本人啦,嘻嘻。

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西里小诸葛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值