Linux-C 文件操作

Linux-C 文件操作

一、简述

         记--Linux环境下C语言编程的文件操作。

         两种操作文件的方式:

        1、系统I/O:系统调用接口,open(), read(), write(), lseek(), close()。是操作系统直接提供的编程接口(API)。

        2、标准/IO:标准库的I/O函数,fopen(), fread(), fwrite(), fseek(), fclose(),是对系统调用接口进一步封装。

        系统I/O常用于硬件级别,可以设置读缓冲区,一般没有写缓冲区;

        标准I/O常用于软件级别,自带读写缓冲区。

二、系统I/O

       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);
参数 pathname 要打开的文件路径名称
flags O_RDONLY 只读方式打开文件 这三个参数互斥
O_WRONLY 只写方式打开文件
O_RDWR 读写方式打开文件
O_CREAT 如果文件不存在,则创建该文件  
O_TRUNC 如文件已经存在,则删除文件中原有数据  
O_APPEND 以追加方式打开文件  
mode 如果文件被新建,指定其权限为mode(八进制表示法)
返回值 成功 大于等于0 的整数(即文件描述符)
失败 -1,并且errno会被设置

补充说明:

1)flags 的各种取值可以用位或的方式叠加起来,例如创建文件的时候需要满足这样的
选项:读写方式打开,不存在要新建,如果存在了则清空。则flags 的取值应该是:O_RDWR | O_CREAT | O_TRUNC。
2)mode 是八进制权限,比如0644,或者0755 等。也可以是使用系统已定义的

              S_IRWXU  00700 user (file owner) has read,  write,  and  execute permission //用户可读写执行权限

              S_IRUSR  00400 user has read permission//用户写权限

              S_IWUSR  00200 user has write permission//用户写权限

              S_IXUSR  00100 user has execute permission//用户执行权限      (更多选项可查询man手册:man 2 open)

              比如新创建的文件权限只需要读写权限:S_IRUSR  | S_IWUSR  

3)文件描述符

         其实是一个数组的下标值,在内核中打开的文件是用 file 结构体来表示的,每一个结构体都会有一个 指针来指向它们,这些指针被统一存放在一个叫做 fd_array 的数组当中,而这个数组被存 放在一个叫做 files_struct 的结构体中,该结构体是进程控制块 task_struct 的重要组成部分。

     2.2 close()函数

功能

关闭文件并释放相应资源

头文件

#include <unistd.h>

原型

int close(int fd);

    参数       fd 要关闭的文件的描述符

返回值

成功

0

失败

-1

备注

重复关闭一个已经关闭了的文件或者尚未打开的文件是安全的。

     2.3 read()函数

功能

从指定文件中读取数据

头文件

#include <unistd.h>

原型

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

 

     参数

fd

从文件 fd 中读数据,(fd是某个文件的描述符)

buf

指向存放读到的数据的缓冲区,(就是放数据的内存首地址)

count

想要从文件 fd 中读取的字节数

返回值

成功

实际读到的字节数

失败

-1

备注

实际读到的字节数小于等于 count

补充说明:

     ssize_t :是类型重定义,为了跨平台兼容。比如说long在32位系统可能是4字节,64位系统可能是8字节,嵌入式开发有的只有16位,那么int只有2个字节。

但是在编程时往往需要根据类型大小来进行操作数据,例如在64位系统编程时8字节使用long类型,如果移植到32位系统时long只有4字节,那么就需要改动好多个地方,所以重定义一种类型,然后根据实际系统再指定,方便改动移植。例如:重定义ssize类型是8字节的,在32位系统,我可以将long long重定义为ssize类型,如果是64位系统可以定义为long类型,这样只需改动一处。

 2.4 write()函数

功能

将数据写入指定的文件

头文件

#include <unistd.h>

原型

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

参数

fd

将数据写入到文件fd 中 (fd是某个文件的描述符)

buf

指向即将要写入的数据,(要写的数据的内存首地址)

count

要写入的字节数

返回值

成功

实际写入的字节数

失败

-1

备注

实际写入的字节数小于等于 count

2.5 lseek()函

功能

调整文件位置偏移量

头文件

#include <sys/types.h>

#include <unistd.h>

原型

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

参数

fd

要调整位置偏移量的文件的描述符

offset

相对基准点的偏移大小

whence:基准点

SEEK_SET:文件开头处

SEEK_CUR:当前位置

SEEK_END:文件末尾处

返回值

成功

新文件位置偏移量(相对于文件开头的偏移)

失败

-1

备注

可用 file-size= lseek(fd,0,SEEK_END);来测量文件大小

     示例代码:

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

int main(int argc,char* argv[])
{
	int fd;
	int wr_ret;
	int rd_ret;
	unsigned long file_size;
	char wr_buf[100] = "hello world";
	char rd_buf[100];

	fd = open("a.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IROTH);//等价于fd = open("a.txt", O_RDWR | O_CREAT | O_TRUNC, 0x604);
	if(fd == -1)
	{
		perror("open file error:");//只有上面的函数设置了error全局错误号,才可使用,会根据error输出对应的错误信息
		return -1;
	}
	printf("fd = %d\n", fd);

	wr_ret = write(fd, wr_buf, sizeof(wr_buf));
	if(wr_ret == -1)
	{
		perror("write file error:");
		return -1;
	}
	printf("wr_ret = %d\n", wr_ret);

	lseek(fd, 0, SEEK_SET);//上面的写操作,文件位置偏移量也会相应的移动,此处将文件偏移到文件开始位置,然后才能读取刚刚输入的内容
	rd_ret = read(fd, rd_buf, sizeof(rd_buf));
	if(rd_ret == -1)
	{
		perror("read file error:");
		return -1;
	}
	printf("rd_ret = %d\n",rd_ret);
	printf("content=%s\n", rd_buf);

	file_size = lseek(fd, 0, SEEK_END);
	printf("file_size = %lu\n", file_size);

	close(fd);//关闭文件

	return 0;
}

     运行结果:
              

 2.5 mmap()函数

功能

将物理内存映射为虚拟内存,为了提高效率。(比如将一个文件映射到虚拟内存,以操作内存的方式进行数据的读写,但是不会改变文件的大小,一般不用于普通文件)

头文件

#include <sys/mman.h>

原型

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

 

      参数

addr 从虚拟内存的哪个地址开始去映射这片内存
        NULL代表由系统决定映射起始地址
length 映射的内存长度(字节为单位)

port

决定这块内存的操作权限,以下数值可以相或
         PROT_EXEC  Pages may be executed.  执行权限

         PROT_READ  Pages may be read.      读权限

         PROT_WRITE Pages may be written.   写权限

         PROT_NONE  Pages may not be accessed.  无权限

flags 操作标志
        MAP_SHARED:在多进程中把这块内存共享给其他进程    
        MAP_PRIVATE:不共享内存

fd

将数据写入到文件fd 中 (fd是某个文件的描述符)

offset

基于文件头偏移多少单位开始映射

 

      返回值

成功

成功返回映射的虚拟地址

失败

失败返回MAP_FAILED,其实就是个-1, errno会被设置

 

    备注

取消映射   int munmap(void *addr, size_t length);
    addr:映射的起始地址
    length:取消的长度

成功返回0,失败返回-1

   更多请查看man手册:man 2 mmap

示例代码:

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h> //mencpy()

int main(void)
{
	int fd;
	char *map_ptr;

	int retval;

	fd = open("a.txt",O_RDWR);
	if(fd == -1)
	{
		perror("open failed:");
		return -1;
	}
	

	map_ptr = mmap( NULL, 100, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if(map_ptr == MAP_FAILED)
	{
		perror("map memory failed:");
		return -1;
	}

	printf("%s", map_ptr);

	memcpy(map_ptr, "haha", 5);


	retval = munmap(map_ptr, 100);
	if(retval == -1)
	{
		perror("munmap failed:");
		return -1;
	}

	close(fd);

	return 0;
}

运行结果:

三、标准I/O

     3.1 fopen()函数

功能

获取指定文件的文件指针

头文件

#include <stdio.h>

原型

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

 

 

 

 

 

 

 

 

 

 

参数

path

要打开的文件的路径名称

mode

“r” : 以只读方式打开文件,要求文件必须存在。

“r+” : 以读写方式打开文件,要求文件必须存在。

“w” :  以只写方式打开文件,文件如果不存在将会创建新文件,如果存

在将会将其内容清空。

“w+” :  以读写方式打开文件,文件如果不存在将会创建新文件,如果存在将会将其内容清空。

“a” : 以只写方式打开文件,文件如果不存在将会创建新文件,且文件位置偏移量被自动定位到文件末尾(即以追加方式写数据)。

“a+” : 以读写方式打开文件,文件如果不存在将会创建新文件,第一次用于写数据则文件位置偏移量被自动定位到文件末尾(即以追加方式写数据),如果第一次用于读数据,文件位置偏移位置会定位到文件开始。

    返回值

成功

文件指针

失败 NULL
      备注

返回的文件指针是一种指向结构体 FILE{}的指针,文件描述符就被封装在FILE结构体里面

        程序一开始默认打开3个文件

设备

文件描述符(int)

文件指针(FILE *)

标准输入设备(键盘)

0

STDIN_FILENO

stdin

标准输出设备(屏幕)

1

STDOUT_FILENO

stdout

标准出错设备(屏幕)

2

STDERR_FILENO

stderr

     3.2 fclose()函数

   

功能

关闭指定的文件并释放其资源

头文件

#include <stdio.h>

原型

int fclose(FILE *fp);

参数

fp

即将要关闭的文件

 

返回值

成功

0

失败

EOF

备注

fclose( )不能对一个文件重复关闭

     3.3 fread()函数

       

功能

从指定文件读取若干个数据块

头文件

#include <stdio.h>

原型

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

 

参数

     ptr

自定义缓冲区指针,(通俗的说就是要存放 读取出来的数据 的地方)

     size 

数据块大小

 nmemb

数据块个数

  stream

即将被读取数据的文件指针

返回值

成功

读取的数据块个数,等于 nmemb

失败

读取的数据块个数,小于 nmemb 或等于 0

备注

当返回小与 nmemb 时,文件 stream 可能已达末尾,或者遇到错误

     3.4 fwrite()函数

功能

将若干块数据写入指定的文件

头文件

#include <sys/ioctl.h>

原型

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

参数

ptr:自定义缓冲区指针

size:数据块大小

nmemb:数据块个数

stream:即将被写入数据的文件指针

返回值

成功

写入的数据块个数,等于 sinmembze

失败

写入的数据块个数,小于 nmemb 或等于 0

备注

     3.5 fseek()函数

功能

设置指定文件的当前位置偏移量

头文件

#include <sys/ioctl.h>

原型

int fseek(FILE *stream, long offset, int whence);

参数

stream:需要设置位置偏移量的文件指针

offset:新位置偏移量相对基准点的偏移

whence:基准点

SEEK_SET:文件开头处

SEEK_CUR:当前位置

SEEK_END:文件末尾处

返回值

成功

0

失败

-1

备注

 3.6 ftell()函数

功能

获取指定文件的当前位置偏移量

头文件

#include <sys/ioctl.h>

原型

long ftell(FILE *stream);

参数

stream:需要返回当前文件位置偏移量的文件指针

返回值

成功

当前文件位置偏移量

失败

-1

备注

 3.7rewind()函数

功能

将指定文件的当前位置偏移量设置到文件开头处

头文件

#include <sys/ioctl.h>

原型

void rewind(FILE *stream);

参数

stream:需要设置位置偏移量的文件指针

返回值

备注

该函数的功能是将文件 strean 的位置偏移量置位到文件开头处。

简单例子:

#include <stdio.h>

int main(int argc,char* argv[])
{
	int wr_ret;
	int rd_ret;
	FILE *fp;
	unsigned long file_size;
	char wr_buf[100] = "hello world";
	char rd_buf[100];

	fp = fopen( "a.txt", "a+" );//文件追加,可读可写,文件不存在则创建
	if(fp == NULL)
	{
		perror("open file error:");//只有上面的函数设置了error全局错误号,才可使用,会根据error输出对应的错误信息
		return -1;
	}

	wr_ret = fwrite( wr_buf, sizeof(wr_buf), 1, fp);
	printf("wr_ret = %d\n", wr_ret);

	rewind(fp);//上面的写操作,文件位置偏移量也会相应的移动,此处将文件偏移到文件开始位置,然后才能读取刚刚输入的内容
	rd_ret = fread(rd_buf, sizeof(rd_buf), 1, fp);
	printf("rd_ret = %d\n",rd_ret);
	printf("content=%s\n", rd_buf);

	fseek(fp, 0, SEEK_END);
	file_size = ftell(fp);
	printf("file_size = %lu\n", file_size);

	fclose(fp);//关闭文件

	return 0;
}

运行结果

      

猜你喜欢

转载自blog.csdn.net/nanfeibuyi/article/details/81456273