Linux下的文件操作(C语言文件和目录IO)

目录

1. 文件操作

2. 非缓冲文件操作

2.1 open函数

2.2 read / write函数

2.3 关闭文件close函数

2.4 指针移动文件

2.5 标准main函数写法------带两个参数

2.6 字符串转整数

2.7 实现cat命令

2.8 实现cp命令

2.9  初始化缓冲区

3. 带缓冲的文件操作

3.1 打开文件fopen

3.2 读写函数

3.3 关闭文件

4. 目录操作

4.1 打开目录

4.2 读目录

4.3 关闭目录


1. 文件操作

Linux下的一切设备都是文件操作。

声卡、LCD显示屏、鼠标、键盘----->都是一个文件。

文件操作操作分为:缓冲和非缓冲操作。

(1)常用的跟文件相关的命令

cat:读文件

touch:创建文件

vi、vim、gedit:编辑文件

(2)缓冲和非缓冲的区别

缓冲形式的文件操作函数(带有f的):fopen、fread、fwrite、fclose…………

用途:一般用来操作普通的文件

数据放在DDR内存空间(RAM)。

非缓冲的文件操作:open、read、write、close…………

用途:一般来操作驱动设备文件

缓冲,意味着实时性要求不是很强。因为设备驱动中,要求设备驱动能实时响应用户程序的行为,所以使用的是非缓冲形式的文件。

注:带f的是C语言标准库,不带f的是linux内核里面的函数。

2. 非缓冲文件操作

Linux下设备驱动专用的操作!

2.1 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); //带权限地打开或者创建

int creat(const char *pathname, mode_t mode);  //创建文件

API的参数:

(1)const char *pathname  :文件的路径和名称。 字符串的形式

 比如:”/work/123.c”

这里需要注意C和C++路劲的不同写法。

(2)flags 的可选项如下所示:

O_RDONLY :0x0000 以只读的方式打开文件或者设备
O_WRONLY :0x0001 以只写的方式打开

O_RDWR  :0x0002 以读写的方式打开------创建管道文件的时候,必须是这种方式
O_CREAT :0x0100 如果文件不存在,则创建文件

O_EXCL :0x0400 仅与 O_CREAT 连用,如果文件已存在,则强制 open 失败
O_TRUNC :0x0200 如果文件存在,将文件的长度截至 0
O_APPEND :0x0008
以追加的方式打开文件, 每次调用 write 时, 文件指针自动先移到文件尾,
用于多进程写同一个文件的情况。
O_NONBLOCK 非阻塞方式打开,无论有无数据读取或等待,都会立即返回进程之中。
O_NODELAY 非阻塞方式打开
O_SYNC 同步打开文件,只有在数据被真正写入物理设备设备后才返回

注:该参数可以使用|,同时设备文件的多个属性。

比如: int fd=open(“./123.c”,O_RDWR|O_CREAT);

(3)返回值:

返回值是一个小整数。这个整数称为文件描述符fd。这个文件描述符相当于一个文件信息结构的索引!

>0  :表示文件打开成功。

<0  :表示文件打开失败。

文件描述符会存放在映射表。----linux内核机制

file_info[10];

(4)mode_t mode:决定创建文件的权限!mode 的可选项:

S_IRWXU 权限,代表该文件所有者具有可读(R)、可写(W)及可执行(X)的权限。
S_IRUSR  或 S_IREAD,00400 权限, 代表该文件所有者具有可读取的权限。
S_IWUSR  或 S_IWRITE,00200 权限,代表该文件所有者具有
可写入的权限。
S_ILRYSR 或 S_IEXEC,00100 权限,代表该文件所有者具有
可执行的权限。
 

S_IRWXG 00070 权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
S_IWGRP 00020 权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。

 

S_IRWXO 00007 权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002 权限,代表其他用户具有可写入的权限。

2.2 read / write函数

所有对文件的操作的前提是,文件要先成功打开。

在linux里面查看帮助:

# man 2 read

数字2表示查看第2页的帮助信息,控制台打印输出如下:

#include <unistd.h>

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

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

(1)参数

int fd            :文件描述符。Open的返回值。

void *buf      :存放读出的数据缓冲区和写数据的缓冲区

size_t count :读出的字节数和写字节数

返回值:读写成功的字节数量

注:

(1) 对普通文件/设备文件的读写之前,都要先打开,获得文件描述符,才能进行读写操作。

(2)缓冲区:是以字节为单位

读:是读出打开的文件的数据,那么读出来了,放到哪里?放到缓冲区;

写:是将已经存在的数据(缓冲区里面的)写入已经打开了的文件;

2.3 关闭文件close函数

#include <unistd.h>

int close(int fd);

功能:关闭打开的文件。

参数:打开文件时,open()函数返回的文件描述符。

返回值:

 close() returns  zero on success.  On error, -1 is returned, and errno is set appropriately.

2.4 指针移动文件

#include <sys/types.h>

#include <unistd.h>

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

功能:移动文件指针;文件指针会按照偏移量(字节为单位),进行偏移。

参数:

int fd             :open()的返回值。

off_t offset    :偏移的属性(从哪里开始偏移)。

SEEK_SET  :文件头开始

SEEK_CUR :当前位置

SEEK_END :文件结尾

int whence   :偏移的字节数

2.5 标准main函数写法------带两个参数

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

//一般有两种写法

int main(int argc,char**argv)   // int main(int argc,char*argv[])

{

        

}

int argc    :表示传入的参数数量

char**argv :存放传入的参数缓冲区。注意:传入的参数都是以字符串的形式存在。缓冲区的数组下标从0开始的。

注:特殊之处在于缓冲区由系统分配和管理,不需要用户自定义;一个参数就是一个串,串与串之间空格隔开。

示例1:

#include<stdlib.h>

#include<stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int main(int argc,char **argv)

{

         int count=0;

         printf("总共传入了%d个参数\n",argc);

         for(;count<argc;count++)

         {

                   printf("第%d个参数:%s\n",count,argv[count]);

         }

        return 0;

}

代码运行

#./a.out 123 456 789

argc = 4

argv[0] =”a.out”

argv[1]=”123”

argv[2]=”456”

示例2:

#include <stdio.h>

#include <stdlib.h>

Int main(int argc ,char *argv[])

{

   int i=0;

   printf("argc=%d\r\n",argc);

   for(;i<argc;i++)

         {

              printf("arcv[%d]=%s\r\n",i,argv[i]);

         }

    return 0;

}

在PC机linux下,编译并测试如下:

[root@localhost test]# ./main 123 456 789

argc=4

arcv[0]=./main

arcv[1]=123

arcv[2]=456

arcv[3]=789

在嵌入式平台下编译并测试:

在宿主机上进行编译:

[root@localhost test]# arm-linux-gcc main.c -o arm-mian

[root@localhost test]# ls

arm-mian  main  main.c

在开发版中运行:

[root@WGP /test]# ls

arm-mian  main      main.c

[root@WGP /test]# ./arm-mian 1234 456 789

argc=4

arcv[0]=./arm-mian

arcv[1]=1234

arcv[2]=456

arcv[3]=789

[root@WGP /test]#

关于字符编码:Linux下通常会使用的文字编码:UTF-8 。Windows下默认使用的编码:GB2312 、(GBK) ;简称 936。

2.6 字符串转整数

比较简单的函数:

#include <stdlib.h>

int atoi(const char *nptr);      //字符串转为整数

long atol(const char *nptr);

long long atoll(const char *nptr);

long long atoq(const char *nptr);

示例1:

#include <stdio.h>

#include <stdlib.h>

Int main(int argc ,char *argv[])

{

    int data;

    data=atoi((char *)argv[1]);

    printf("data=%d\r\n",data+1);

    return 0;

}

测试如下:

[root@localhost test]# ./main 2

data=3

[root@localhost test]# ./main 222

data=223

字符串格式化输出:

#include <stdio.h>

int sprintf(char *str, const char *format, ...);

int snprintf(char *str, size_t size, const char *format, ...);

2.7 实现cat命令

实现cat命令相同的功能(相当于自己写一个cat命令,名称cat_1)

./cat  123.txt

示例代码如下:

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

int main(int argc ,char**argv[])

{

         char *file_buff=NULL;

         if(argc!=2)

         {

            printf("format:./app [filename]\r\n");

            exit(-1);

         }

         int fd=open((char *)argv[1],O_RDWR|O_CREAT);

         if(fd<0)

         {

                  printf("file_open_fail\r\n");

        }

        struct stat st;

         if(stat((char *)argv[1],&st)==-1)

         {

           printf("can not get size of file\r\n");

           exit(-1);

         }

         else

         {

           printf("byte=%d\r\n",st.st_size);

           file_buff=(char *)malloc((st.st_size+1)*sizeof(char));

          if(file_buff==NULL)

           {

             printf("fail to malloc\r\n");

             exit(-1);

          }

         }

        //char *str=file_buff;

         int re_fd=0;

         while(1)

         {

              re_fd=read(fd,file_buff,st.st_size);

              file_buff[re_fd]='\0';

             while(*file_buff!='\0')

              {

                     printf("%c",*file_buff++);

             }

              file_buff-=re_fd;

              //free(str);

             re_fd=0;

              break;

         }

         close(fd);

         return 0;

}

测试:

[root@localhost test]# ls

12.txt  main.c  rm.sh

[root@localhost test]# gcc main.c -o cat

[root@localhost test]# ls

12.txt  cat  main.c  rm.sh

[root@localhost test]# ./cat 12.txt

byte=52

123456789101112131415161718192021222324252627282930

[root@localhost test]#

注:

  1. malloc函数的使用:全局变量指针初始化要先指向空(NULL)、万能型指针(记得类型转换)
  2. Stat()函数求得的是文件的大小,文件大小包括:文件结构+文件内容
  3. Read()函数读出来的是文件里面实际内容的大小。
  4. 分配空间的时候,记得多分配一个空间(结束符),读出来的时候,要加上结束符。
  5. 指针偏移之后,记得移回来(指针减、或者先用一个指针变量保存之前分配到的空间的首地址)。

2.8 实现cp命令

实现cp命令相同的功能。

cp 123.txt 456.txt   结果:将123.txt拷贝到456.txt文件中。

示例代码:

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

main(int argc ,char *argv[])

{

         char *file_buff=NULL;

         if(argc!=3)

         {

            printf("format:./app [op_filename] [wr_filename]\r\n");

            exit(-1);

         }

         int op_fd=open((char *)argv[1],O_RDWR|O_CREAT);

         if(op_fd<0)

         {

           printf("opfile_open_fail\r\n");

          exit(-1);

        }

         int wr_fd=open((char *)argv[2],O_RDWR|O_CREAT);

         if(wr_fd<0)

         {

           printf("wrfile_open_fail\r\n");

          exit(-1);

        }

        struct stat st;

         if(stat((char *)argv[1],&st)==-1)

         {

           printf("can not get size of opfile\r\n");

           exit(-1);

         }

         else

         {

           printf("opfile_byte=%d\r\n",st.st_size);

           file_buff=(char *)malloc((st.st_size+1)*sizeof(char));

          if(file_buff==NULL)

           {

             printf("fail to malloc\r\n");

             exit(-1);

          }

         }

         int re_count=0;

         int wr_count=0;

         while(1)

         {

              re_count=read(op_fd,file_buff,st.st_size);

             wr_count=write(wr_fd,file_buff,re_count);

              if(re_count==wr_count)

             {

               re_count=0;

                wr_count=0;

               free(file_buff);

               printf("successful\r\n");

               break;

             } 

             else

             {

                re_count=0;

                 wr_count=0;

                free(file_buff);

                printf("fail\r\n");

                break;

              }

         }

         close(op_fd);

         close(wr_fd);   

         return 0;

}

测试如下:

[root@localhost test]# ls

12.txt  34.txt  main.c  rm.sh

[root@localhost test]# gcc main.c -o cp

[root@localhost test]# ls

12.txt  34.txt  cp  main.c  rm.sh

[root@localhost test]# ./cp 12.txt 34.txt

opfile_byte=52

successful

[root@localhost test]#

2.9  初始化缓冲区

#include <string.h>

void *memset(void *s, int c, size_t n);

参数:

void *s  :缓冲区的首地址

int c    :填充的数据值

size_t n :填充的长度,以字节为单位。

3. 带缓冲的文件操作

C语言标准文件操作!带缓冲的文件操作 都是对文件指针操作!

3.1 打开文件fopen

#include <stdio.h>

FILE *fopen(const char *path, const char *mode);

FILE *fdopen(int fd, const char *mode);

参数:

const char *path  :文件的路径。

const char *mode :模式

返回值:打开成功返回对应的文件指针。失败返回NULL。

mode 模式可选的值:

模式位置截断原内容创建
rbYESNO文件头NONO
r+bYESYES文件头NONO
wbNOYES文件头YESYES
w+bYESYES文件头YESYES
abNOYES文件尾NOYES
a+bYESYES文件尾NOYES

注:如果选择“截断原内容”,则操作的目标文件的原来的内容会被清空!

3.2 读写函数

#include <stdio.h>

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

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

参数:

void *ptr     :读写的缓冲区指针。

size_t size    :数据包的大小(单个)。

size_t nmemb :数据包的数量(总的)。

FILE *stream  :fopen的返回值。

返回值:读写成功的数据包数量。

注:带缓冲的,是分包进行读写或者发送的。

示例:

//写1024个数据到123.c 。

fwrite(ptr,1024 ,1 ,stream); //一次写1024个字节,写一次。

fwrite(ptr,1,1024 ,stream);  //一次写1个字节,写1024次。

参数2 3之间是一种耦合关系。

3.3 关闭文件

#include <stdio.h>

int fclose(FILE *fp);

功能:关闭打开的文件。释放文件指针占用的空间。

4. 目录操作

4.1 打开目录

#include <sys/types.h>

#include <dirent.h>

DIR *opendir(const char *name);

参数:const char *name ,目录的路径。

返回值:成功则返回DIR *  :打开的目录指针,失败就返回值空指针 NULL。

4.2 读目录

#include <dirent.h>

struct dirent *readdir(DIR *dirp);

形参:

DIR *dirp :opendir函数返回值。

返回值:正常返回struct dirent *指针,失败返回空。

struct dirent {

               ino_t          d_ino;       /* inode number */

               off_t          d_off;       /* offset to the next dirent */

               unsigned short d_reclen;      /* length of this record */

               unsigned char  d_type;      /* type of file; not supported

                                              by all file system types */

               char           d_name[256];     /*文件的名称*/

           };

4.3 关闭目录

#include <sys/types.h>

#include <dirent.h>

int closedir(DIR *dirp);

实现的功能: 遍历出指定目录下的所有文件。

C89标准 、C99标准 、C11标准

C99标准:1999年国际标准化组织颁布的C语言官方标准第二版。

C99标准:2011年国际标准化组织颁布的C语言官方标准第三版。

GCC编译器支持C11

练习:实际应用-->图片浏览器 --->视频播放器--->音乐播放器。

题目:列出指定目录下的文件。比如: xxx.bmp  、xxx.mp4  、 xxx.MP3

基础:先实现打印出完整路径。

./a.out  /etc/

打印的完整路径效果:/etc/1.c   /etc/2.txt

示例代码:

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <dirent.h>

#include <string.h>

int main(int argc ,char *argv[])

{

   if(argc!=3)

   {

     printf("./app [dirname] [file.end]\r\n");

     exit(0);

   }

  DIR *dir=NULL;

  dir=opendir(argv[1]);

  if(dir==NULL)

  {

   printf("fail_to_opendir\r\n");

   exit(0);

  }

  struct dirent *dir_data;

  int count=0;

  char *dir_name;

  char *p;

  while(dir_data=readdir(dir))

  {

       if(p=strstr(dir_data->d_name,argv[2]))

       {

          dir_name=malloc(strlen(argv[1])+strlen(dir_data->d_name)+1);

          strcpy(dir_name,argv[1]);

          strcpy(dir_name,dir_data->d_name);

          count++;

          printf("%d:%s\r\n",count,dir_name);

          free(dir_name);

       }

  }

  closedir(dir);

  return 0;

}

测试如下:

[root@localhost test]# ls

12.txt  34.txt  a.out  dir.c  dir.c~  rm.sh

[root@localhost test]# ./a.out ./ .txt

1:12.txt

2:34.txt

[root@localhost test]# ./a.out ./ .c

1:dir.c

2:dir.c~

下一篇:示例代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值