文件IO之对普通文件的操作

在 Linux 中,文件总共被分成了 7 种,他们分别是:

1,普通文件 (regular)  '- ':存在于外部存储器中,用于存储普通数据。

2,目录文件 (directory)  'd':用于存放目录项,是文件系统管理的重要文件类型。

3,管道文件 (pipe)  'p':一种用于进程间通信的特殊文件,也称为命名管道 FIFO。

4,套接字文件 (socket)  's':一种用于网络间通信的特殊文件。

5,链接文件 (link)  'l':用于间接访问另外一个目标文件,相当于 Windows 快捷方式。

6,字符设备文件 (character)  'c':字符设备在应用层的访问接口。

7,块设备文件 (block)  'b':块设备在应用层的访问接口。

一.系统IO对文件的操作

1.打开文件open()

 1.1 需要的头文件

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

 1.2 函数的原

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_EXCL:如果使用 O_CREAT 选项且文件存在,则返回错误消息。

O_NOCTTY:如果文件为终端,那么终端不可以作为调用 open()系统调 用的那个进程的控制终端。

O_TRUNC:如文件已经存在,则删除文件中原有数据。

O_APPEND:以追加方式打开文件。

mode

如果文件被新建,指定其权限为 mode  (八进制表示法) 

如果使用了O_CREAT,open()函数就要加第三个参数,mode文件权限(八进制数表示)

 1.3 返回值

成功:大于0 的整数 (即文件描述符)          失败:-1

 1.4 代码演示

	int a = open("./1.txt", O_RDONLY);
	int b = open("./2.txt", O_RDONLY);
	int c = open("./3.txt", O_RDONLY);
	printf("%d %d %d\n", a,b,c);

 运行结果:

 至于从3开始的原因是:0为键盘的标准输入,1是屏幕的标准输出,2是屏幕的标准输入

2.关闭文件close()

 2.1 需要的头文件

#include <unistd.h>

 2.2 函数的原型

int close(int fd);

函数参数:

fd:即将要关闭的文件的描述符

 2.3 返回值

成功:0                失败:-1

 2.4 代码演示

	close(a);
    close(b);
	close(c);

3. 文件光标的偏移lseek()

       在读写文件的时候有个偏移量的概念,即当前读写的位置,简单来说,就是在记事本中那个闪烁的竖线。这个位置可以获取,也可以人为调整。

 3.1 需要的头文件

#include <sys/types.h>

#include <unistd.h>

 3.2 函数的原型

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

函数参数:

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

offset:新位置偏移量相对基准点的偏移,输入多少就在基准点的位置向右偏移多少

whence:基准点

SEEK_SET:文件开头处

SEEK_CUR:当前位置

SEEK_END:文件末尾处

 3.3 返回值

成功:新文件位置偏移量              失败:-1

 3.4 代码演示

	int fd = open("./3.txt", O_RDWR);
	char ch;
	//将文件光标偏移到文件结尾
	int ls1 = lseek(fd, 0, SEEK_END);
	//将文件光标偏移到文件开头
	int ls2 = lseek(fd, 0, SEEK_SET);
	//将文件光标在当前位置向右偏移6个字节
	int ls3 = lseek(fd, 6, SEEK_CUR);
	printf("ls1 = %d\nls2 = %d\nls3 = %d\n", ls1, ls2, ls3);

 运行结果:

ls2为0是因为光标往前偏移 。

4.文件的读取read()

 4.1 需要的头文件

#include <unistd.h>

 4.2 函数的原型

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

函数参数:

fd:从文件fd 中读数

buf:指向存放读到的数据的缓冲区

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

 4.3 返回值

成功:实际读到的字节数                      失败:-1

 4.4 代码演示 perror的使用

  4.4.1 读取一个字符
	char ch1 = 0;
	int fd = open("./1.txt", O_RDONLY);
	if (fd == -1)
	{
		perror("文件打开失败!");
		return -1;
	}
	int n = read(fd, &ch1, sizeof(ch1));
	if (n == -1)
	{
		perror("写入失败!");
        return -1;
	}

 注:perror:是使用strerror(errno)打印出错误信息。使用errno需要头文件#include<errno.h>

  4.4.2 读取一行字符
char ch2 = 0;
int n, fd = open("./1.txt", O_RDONLY);
if (fd == -1)
{
	perror("文件打开失败!");
	return -1;
}
while (ch2 != '\n')
{
	n = read(fd, &ch2, sizeof(ch2));
	if (n == 0) break;
	printf("%c", ch2);
}
  4.4.3 读取所有内容
	char ch2[100] = { 0 };
	int n, fd = open("./1.txt", O_RDONLY);
	if (fd == -1)
	{
		perror("文件打开失败!");
		return -1;
	}
	while (n = read(fd, ch2, sizeof(ch2) - 1))
	{
		if (n == -1)
		{
			perror("文件读取失败!");
			return -1;
		}
		printf("%s", ch2);
		memset(ch2, 0, sizeof(ch2));
	}

 5.文件的写入write()

 5.1 需要的头文件

#include <unistd.h>

 5.2 函数的原型

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

函数参数:

fd:将数据写入文件 fd

buf指向即将要写入的数据

count:要写入的字节数

 5.3 返回值

成功:实际写入的字节数                      失败:-1

 5.4 代码演示

  5.4.1 写入一个字符
	char ch1 = 'a';
	int fd = open("./1.txt", O_WRONLY);
	if (fd == -1)
	{
		perror("文件打开失败!");
		return -1;
	}
	int n = write(fd, &ch1, 1);
	if (n == -1)
	{
		perror("写入失败!");
	    return -1;
	}
   5.4.2 写入多个字符
	char str[100] = "文件IO.exe(Win32):已加载:System32\msvcrt.dll。";
	int fd = open("./1.txt", O_WRONLY);
	if (fd == -1)
	{
		perror("文件打开失败!");
		return -1;
	}
	int n = write(fd, str, strlen(str));
	if (n == -1)
	{
		perror("写入失败!");
		return -1;
	}

注: 写入的字节数count要使用strlen(str),不要使用sizeof(str)。因为你写入内容时使用sizeof(str)会将str中所有内容写入到文件中。例如你str的大小100,但写入str里面的内容只有"hello world",但是你使用的是sizeof(str),那就会写入"hello world"之后再写入很多空格,直到写到100,所有写入的时候要使用strlen(str)写入str的有效长度的大小。

6.其他函数 

6.1 复制文件描述符dup( )/dup2( )

头文件

#include <unistd.h>

原型

int dup(int oldfd);

int dup2(int oldfd, int newfd);

参数

oldfd:要复制的文件描述符

newfd:指定的新文件描述符

返回值

成功

新的文件描述符

失败

- 1

6.2 控制 

6.2.1 ioctl()

头文件

#include <sys/ioctl.h>

原型

int ioctl(int d, int request, ...);

参数

d:要控制的文件描述符

request:针对不同文件的各种控制命令字

变参:根据不同的命令字而不同

返回值

成功

一般情况下是 0 ,但有些特定的请求将返回非负整数。

失败

- 1

 6.2.2 fcntl()

头文件

#include <unistd.h>

#include <fcntl.h>

原型

int fcntl(int fd, int cmd, .../* arg */ );

参数

fd:要控制的文件描述符

cmd:控制命令字

变参:根据不同的命令字而不同

返回值

成功

根据不同的 cmd ,返回值不同

失败

- 1

对于 fcntl( )而言,其第二个参数命令字 cmd 有很多,下面的网址有一个汇总: 

文件控制 fcntl()中的参数cmd汇总和内存映射mmap函数中参数flags汇总-CSDN博客

6.3 内存映射mmap()

功能

内存映射

头文件

#include <sys/mman.h>

原型

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

参数:

addr:

映射内存的起始地址。

如果该参数为 NULL,  则系统将会自动寻找一个合适的起始地址,一 般都使用这个值。

如果该参数不为 NULL,则系统会以此为依据来找到一个合适的起始地 址。在 Linux 中,映射后的内存起始地址必须是页地址的整数倍。

length:

映射内存大小。

prot:

映射内存的保护权限。

PROT_EXEC : 可执行。

PROT_READ : 可读。

PROT_WRITE : 可写。

PROT_NONE: 不可访问。

flags文件控制 fcntl()中的参数cmd汇总和内存映射mmap函数中参数flags汇总-CSDN博客

fd:

要映射的文件的描述符

offset:

文件映射的开始区域偏移量,该值必须是页内存大小的整数倍,即必 须是函数 sysconf(_SC_PAGE_SIZE)返回值的整数倍。

二.标准IO对文件的操作

1.打开文件fopen()

 1.1 需要的头文件

#include <stdio.h>

 1.2 函数的原

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

函数参数:

path即将要打开的文件

mode

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

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

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

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

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

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

 1.3 返回值

成功:指针                    失败:NULL

 1.4 代码演示

	FILE* fp = fopen("1.txt", "r+");
	//如果值为NULL,则文件打开失败
	if (fp == NULL)
	{
		printf("文件打开失败");
        return -1;
	}

2.关闭文件fclose()

 2.1 需要的头文件

#include <stdio.h>

 2.2 函数的原型

int fclose(FILE *fp);

函数参数:

fp:即将要关闭的文件

 2.3 返回值

成功:0                失败:EOF(-1)

 2.4 代码演示

    fclose(fp);

3.文件指针的偏移 fseek()函数

头文件:#include <stdio.h>

函数原型:int fseek(FILE *stream, long offset, int whence);

参数:

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

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

whence:基准点

SEEK_SET:文件开头处

SEEK_CUR:当前位置

SEEK_END:文件末尾处

返回值: 成功:0            失败:-1

代码演示:

	//将文件光标偏移到文件结尾
	fseek(fp, 0, SEEK_END);
	//将文件光标偏移到文件开头
	fseek(fp, 0, SEEK_SET);
	//将文件光标在当前位置向右偏移6个字节
	Fseek(fp, 6, SEEK_CUR);

4.读取文件

 4.1 读取一个字符fgetc()函数

fgetc()函数:读一个,读取完会将文件指针移动到下一个字符

头文件:#include <stdio.h>

函数原型:int fgetc(FILE *stream);

参数:stream:文件指针

返回值: 成功:读取到的字符            失败:EOF( -1 )

备注:当返回 EOF 时,文件 stream 可能已达末尾,或者遇到错误

代码演示:fp为文件指针

	char ch = fgetc(fp);
	printf("%c\n", ch);

使用 fgetc()函数读取文件的所有内容

	char ch;
    while (EOF != (ch = fgetc(fp)))
	{
		printf("%c", ch);
	}

 4.2 读取一行字符fgets()函数

fgets()函数:读一行,文件指针自动遇到下一行

头文件:#include <stdio.h>

函数原型:char *fgets(char *s, int size, FILE *stream);

参数:

s: 自定义缓冲区指针

size: 自定义缓冲区大小

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

返回值: 成功:自定义缓冲区指针 s            失败:NULL

备注:

①gets( )缺省从文件 stdin 读入数据

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

 代码演示:fp为文件指针

	//读到结尾返回NULL
	char str[100] = {0};
	fgets(str, 100, fp);
	printf("%s\n", str);

 使用 fgets()函数读取文件的所有内容

	char str[100] = {0};
    while (fgets(str, 100, fp))
	{
		printf("%s", str);
        memset(str,0,100);//清空str
	}
	printf("\n");

 4.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 可能已达末尾,或者遇到错误

代码演示:fp为文件指针

4.3.1 读取文件的前20个字节:
    char str[100] = {0};
    int n = fread(str,1,20, fp);
	str[n] = "\0";//n<100,不然会发生数组越界
	printf("%s\n", str)
4.3.2 读取文件的使用内容:
	char str[100] = {0};
	while (fread(str, 1, 20, fp))
	{
		printf("%s", str);
        memset(str,0,100);//清空str
	}

注:fread函数的返回值是读取的块数,写满一块才返回1

 4.3.3 使用fread()函数实现fgetc()函数的功能
int myFgetc(FILE* fileP)
{
	char ch; int n;
	n = fread(&ch, 1, 1, fileP);
	return n == 1 ? ch : EOF;
}
 4.3.4使用fread()函数实现fgets()函数的功能
char* myFgets(char* str, int size, FILE* fileP)
{
	int i = 0;
	while ((str[i] = myFgetc(fileP)) != EOF) 
	{
		if (fseek(fileP, 1, SEEK_CUR) == -1)
			return NULL;
		fseek(fileP, -1, SEEK_CUR);
		if ((str[i] = myFgetc(fileP)) == '\n')
			break;
		i++;
	}
	str[i] = '\0';
	return i > 0 ? str : NULL;
}

 5.写入文件

  5.1 写入一个字符到指定文件中 fputc()函数

头文件:#include <stdio.h>

函数原型:int fputc(int c, FILE *stream);

参数:

c:要写入的字符

stream:文件指针

返回值: 成功:写入到的字符            失败:EOF( -1 )

代码演示:fp为文件指针

	fputc('A', fp);
	fputc('B', fp);
	fputc('C', fp);

 5.2 写入一个字符串到指定文件中 fputs()函数

头文件:#include <stdio.h>

函数原型:int fputs(const char *s, FILE *stream);

参数:

s: 自定义缓冲区指针

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

返回值: 成功:非负整数            失败:NULL

 代码演示:fp为文件指针

	char* str = "hello world\n";
	fputs(str, fp);

  5.3 想写多少读多少 fwrite()函数

头文件:#include <stdio.h>

函数原型:size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

参数:

ptr: 自定义缓冲区指针

size:数据块大小

nmemb:数据块个数

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

返回值:

成功:写入的数据块个数,等于 sinmembze 

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

代码演示:fp为文件指针

5.3.1 :演示
    char* str = "123456789abcdefg123456789abcdefg123456789abcdefg\n";
	fwrite(str,1,strlen(str3), fp);
注:fread函数的返回值是写入的块数,写满一块才返回1
 5.3.2 使用fread()函数实现fgetc()函数的功能
int myFputc(int c, FILE* fileP)
{
	int n;
	n = fwrite(&c, 1, 1, fileP);
	return n == 1 ? c : EOF;
}
 5.3.3 使用fread()函数实现fgets()函数的功能
int myFputs(const char* str, FILE* fileP)
{
	int i = 0;
	if (fseek(fileP, -1, SEEK_CUR) != -1)
	{
		fwrite("\n", 1, 1, fileP);
		fseek(fileP, 1, SEEK_CUR);
	}
	while (str[i] != '\0')
	{
		fwrite(&str[i], 1, 1, fileP);
		i++;
	}
	return i > 0 ? i : EOF;
}

6.其他函数

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

头文件

#include <stdio.h>

原型

long ftell(FILE *stream);

参数

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

返回值

成功

当前文件位置偏移量

失败

- 1

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

头文件

#include <stdio.h>

原型

void rewind(FILE *stream);

参数

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

返回值

备注

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

6.3 判断文件指针

功能

feof():判断一个文件是否到达文件末尾

ferror():判断一个文件是否遇到了某种错误

头文件

#include <sys/ioctl.h>

原型

int feof(FILE *stream);

int ferror(FILE *stream);

参数

stream:进行判断的文件指针

返回值

feof

如果文件已达末尾则返回真,否则返回假

ferror

如果文件遇到错误则返回真,否则返回假

三.系统IO和标准IO的区别

系统IO:

       具有通用性,简约性,没有缓冲区,直接操作内核,open的返回值是一个整型(int)的文件描述符。

标准IO:

       只能在有标准C库的情况下使用,有丰富的读写操作,有标准IO的缓冲区,要处理的数据会先存到标准IO缓冲区,等缓冲区满了之后,才会送到内核执行,fopen的返回值是一个指向文件结构体的指针,简称文件指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值