Linux系统一编写程(一) —— 文件操作函数

  编写Linux应用程序要用到如下工具:

文件操作

  (1)编译器:GCC

展开文件

  GCC是Linux平台下最要害的开荒工具,它是GNU的C和C++编写翻译器,其主干用法为:gcc
[options] [filenames]。

1.施用open()函数张开和创办理文件件

  • 手册文件 man 2 open

函数头文件及函数原型
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

函数参数:

  pathname:待打开文件的绝对路径和文件名。

  flags:打开的旗标类型,或称模式,
  O_RDONLY      只读模式打开文件
  O_WRONLY      只写模式打开文件
  O_RDWR        读写模式打开文件
  O_CREAT       若欲打开的文件不存在则自动建立该文件
  O_TRUNC       若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为0, 
                而原来存于该文件的资料也会消失。
  O_EXCL        如果O_CREAT 也被设置, 此指令会去检查文件是否存在。 
                文件若不存在则建立该文件,否则将导致打开文件错误. 
                此外, 若O_CREAT 与O_EXCL 同时设置,并且欲打开的文件为符号连接, 
                则会打开文件失败。

  参数mode仅在flags中含有O_CREAT时有效,设定新建文文件的打开权限,有下列数种组合,
  S_IRWXU             00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
  S_IRUSR 或S_IREAD,  00400 权限,代表该文件所有者具有可读取的权限。
  S_IWUSR 或S_IWRITE, 00200 权限,代表该文件所有者具有可写入的权限。
  S_IXUSR 或S_IEXEC,  00100 权限,代表该文件所有者具有可执行的权限。
  S_IRWXG             00070 权限,代表该文件用户组具有可读、可写及可执行的权限。
  S_IRGRP             00040 权限,代表该文件用户组具有可读的权限。
  S_IWGRP             00020 权限,代表该文件用户组具有可写入的权限。
  S_IXGRP             00010 权限,代表该文件用户组具有可执行的权限。
  S_IRWXO             00007 权限,代表其他用户具有可读、可写及可执行的权限。
  S_IROTH             00004 权限,代表其他用户具有可读的权限。
  S_IWOTH             00002 权限,代表其他用户具有可写入的权限。
  S_IXOTH             00001 权限,xit代表其他用户具有可执行的权限。

函数重回值: 张开文件成功,重返三个文件汇报符
>2;张开战败,再次来到-1。

  我们应有使用linux-gcc。

唤醒:使用 access()成效户认证方面包车型大巴推断要特意小心, 举例在access()后再作open()空文件恐怕会促成系统安全上的主题素材。

  (2)调试器:GDB

2.使用create()函数创设并开垦文件

函数原型

     int creat(const char *pathname, mode_t mode);
     相当于使用调用方式,
     open(const char *pathname, (O_CREAT|O_WRONLY|O_TRUNC));

函数参数:

  pathname   待打开文件的绝对路径和文件名。

  mode       新创建文件的权限,见上面open()

函数再次来到值:若成功会回来新的文书描述符,若有错误发生则会回去-1。

  gdb是一个用来调节和测量检验C和C++程序的暴力调节和测验器,大家能因此它进行一各类调节和测验职业,包蕴安装断点、观查变量、单步等。

提醒:creat()不可能树立特意的设置文件,倘若供给请使用mknod()。

  大家理应利用linux-gdb。

读写文件

  (3)Make

1.应用read()函数从文件中读取数据

  • 手册文件 man 2 read

函数头文件及函数原型
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

函数参数:

 fd      文件指针,提供数据的文件的文件描述符,读取的数据的来源。

 buf     读到的数据所存放的内存空间的起始地址,同时文件的当前读写位置向后移。

 count   想要读取的数据的字节数,也是提供的存储空间字节数。

函数表明及再次回到值: read()会把参数fd 所指的文件传送count 个字节到buf
指针所指的内部存款和储蓄器中(暨在[0,count]距离变动)。

1.若参数count 为0,则read()不会有作用并返回0。
2.成功时,返回值为实际读取到的字节数。
3.如果返回0,表示已到达文件尾,暨碰到了EOF或是无可读取的数据。
4.此外文件读写位置会随读取到的字节移动。
5.有错误发生时则返回-1,而文件读写位置则无法预测。

   GNU
Make的首要性职业是读进三个文本文件,称为makefile。那几个文件记录了什么文件由什么文件发出,用哪些命令来发出。Make依赖此
makefile中的消息检查磁盘上的文件,假若目的文件的创建或改造时间比它的二个重视文件旧的话,make就试行相应的命令,以便更新目标文件。

提示:

read()函数担当从文件句柄中读取内定数量的字节,并将这个字节放在标量型变量中。read()函数和规范I/O函数fread()同样的法子管理I/O缓冲的。为了进步效能,read()函数实际不是一遍读取二个字节,而是读取一块数据并保存到有时存款和储蓄区中。然后,C的fread函数与Perl的read函数会从一时缓冲区将数据一回一个字节地传递给程序。print()函数(并不是write()函数担负输出read()函数重回的实际字节。print()函数类似于C中的fwrite()函数。

附加:若是顺遂 read()会回到实际读到的字节数,最CANON将重返值与参数count
作相比,若重回的字节数比要求读取的字节数少,则

  1. 读取普通文书时,读到文件末尾还远远不够 nbytes 字节。譬喻:固然文件独有 30
    字节,
    而作者辈想读取 100字节,那么实际上读到的独有 30 字节,read 函数重返 30 。
    那会儿再选择 read 函数功用于那几个文件会促成 read 重返 0 。
  2. 从极限设备(terminal device)读取时,一般情形下每一遍只好读取一行。
  3. 从网络读取时,互连网缓存也许引致读取的字节数小于 nbytes 字节。
  4. 读取 pipe 或许 FIFO 时,pipe 或 FIFO 里的字节数大概低于 nbytes 。
    5.
    从面向记录的设备读取时,某个面向记录的装置(如磁带)每趟最七只好回去一个笔录。
  5. 在读取了部分数目时被时域信号中断。读操作始于 cfo 。在中标重返此前,cfo
    增添,
    增量为实际读取到的字节数。

  Makefile中的编写翻译准则要对应地运用linux-版本。

2.施用write()函数向钦命文件中写入数据
  • 手册文件 man 2 write

函数头文件及函数原型
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

函数参数:

fd      待写入数据的文件的描述符

buf     写入数据的起始地址

count   待写入的数据的字节数

函数表达及再次回到值: write()会把参数buf 所指的内存写入count
个字节到参数fd 所指的文本内。当然,文件读写地点也会随之移动。
倘使顺遂会回到实际写入数据的字节数,表示写了有的依然全部的数额。
当有荒唐发生时,重回-1,大家要依照错误的连串来管理。要是不当为EINT哈弗表示在写时现身了制动踏板错误。借使为EPIPE表示网络连接出现了难题。

  (4)代码编辑

唤醒:对于常见文书,写操作始于 cfo 。假如展开文件时利用了 O_APPEND,则每一趟写操作都将数据写入文件末尾。成功写入后,cfo 扩大,增量为实际写入的字节数。

  能够动用古板的vi编辑器,但最佳使用emacs软件,它兼具语法高亮、版本调节等附带效能。

定点文件

预概念: 全数展开的公文都有一个脚下文件偏移量(current file
offset),以下简称为 cfo。cfo
经常是多少个非负整数,用于阐明文件早先处到文件当前任务的字节数。读写操作常常初步于
cfo,并且使 cfo 增大,增量为读写的字节数。文件被张开时,cfo 会被初阶化为
0,除非选择了 O_APPEND 。

  在宿主机上用上述工具完结应用程序的开垦后,可以透过如下门路将顺序下载到目标板上运维:

行使lseek()函数定位内定已展开文件的读写指针

  • 手册文件 man lseek

函数头文件及函数原型
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);

函数参数:

fd 待重新定位读写指针位置的文件的描述符

offset 读写指针的偏移量(可正可负可为0)

whence 读写指针的偏移位置
    SEEK_SET   相对文件首部偏移,文件偏移量将被设置为 offset。
    SEEK_CUR   相对文件当前读写位置偏移,文件偏移量将被设置为 cfo 加上 offset,
               offset 可以为正也可以为负。
    SEEK_END   相对文件尾部偏移,文件偏移量将被设置为文件长度加上 offset,
               offset 可以为正也可以为负。

函数表达及重回值:
每贰个已开垦的文书都有二个读写地点,当张开文件时一般其读写地点是指向文件初叶,若是以附加的办法打开文件(如O_应用程式END),则读写地点会针对文件尾。当read()或write()时,读写地方会随之大增,lseek()正是用来支配该文件的读写地方。参数fildes
为已开垦的文书描述词,参数offset
为基于参数whence来移动读写地方的位移数。当调用成功时则赶回前段时间的读写地点,也便是离开文件多少个字节数。若有不当则赶回-1。

例:

 将读写位置移到文件开头时: lseek(int fildes, 0, SEEK_SET);
 将读写位置移到文件尾时:   lseek(int fildes, 0, SEEK_END);
 想要取得目前文件位置时:   lseek(int fildes, 0, SEEK_CUR);

  (1)通过串口通讯协议rz将次第下载到指标板的文件系统中(感激Linux提供了rz那样的贰个下令);

提示:

1.Linux 类别不容许lseek()对tty
装置作用,此项动作会令lseek()重返ESPIPE。
2.只要参数 fd(文件叙述符)钦点的是 pipe(管道)、FIFO 恐怕socket,lseek 重回 -1 并且置 errno 为 ESPIPE。 对于普通文书(regular
file),cfo 是贰个非负整数。但对于特别规装备,cfo
有希望是负数。由此,大家无法轻松地测试
lseek 的重回值是还是不是低于 0 来判别 lseek 成功与否,而相应测量检验 lseek
的重返值是或不是等于 -1 来判别 lseek 成功与否。
3.lseek 仅将 cfo 保存于内核中,不会促成别的 I/O 操作。这些 cfo
将被用来之后的读写操作。
4.譬喻 offset
比文件的脚下长度更加大,下一个写操作就能把公文“撑大(extend)”。这正是所谓的在文件里创制”空洞(hole)”。未有被实际写入文件的有所字节由重复的
0 表示。空洞是还是不是占用硬盘空间是由文件系统(file system)决定的。

  (2)通过ftp通讯协议从宿主机上的ftp目录里将先后下载到指标板的文件系统中;

关门文件

  (3)将顺序拷入U盘,在指标机上mount U盘,运转U盘中的程序;

行使close函数关闭钦赐文件

  • 手册文件 man close

函数头文件及函数原型

 #include <unistd.h>
 int close(int fd);

函数参数:

fd    为open()或creat()打开的文件描述符。

函数表达及重回值: 当使用完已开拓的文书后若已不复供给则可使用
close()关闭该文件, 而close()会让数据写回磁盘, 并释放该公文所据有的财富.
参数fd
为先前由open()或creat()所重返的文书叙述词.**重返值:若文件顺遂关闭则再次回到0,
发生错误时回来-1.

  (4)假设目的机Linux使用NFS文件系统,则足以一贯将顺序拷入到宿主机相应的目录内,在对象机Linux中得以一向动用。

提拔:尽管在经过甘休时,系统会自动关闭已开荒的文件,但仍提出活动关闭文件,并真正检查重返值。

  1. 文书编制程序

综合案例

// ./my-cp <src_file> <dst_file>

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

#define BUFFER_SIZE 100

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        printf("usage : %s <src_file> <dst_file>\n",
            argv[0]);
        return 1;
    }

    int src_fd = 0;
    int dst_fd = 0;
    int n = 0;
    char buf[BUFFER_SIZE] = {'\0'};
    char *src_file = argv[1];
    char *dst_file = argv[2];

    // 1.open
    // 1.1 以只读方式打开源文件
    if((src_fd = open(src_file, O_RDONLY)) == -1)
    {
        perror("open src error");
        return 1;
    }
    // 1.2 以只写方式打开目的文件
    if((dst_fd = open(dst_file, 
            O_WRONLY | O_CREAT | O_TRUNC,
            S_IRUSR | S_IWUSR)) == -1)
    {
        perror("open dst error");
        return 1;
    }

    // 2. 循环从源文件中读取数据写入到目的文件中
    // 直到读到源文件的尾部为止
    // 2.1 read data from src_file
    // 2.2 write data to dst_file
    while((n = read(src_fd, buf, BUFFER_SIZE)) > 0)
    {
        write(dst_fd, buf, n);
    }

    // 3.close
    close(src_fd);
    close(dst_fd);

    return 0;
}

// 练习:
// 实现一个相对完整版的cp程序,要求能够判断出目标文件是否存在。
//  如果存在,给出提示是否覆盖。
// 思路:
// 1.打开源文件
// 2.判断目的文件是否存在
// 3.如果目的文件存在,提示是否覆盖
// 4.如果选择覆盖,则以只写的方式打开文件,并截短文件内容(O_TRUNC)
// 5.如果选择不覆盖,则提醒输入新的保存文件名,并已只写方式打开
// 6.循环读取源文件内容,写入到目的文件中
// 7.关闭已打开的文件

// 思考题1:能否关闭标准输入文件、标准输出文件、标准出错文件?

  Linux的公文操作API涉及到创制、展开、读写和破产文件。

参照他事他说加以考察资料

刘老师上课资料及互连网前辈资料
微型Computer操作系统教程:介绍今世操作系统原理及运用

  创建

  int creat(const char *filename, mode_t mode);

  参数mode钦命新建文件的存取权限, 【 Linux公社
www.Linuxidc.com 】它同umask一同决定文件的末尾权限(mode&umask),当中umask代表了文本在开立刻索要去掉的有的存取权限。umask可透过系统调用umask()来更换:

  int umask(int newmask);

  该调用将umask设置为newmask,然后回来旧的umask,它只影响读、写和实行权限。

  打开

  int open(const char *pathname, int flags);

  int open(const char *pathname, int flags, mode_t mode);
       函数表达:

  参数 pathname 指向欲张开的文书路线字符串。下列是参数 flags
所能使用的旗标:

  O_帕杰罗DONLY 以只读格局打开文件

  O_WRONLY 以只写格局张开文件

  O_奥德赛DW纳瓦拉以可读写情势张开文件。

  上述两种旗标是排斥的,也便是不可同期使用,但可与下列的旗标利用
O奥迪Q7(|)运算符组合。

  O_CREAT 若欲展开的文件空头支票则自动建构该公文。

  O_EXCL 如果 O_CREAT 也被设置,
此指令会去检查文件是不是留存。文件若不设有则树立该公文,

  不然将导致打开文件破绽相当多。 其余,若 O_CREAT 与 O_EXCL 同临时候设置,
并且欲张开的文件为标志连接,则会展开文件退步。

  O_NOCTTY
假如欲展开的文件为终端机设备时,则不会将该终端机当成进度序调控制终端机。

  O_TRUNC 若文件存在况且以可写的点子张开时,此旗标会令文件长度清为
0,而原来存于该公文的资料也会未有。

  O_APPEND 当读写文件时会从文件尾起始运动,
也正是所写入的数据会以附加的方法出席到文件前边。

  O_NONBLOCK
以不足阻断的主意张开文件,也便是随意有无数据读取或等待,都会立马回到经过之中。

  O_NDELAY 同 O_NONBLOCK。

  O_SYNC 以一头的不二等秘书诀展开文件。

  O_NOFOLLOW 假如参数 pathname
所指的文书为一符号连连,则会令张开文件失败。

  O_DIRECTO讴歌ZDXY 假设参数 pathname 所指的文书并不是为一索引, 则

  会令展开文件战败。此为 Linux2.2 未来特有的旗标,避防止有个别系

  统安全主题材料。参数 mode 则有下列数种组成,唯有在创立新文件时

  才会生效,其余真正建文件时的权柄会遭受 umask 值所影响,因而

  该文件权限应为(mode-umaks).

  S_I瑞虎WXU00700 权限, 代表该文件全数者具有可读、 可写及可进行的权位。

  S_IRUSR 或 S_IREAD,00400 权限,代表该文件全体者具有可读取的权力。

  S_IWUSR 或 S_IW索罗德ITE,00200 权限,代表该公文全体者具备可写入的权限。

  S_IXUSR 或 S_IEXEC,00100 权限,代表该文件全数者具有可推行的权柄。

  S_IEnclaveWXG 00070 权限,代表该文件用户组具有可读、 可写及可施行的权杖。

  S_I奇骏GRP 00040 权限,代表该文件用户组具有可读的权能。

  S_IWGRP 00020 权限,代表该公文用户组具有可写入的权力。

  S_IXGRP 00010 权限,代表该文件用户组具备可实行的权位。

  S_IPAJEROWXO 00007 权限,代表其余用户具备可读、可写及可举行的权力。

  S_IROTH 00004 权限,代表别的用户具备可读的权位

  S_IWOTH 00002 权限,代表别的用户具备可写入的权力。

  S_IXOTH 00001 权限,代表别的用户具备可奉行的权位。

  返回值:

  若持有欲核准的权力都经过了检查则赶回 0 值,表示成功, 【 Linux公社
www.Linuxidc.com 】只要有 多少个权力被明确命令禁止则赶回-1。

  错误代码:

  EEXIST 参数 pathname 所指的公文已存在,却使用了 O_CREAT和 O_EXCL
旗标

  EACCESS 参数 pathname 所指的文本不合乎所须要测量试验的权杖。

  EROFS 欲测量试验写入权限的文本存在于只读文件系统内。

  EFAULT 参数 pathname 指针高出可存取内部存款和储蓄器空间。

  EINVAL 参数 mode 不正确。

  ENAMETOOLONG 参数 pathname 太长。

  ENOTDIRAV4 参数 pathname 不是目录。

  ENOMEM 主旨内部存款和储蓄器不足。

  ELOOP 参数 pathname 有过多符号连接难题。

  EIO I/O 存取错误。

  读写

  在文件展开以往,大家才可对文本举行读写了,Linux中提供文件读写的系统调用是read、write函数:

  int read(int fd, const void *buf, size_t length);

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

  当中参数buf为指向缓冲区的指针,length为缓冲区的尺寸(以字节为单位)。函数read()达成从文件描述符fd所内定的文本中读取
length个字节到buf所指向的缓冲区中,再次回到值为实际读取的字节数。函数write落成将把length个字节从buf指向的缓冲区中写到文件陈说符fd所指向的文书中,再次回到值为实在写入的字节数。

  以O_CREAT为标识的open实际上实现了文件创造的效能,由此,上面包车型客车函数等同creat()函数:

  int open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);

  定位

  对于随便文件,大家得以自由的钦定地方读写,使用如下函数进行定点:

  int lseek(int fd, offset_t offset, int whence);

  lseek()将文件读写指针相对whence移动offset个字节。操作成功时,重临文件指针相对于文件头的地点。参数whence可使用下述值:

  SEEK_SET:相对文件开始

  SEEK_CUOdyssey:相对文件读写指针的当前职分

  SEEK_END:相对文件末尾

  offset可取负值,举个例子下述调用可将文件指针相对当前任务向前移动5个字节:

  lseek(fd, -5, SEEK_CUR);

  由于lseek函数的重回值为文件指针相对于文件头的职位,因而下列调用的再次回到值正是文本的尺寸:

  lseek(fd, 0, SEEK_END);

  关闭

  只要调用close就能够了,在那之中fd是大家要关张的文本叙述符:

  int close(int fd);

  上面我们来编排一个应用程序,在当前目录下创设用户可读写文件”example.txt”,在里头写入”Hello
World”,关闭文件,再一次张开它,读取其中的剧情并出口在荧屏上:

  #include

  #include

  #include

  #include

  #define LENGTH 100

  main()

  {

  int fd, len;

  char str[LENGTH];

  fd = open(“hello.txt”, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);

  if (fd)

  {

  write(fd, “Hello, Software Weekly”, strlen(“Hello, software
weekly”));

  close(fd);

  }

  fd = open(“hello.txt”, O_RDWR);

  len = read(fd, str, LENGTH);

  str[len] = ‘\0’;

  printf(“%s\n”, str);

  close(fd);

  }

图片 1

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图