Linux文件编程(一)
1.什么是文件IO
IO就是input/output,输入/输出。文件IO的意思就是读写文件。
2.什么是操作系统API
(1)API是一些函数,这些函数是由linux系统提供支持的,由应用层程序来使用。
(2)应用层程序通过调用API来调用操作系统中的各种功能,来干活。
(3)学习一个操作系统,其实就是学习使用这个操作系统的API。
3.linux常用文件IO接口
open、close、write、read、lseek
4.文件操作的一般步骤
(1)在linux系统中要操作一个文件,一般是先open打开一个文件,得到一个文件描述符,然后对文件进行读写操作(或其他操作),最后close关闭文件即可。
(2)注意一点:我们对文件进行操作时,一定要先打开文件,打开成功后才能去操作(如果打开本身失败,后面就不用操作了);最后读写完成之后一定要close关闭文件,否则可能会造成文件损坏。
(3)文件平时是存在块设备中的文件系统中的,我们把这种文件叫静态文件。当我们去open打开一个文件时,linux内核做的操作包括:内核在进程中建立了一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内存中特定地址管理存放(叫动态文件)。
(4)打开文件后,以后对这个文件的读写操作,都是针对内存中这一份动态文件的,而并不是针对静态文件的。当我们对动态文件进行读写后,此时内存中的动态文件和块设备中的静态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件。
5.文件描述符
(1)文件描述符其实实质是一个数字,这个数字在一个进程中表示一个特定的含义,当我们open打开一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护这个动态文件的这些数据结构挂钩绑定上了,以后我们应用程序如果要操作这一个动态文件,只需要用这个文件描述符进行区分。
(2)一句话讲清楚文件描述符:文件描述符就是用来区分一个程序打开的多个文件的。
(3)文件描述符的作用域就是当前进程,出了当前进程这个文件描述符就没有意义了
实时查man手册
( 1)当我们写应用程序时,很多API原型都不可能记得,所以要实时查询,用man手册
(2)man 1 xx查linux shell命令,man 2 xxx查API, man 3 xxx查库函数
6.读取文件内容
(1)ssize_t read(int fd, void *buf, size_t count);
fd表示要读取哪个文件,fd一般由前面的open返回得到
buf是应用程序自己提供的一段内存缓冲区,用来存储读出的内容
count是我们要读取的字节数
返回值ssize_t类型是linux内核用typedef重定义的一个类型(其实就是int),返回值表示成功读取的字节数。
7.向文件中写入
写入用write系统调用,write的原型和理解方法和read相似
ssize_t write(int fd, const void *buf, size_t count);
int fd 文件描述符
const void *buf 是一个文件缓冲区,把这个文件写入到fd中
size_t count 要写入文件的大小
可以简单理解为:将缓冲区中的数据,写count个字节,写到fd中
写入成功的话,则返回写入字节大小,没有内容写入则返回0,错误写入则返回-1
8.open函数的flag详解1
读写权限:O_RDONLY 、 O_WRONLY、 O_RDWR
(1)linux中文件有读写权限,我们在open打开文件时也可以附带一定的权限说明(譬如O_RDONLY就表示以只读方式打开,O_WRONLY表示以只写方式打开,O_RDWR表示以可读可写方式打开)
(2)当我们附带了权限后,打开的文件就只能按照这种权限来操作。
9.open函数的flag详解2
打开不存在的文件时:O_CREAT、O_EXCL
(1)当我们去打开一个并不存在的文件时会怎样?当我们open打开一个文件时如果这个文件名不存在则会打开文件错误。
(2)open中加入O_CREAT后,不管原来这个文件存在与否都能打开成功,如果原来这个文件不存在则创建一个空的新文件,如果原来这个文件存在则会重新创建这个文件,原来的内容会被消除掉。
(3)O_EXCL标志和O_CREAT标志来结合使用。当这两个标志一起的时候,则没有文件时创建文件,有这个文件时会报错提醒我们。
10.打开存在并有内容的文件时:O_APPEND、O_TRUNC
(2)O_TRUNC属性去打开文件时,如果这个文件中本来是有内容的,则原来的内容会被丢弃。
(3)O_APPEND属性去打开文件时,如果这个文件中本来是有内容的,则新写入的内容会接续到原来内容的后面。
11.exit、_exit、_Exit退出进程
(1)当我们程序在前面步骤操作失败导致后面的操作都没有可能进行下去时,应该在前面的错误监测中结束整个程序,不应该继续让程序运行下去了。
(2)我们如何退出程序?
第一种;在main用return,一般原则是程序正常终止return 0,如果程序异常终止则return -1。
第一种:正式终止进程(程序)应该使用exit或者_exit或者_Exit之一。
一个简单的文件读写实例
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = -1; // fd 就是file descriptor,文件描述符
char buf[100] = {0};
char writebuf[20] = "l love linux";
int ret = -1;
// 第一步:打开文件
fd = open("a.txt", O_RDWR);
if (-1 == fd) // 有时候也写成: (fd < 0)
{
printf("文件打开错误\n");
}
else
{
printf("文件打开成功,fd = %d.\n", fd);
}
// 第二步:读写文件
// 写文件
ret = write(fd, writebuf, strlen(writebuf));
if (ret < 0)
{
printf("write失败.\n");
}
else
{
printf("write成功,写入了%d个字符\n", ret);
}
/*
// 读文件
ret = read(fd, buf, 5);
if (ret < 0)
{
printf("read失败\n");
}
else
{
printf("实际读取了%d字节.\n", ret);
printf("文件内容是:[%s].\n", buf);
}
*/
// 第三步:关闭文件
close(fd);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = -1; // fd 就是file descriptor,文件描述符
char buf[100] = {0};
char writebuf[20] = "l love linux";
int ret = -1;
// 第一步:打开文件
fd = open("a.txt", O_RDWR | O_APPEND | O_TRUNC);
if (-1 == fd) // 有时候也写成: (fd < 0)
{
printf("文件打开错误\n");
// return -1;
_exit(-1);
}
else
{
printf("文件打开成功,fd = %d.\n", fd);
}
#if 1
// 第二步:读写文件
// 写文件
ret = write(fd, writebuf, strlen(writebuf));
if (ret < 0)
{
printf("write失败.\n");
_exit(-1);
}
else
{
printf("write成功,写入了%d个字符\n", ret);
}
#endif
#if 0
// 读文件
ret = read(fd, buf, 5);
if (ret < 0)
{
printf("read失败\n");
_exit(-1);
}
else
{
printf("实际读取了%d字节.\n", ret);
printf("文件内容是:[%s].\n", buf);
}
#endif
// 第三步:关闭文件
close(fd);
_exit(0);
}