Linux编程——文件操作

文件在Linux系统中是一个广泛的概念,Linux将所有的硬件设备当作文件来处理,因此了解文件操作是十分重要的。

(一)文件和目录操作

1.stat  获取文件属性

       #include <sys/types.h>

       #include <sys/stat.h>

       #include <unistd.h>

       int stat(const char *filename,struct stat *buf);

       int fstat(fd, struct stat *buf);

       int lstat(const char *filename, struct stat *buf);

     

       fstatstat的区别是fstat通过文件描述符指定文件;lstatstat的区别在于,对于符号连接文件,lstat返回的是符号链接文件本身的状态信息,而stat返回的是符号链接指向的文件状态信心。

       成功返回0,错误范围-1

 

2.  chown 设置文件属性

       #include <sys/types.h>

       #include <unistd.h>

       int chown(const char *path,uid_t owner, gid_t group);

       int fchown(int fd, uid_t owner, gid_t group)’

       int lchown(const char *path, uid_t owner,gid_t group);

  

   fchownchown的区别是fchown通过文件描述符指定文件;lchownchown的区别在于,对于符号连接文件,lchown返回的是符号链接文件本身的状态信息,而chown返回的是符号链接指向的文件状态信心。

       成功返回0,错误范围-1

       文件的所有者只能改变文件的组id为其所属组中的一个,超级用户才能修改文件的所有者id,并且超级用户可以任意修改文件的用户组id。如果参数ownergroup指定为-1,那么文件的用户id和组id不会被改变。

 

3. truncate 改变文件大小

       #include <sys/types.h>

       #include <unistd.h>

       int truncate(const char *path, off_t length);

       int ftruncate(int fd, off_t length);

     

       将指定文件大小改为参数length指定的大小,如果原来的文件比参数length大,则超过的部分会被删除;如果原来的文件大小比参数length小,则文件将被扩展,扩展部分用0填充。

       成功返回0,错误范围-1

 

4. utime 改变文件的st_mtime域和st_ctime域,即存取时间和修改时间。

       #include <sys/types.h>

       #include <utime.h>

       int utime(const char *filename,struct utimbuf *buf);

     

       #include <sys/time.h>

       int utime(char *filename,struct timeval *tvp);

 

       struct utimbuf

       {

              time_t actime;

              time_t modtime;

       }

       如果buf是一个空指针,则存取时间和修改时间都为当前时间。

       成功返回0,错误范围-1

 

5. umake 设置文件创建时的屏蔽字,并返回以前的值

       #include <sys/types.h>

       #include <sys/stat.h>

       mode_t umask(mode_t mask);

 

6. rename 文件的移动和修改文件名

       #include <stdio.h>

       int rename(const char *oldpath, const char *newpath);

       newpath指定的文件已存在,则原文件会删除

 

7. remove 文件的删除

       #include <unistd.h>

       int unlink(const char *pathname);

       int remove(const char *pathname);

 

       文件的删除可以使用unlink系统调用,目录的删除需要使用rmdir系统调用,而通用的既能删除文件又能删除目录的系统调用是removeremove内部封装了unlinkrmdir

       成功返回0,错位返回-1

 

8. mkdir 目录的创建

       #include <sys/types.h>

       #include <sys/stat.h>

       int mkdir(const char *pathname, mode_t mode);

       成功返回0,错位返回-1

 

9. rmdir 目录的删除

       #include <unistd.h>

       int rmdir(const char *pathname);

      rmdir只能删除空目录,成功返回0,错位返回-1

 

10. getcwd 获取当前目录

       #include <unistd.h>

       char *gercwd(char *buf, size_t size);

       char *get_current_dir_name(void);

       char *getwd(char *buf);

     

       getcwd会将当前的工作目录绝对路径复制到参数buf所指的内存空间,参数sizebuf的空间大小。在调用此函数时,buf所指的内存空间要足够大,若工作目录绝对路径的字符串长度超过参数size大小,则返回值为NULLerrno的值为ERANGE。倘若参数bufNULLgetcwd()会根据参数size的大小自动分配内存(使用malloc),如果size也为0,则getcwd()会根据工作目录绝对路径的字符串长度来决定配置的内存大小。进程可以在使用完此字符串后利用free()来释放空间。

       执行成功则将结果复制到参数buff所指向的内存空间,或是返回自动分配的字符串指针,失败返回NULL.

 

11. chdir 设置工作目录

       #include <unistd.h>

       int chdir(const char *path);

       int fchdir(int fd);

       chdir将工作目录改为由path指定的目录,fchdir将工作目录改为由文件描述符fd指定的目录。

       执行成功返回0,错误返回-1

 

12. 获取目录信息

1  opendir

       #include <sys/types.h>

       #include <dirent.h>

       DIR *opendir(const char *name);

       opendir打开参数name指定的目录,并返回DIR*形态的目录刘,类似于文件描述符。成功返回目录流,失败返回NULL

2  readdir

       #include <sys/types.h>

       #include <dirent.h>

       struct dirent *readdir(DIR *dir);

       readdir用来从dir所指向的目录读取出目录的信息,返回一个struct dirent结构的指针。

       struct dirent

       {

              long d_ino;//此目录i节点编号

              off_t d_off;//目录文件开头至此目录进入点的位移

              unsigned short d_reclen;//d_name的长度

              char d_name[NAME_MAX+1];//NULL结尾的文件名

       }

       函数执行成功范围该目录下一个文件的信息。如果用opendir打开某个目录,第一次调用该函数,则返回的是该目录下的第一个文件的信息。如果发生错误或者读到目录文件尾,返回NULL

3  closedir

       #include <sys/types.h>

       #include <dirent.h>

       int *closedir(DIR *dir);

       关闭目录,成功返回0,失败返回-1

 

13. symlink建立符号链接

       #include <unistd.h>

       Int symlink(const char *actualpath, const char *sympath);

 

 

(二)文件I/O操作类型

1 文件的I/O的分类

文件的I/O分为两种类型,第一种类型是非缓冲式文件操作,主要是由系统调用提供,另一种是缓冲式I/O操作,主要是由C语言的标准输入输出库函数提供。

 

1.1    非缓冲式文件I/O操作

非缓冲式文件操作对于小规模文件的读写,或者是实时设备,执行非缓冲式文件操作,应用程序能够立即得到数据。非缓冲式文件操作的函数主要是由系统调用提供,有以下几个函数,read(),write(),lseek().

文件标识符是一个整数,系统预留了3个文件标识符:

 

0                                          代表标准输入,即通过键盘输入

1                                          代表标准输出,即输出到终端

2                                          标准错误,系统中存放错误信息的堆栈

 

打开文件

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

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

int close(int fd);

 

其中,pathname 是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面).

flags 可以是下面的一个值或者是几个值的组合

 

O_RDONLY

以只读方式打开文件

O_WRONLY

以只写方式打开文件

O_RDWR

以读写方式打开文件

O_CREAT

若要打开的文件不存在,则创建一个。权限在mode参数中说明

O_EXCL

与O_CREAT配合使用以验证一个文件是否存在

O_TRUNC

如果文件存在,且以只读或只写方式打开,则将其长度截短为0

O_NOCTTY

如果文件描述符指向终端设备,则不将此设备分配为此进程控制终端

O_APPEND

写入时追加到文件结尾

O_NONBLOCK

将后续的I/O操作设置为非阻塞方式

O_NONELAY

功能不那么完善的O_NONBLOCK

O_SYNC

只有数据被写入外存或其他设备之后操作才返回

 

也可以用数字来代表各个位的标志.Linux 总共用5 个数字来表示文件的各种权限.
00000.
第一位表示设置用户ID.第二位表示设置组ID,第三位表示用户自己的权限位,第四位表示组的权限,最后一位表示其他人的权限.

每个数字可以取1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和

 

打开文件之后我们就要对文件进行读写了.我们可以调用函数read write 进行文件的读写.

 

read(文件标识符,内存指针,内存块长度)

作用: 从文件中把数据读入到内存块中。

返回值: read函数的返回值是读取数据的长度。如果返回0,表示没有读任何数据,如果返回1,表示运行时错误。

 

write(文件标识符,内存指针,内存块长度)

作用: 将指定长度的数据写入到文件中去。

返回值: write函数返回j是实际写入文件中的数据长度。如果返回0,表示没有写任何数据,如果返回1,表示运行时错误。

 

lseek(文件标识符,偏移长度,起始位置)

作用: 用来设置读写指针的位置

起始位置有三个宏: SEEK_SET,SEEK_CUR,SEEK_END,分别是以文件开始位置,当前位置,文件尾为参考位置进行偏移。

关闭文件

Int closeint filedes

关闭一个文件时还会释放该进程加在该文件上的所有记录锁。

当一个进程终止时,内核会自动关闭它所打开的文件。因此很多程序利用这一功能而不显式的用close关闭文件。

 

1.2    缓冲式文件I/O操作

缓冲区是为程序分配的内存块,在进行数据比较大且不要求实时性的I/O操作时,一部分数据被放于缓冲区中,只有当数据块的长度要超过缓冲区的长度或时间周期到达时,才把这些数据送到指定的位置。基于缓冲区的设备操作是为了减少读写的次数,从而减小系统开销,主要适用于大量数据的读写操作。

主要的函数有: fopen,fclose,fread,fwrite,fflush,fscanf,fprintf,fgetpos,fsetpos,ftell,rewind,fgets,fputs

 

 

FILE* fopen(路径,打开方式)

参数: 打开方式有: r,w,rw+

作用: 打开一个文件,返回文件流指针,如果打开失败,则返回文件流指针为NULL.

 

fread(缓冲区指针,长度,数量,文件流指针)

参数: 第一个参数是缓冲区指针,第二个参数是每次读取文件的长度,第三个参数是最多读取的次数,最后一个参数是文件流指针

作用:从文件中读取数据放到缓冲区中去。

返回值: 实际读取到缓冲区内的次数。

 

fwrite(缓冲区指针,长度,数量,文件流指针)

参数:fread

作用: 将缓冲区内的数据写入到文件中去

返回值:实际写入文件的次数

 

fflush(文件流指针)

作用: 如果待写入的数据存在于缓冲区中,又想把数据立刻写到文件中去,则调用fflush.

 

fclose(文件流指针)

作用: 关闭文件流

fscanf(文件流指针,""控制字符串",输入项列表)

fscanf作用从文件流中读取数据保存到输入项列表中去。

fscanfscanf区别: scanf是从键盘输入,即标准输入而fscanf是从文件中输入,重定向了。

 

fprintf(文件流指针,"控制字符串","输出项列表)

fprintf作用: 将格式化后的数据输出到文件中去。

fprintfprintf区别: printf是向终端输出,而printf是向文件中输出,即重定向。

 

fgets(字符串指针,最大长度,文件流指针)

作用: 从文件读取一个字符串保存到字符串指针指向的位置,操作成功后返回字符串指针

fputs(字符串指针,文件流指针)

作用: 向文件输出一个字符串,操作成功后返回字符串的长度

 

备注:

   在一段代码前后分别使用gettimeofday可以计算代码执行时间:

struct timeval tv_begin, tv_end;

gettimeofday(&tv_begin, NULL);

foo();

gettimeofday(&tv_end, NULL);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ARM 是一种广泛使用的 CPU 架构,而 Linux 内核是一个开放源代码的操作系统内核。在 ARM 平台上,我们可以通过内核模块编程的方式与内核进行交互,实现一些自定义的功能。 下面,我们将介绍如何在 ARM Linux 上编写内核模块,并输出一个简单的 "Hello World" 消息。 ## 1. 环境准备 在开始编写内核模块之前,需要先准备好开发环境。具体步骤如下: 1. 安装交叉编译工具链。ARM 平台上的应用程序和内核模块需要使用交叉编译工具链进行编译。可以从官网下载对应的交叉编译工具链,也可以使用已经编译好的交叉编译工具链。 2. 下载内核源代码。可以从官网下载对应版本的内核源代码,也可以使用已经编译好的内核源代码。 3. 配置内核源代码。需要在内核源代码根目录下运行配置命令 `make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig` 进行配置,选择需要的模块和功能。 ## 2. 编写内核模块 在准备好开发环境之后,可以开始编写内核模块了。具体步骤如下: 1. 创建一个新的文件夹,用于存放内核模块代码。 2. 创建一个新的 C 文件,命名为 `hello.c`。 3. 在 `hello.c` 文件中编写以下代码: ```c #include <linux/init.h> #include <linux/module.h> static int __init hello_init(void) { printk(KERN_INFO "Hello, world!\n"); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, world!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple hello world module"); ``` 这段代码定义了一个简单的内核模块,当模块加载时会输出 "Hello, world!" 消息,当模块卸载时会输出 "Goodbye, world!" 消息。 4. 使用交叉编译工具链进行编译。在终端中进入 `hello.c` 文件所在的文件夹,运行以下命令进行编译: ```bash arm-linux-gnueabi-gcc -Wall -Werror -O2 -o hello.ko -c hello.c ``` 这个命令将生成一个名为 `hello.ko` 的内核模块文件。 ## 3. 加载和卸载内核模块 在编写好内核模块后,我们需要将它加载到内核中进行测试。具体步骤如下: 1. 将 `hello.ko` 文件复制到 ARM Linux 系统上。 2. 在终端中进入 `hello.ko` 文件所在的文件夹,运行以下命令以加载内核模块: ```bash insmod hello.ko ``` 这个命令将调用内核中的 `init_module` 函数,执行 `hello_init` 函数,输出 "Hello, world!" 消息。 3. 查看系统日志,可以看到 "Hello, world!" 消息。 ```bash dmesg ``` 4. 在终端中运行以下命令以卸载内核模块: ```bash rmmod hello ``` 这个命令将调用内核中的 `cleanup_module` 函数,执行 `hello_exit` 函数,输出 "Goodbye, world!" 消息。 5. 再次查看系统日志,可以看到 "Goodbye, world!" 消息。 至此,我们已经成功地在 ARM Linux 上编写了一个简单的内核模块,并输出了 "Hello, world!" 消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值