Linux学习记录--文件IO操作相关系统编程
文件IO操作相关系统编程
这里主要说两套IO操作接口,各自是:
POSIX标准
read|write接口。函数定义在#include<unistd.h>
ISO C标准
fread|fwrite接口。函数定义在#include<stdio.h>
有书上说POSIX标准与ISO C标准的差别在于文件读写是否带缓冲区,我则不是非常认同,因此POSIX标准下的IO操作也是带缓冲区的,至于这两个标准下的IO性能谁更加好则不一定。由于这和缓冲区的大小,以及用户逻辑有非常大关系。
POSIX标准
ssize_t read (int __fd, void *__buf, size_t __nbytes)
ssize_t write (int __fd, constvoid *__buf, size_t __n)
读规则:
如预读字节数>文件总字节数,则所有读入文件字节数。返回值为文件字节数
如预读字节数<文件总字节数,则读满__buf(以__nbytes为准)后返回。下回读取会将继续读
如读到文件末尾,则返回值为0
比方:文件长度是100。buf长度是70,那么第一个读取70,读2此会读取剩下的30 ,第三次因为文件游标已经处于文件末尾,则返回0
写操作
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include#include#include<stdio.h>#defineint main() int fd if (access("/tmp/iofile", fd"/tmp/iofile", } else { fd"/tmp/iofile", } if (fd perror("文件打开错误!"); return -1; } char buf[BUFFER_SIZE]; int val do { val if (val write(fd, } else { break; } sum } while (1); printf("写入数据总长度是:%d\n", return 1;} |
读操作
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include#include#include<stdio.h>#defineint main() int fd"/tmp/iofile", if (fd perror("文件打开错误!
); return -1; } char buf[BUFFER_SIZE]; int val do { val printf("读入数据长度是:%d\n", if (val write(1, printf("\n"); } else { sleep(1); } sum } while (1); return 1;} |
运行顺序
1.运行写操作:
tkf@tkf:~/workspace/FileIOWrite/Debug$./FileIOWrite </etc/mtab
写入数据总长度是:990
2.在另外命令行(进程)运行读操作
tkf@tkf:~/workspace/FiloIORead/Debug$./FiloIORead
读入数据长度是:400
读入数据长度是:400
读入数据长度是:200
读入数据长度是:0
……..
è因为此时文件游标已经处于文件末端因此,长度是0
读入数据长度是:0
3.再次运行写操作
tkf@tkf:~/workspace/FileIOWrite/Debug$./FileIOWrite </etc/mtab
写入数据总长度是:990
此时读端进程输出
读入数据长度是:400
读入数据长度是:400
读入数据长度是:200
读入数据长度是:0
è由于再次有数据写入,所以能够读到数据,当数据再次读取完成,则返回0
当然对于第三步骤,我们也能够通过更改读进程游标的位置(lseek)使其能读到数据
IO效率
依据书上效率对照试验,当缓冲区大小(buf)等于文件系统块大小时。性能是最佳的。
文件系统块大小struct stat –>st_blksize 查看
对于IO操作主要步骤能够理解为:
1.内核与系统缓冲区的数据拷贝
2.系统缓冲区与用户缓冲区的拷贝
举例,用户BUF是10字节,系统缓冲区时4096字节,那么到我们写端将用户BUF数据拷贝被系统缓冲区中。因为系统缓冲区没有填满,因此不会运行IO操作,直到写满或者运行同步操作。对于读来说,文件系统会将数据先都预读到系统缓冲区,每次我们请求读都是从系统缓冲区复制到用户缓冲器。
因此在数据存在缓冲区并没有写到磁盘时假设系统出现问题可能数据会丢失。
ISO C标准(标准IO)
标准IO是环绕流的,他与POSIX标准相比能够使用户不用关注分配缓冲区的大小。他会选择适当缓冲区以优化运行IO
冲洗(fflush)
对于标准IO来说,冲洗就是讲缓冲区的数据写入磁盘
缓冲
对于标准IO库提供了三种类型的缓冲
全缓冲:在填满标准IO缓冲区后才进行实际的IO操作
行缓冲:当输入和输出遇到换行符时才运行实际的IO操作
不带缓冲:每次一个都进行实际的IO操作
void setbuf(FILE *__restrict __stream, char *__restrict __buf) ;
int setvbuf (FILE *__restrict __stream, char *__restrict __buf,
int __modes, size_t __n) ;
參数:
__n:缓冲区长度
__buf:缓冲区指针
__stream文件流
__modes:缓冲模式
_IOFBF0:全缓冲
_IOLBF 1:行缓冲
_IONBF 2:无缓冲
|
函数 |
mode |
buf |
缓冲区长度 |
缓冲类型 |
|
setbuf |
非空 |
长度为BUFSIZ的BUF |
全缓冲,行缓冲 |
|
|
NULL |
无缓冲区 |
不带缓冲 |
||
|
setvbuf |
IOFBF |
非空 |
长度为size的buf |
全缓冲 |
|
NULL |
合适长度的系统缓冲区 |
|||
|
IOLBF |
非空 |
长度为size的buf |
行缓冲 |
|
|
NULL |
合适长度的系统缓冲区 |
|||
|
IONBF |
无缓冲区 |
不带缓冲 |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include#include#includeint main() FILE *fopen("fopenfile", "w+"); if (iostream perror("流打開錯誤"); return -1; } setvbuf(iostream,//1 char *buf"abcde"; //2 int sizefwrite(buf, sizeof(char), strlen(buf)+1 printf("寫入的數據是:%s", fflush(iostream); //3 sleep(-1); return 1;} |
针对上述代码做例如以下分析:
将3处进行凝视。并运行
fopenfile文件无不论什么内容,因此如今数据都在缓冲区。因为进程SLEEP流未关闭。而且缓冲区也没有写满,因此不会运行IO操作
不凝视不论什么内容,并运行
fopenfile文件内容为abcde,因为fflush冲洗将缓冲区数据写入文件
将1处缓冲模式改为_IOLBF,凝视3处。并运行
fopenfile文件无不论什么内容,尽管指定了行缓冲可是没有行结束符,因此数据在缓冲区内,没有进行IO操作
将1处缓冲模式改为_IOLBF,凝视3处,并将2处数据改为buf=”abcde\n” ,运行
fopenfile文件内容为abcde,因为设置行行缓冲,而且存在结束符。因此进行了IO操作
将1处缓冲模式改为_IONBF,凝视3处,并运行
fopenfile文件内容为abcde,因为设置无缓冲,因此每次写入都会进行IO操作
主要函数
打开关闭流
打开一个指定的文件
FILE *fopen (constchar *__restrict __filename,
constchar *__restrict __modes)
通过文件描写叙述符打开一个指定的文件
FILE *fdopen (int __fd, constchar *__modes)
modes:打开模式
|
R或rb |
为读而打开 |
|
W或wb |
把文件截断为0长,或为写而创建 |
|
A或ab |
加入;在文件尾为写而打开,或为写而创建 |
|
R+ |
为读和写而打开 |
|
W+ |
把文件截断为0长,或为为读和写而打开 |
|
A+ |
为在文件尾为写而打开或创建 |
关闭文件流
intfclose (FILE *__stream);
单字符读写
读函数
int fgetc (FILE *__stream);
int getc (FILE *__stream);
int getchar (void);
fgetc是一个函数,getc可实现为宏,getchar为从标准输出流中获取一个字符,相当于getc(stdin)
返回值:若成功则返回读取到的字符,若失败或读到文件尾则返回-1
因为不管失败或者读到文件尾都返回-1,为了区分哪种原因返回的-1。提供以下2个函数
以读到文件结尾返回
int feof (FILE *__stream)
以产生错误返回返回
int ferror (FILE *__stream)
返回值:条件为真返回非0.条件为假返回0
写函数
int fputc(int __c, FILE *__stream);
int putc (int __c, FILE *__stream);
int putchar (int __c);
返回值:成功返回c,失败返回EOF
举例:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include#include#includeint main() FILE *fopen("fopenfile", "r"); if (iostream perror("流打開錯誤"); return -1; } char c; while ((cgetc(iostream)) printf("读取的字符是:"); putchar(c); printf("\n"); } if (feof(iostream)) printf("读取到文件末尾结束\n"); } if (ferror(iostream)) printf("读取出现异常结束\n"); } return 1;} |
读取的字符是:a
读取的字符是:b
读取的字符是:c
读取的字符是:d
读取的字符是:e
读取的字符是:
读取到文件末尾结束
整行读写
写函数
int fputs (constchar *__restrict __s, FILE *__restrict __stream);
int puts (constchar *__s);
返回值:成功返回非负值。错误返回EOF
读函数
char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
char *gets (char *__s)
返回值:成功返回buf, 失败或达到文件结尾返回NULL
举例:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include#includeint main() FILE *iostreamfopen("fopenfile", "r+"); if (iostream perror("文件打开错误!
); return -1; } int revalfputs("hello, if (reval perror("文件写入失败。"); return -1; } fflush(iostream); fclose(iostream); iostreamfopen("fopenfile", "r+"); if (iostream perror("文件打开错误!
); return -1; } char buf[1000]; memset(buf, '\0', char *getvalfgets(buf, printf("读入一行数据是:%s",} |
二进制IO
前面说到的单字节以及整行读写。假设要写一个结构则须要每个结构项的读写非常麻烦。这就须要用到2进制IO
读操作
size_t read (void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __stream)
__pt:结构体(数据)指针
__size:单个结构体大小
__n:结构体数量
__stream:文件流
返回值:读或写的对象数
写操作
size_t fwrite (constvoid *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __s);
举例:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#include#includetypedef struct { int no; char name[100]; long tel;}int main(int argc, char *argv[]) if (0strcmp(argv[1], "read")) FILE *iosfopen("binaryfile", "r"); Info fread(&info, sizeof(Info), printf("no=%d\n", printf("name=%s\n", printf("tel=%ld\n", if (getc(ios) if (feof(ios)) printf("读取到文件末尾结束\n"); } if (ferror(ios)) printf("读取出现异常结束\n"); } } } else if (0strcmp(argv[1], "write")) FILE *iosfopen("binaryfile", "w"); Info info.no info.tel char *name"hello"; memcpy(info.name,strlen(name) fwrite(&info, sizeof(Info), } return 1;} |
运行结果:
no=1
name=hello
tel=1234567
读取到文件末尾结束
说明:
1.生成的文件为2进制文件,如打开看到的会是乱码
2.最后须要在此尝试读入一个字符,那么流才会结束,才会使用feof等推断
文件流定位
能够设置文件位置指示器来影响一个文件读取,使用方法和sleek一致
获取当前文件位置指示器
long int ftell (FILE *__stream)
返回值:当前文件位置指示器
int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos);
返回值:成功返回0,失败返回非0值
当前文件位置指示器
int fseek (FILE *__stream, longint __off, int __whence);
返回值:成功返回0,失败返回非0值
int fsetpos (FILE *__stream, constfpos_t *__pos);
返回值:成功返回0。失败返回非0值
重定位文件位置指示器
void rewind (FILE *__stream);
相当于(void)fseek(stream, 0L,SEEK_SET)
返回值:成功返回0,失败返回非0值
暂时文件
char *tmpnam (char *__s)
char *tempnam (constchar *__dir, constchar *__pfx)
FILE *tmpfile (void) __wur;
int mkstemp (char *__template)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#includeint main() char name[1000]; char *revaltmpnam(name); printf("同意最大随机文件名称个数:%d\n", printf("文件名称:%s\n", char *newname"/home/tkf/","SDF"); printf("扩展文件名称:%s\n", FILE *ios=tmpfile(); sleep(10); fclose(ios); printf("暂时文件删除成功!\n"); return 1;} |
Linux学习记录--文件IO操作相关系统编程的更多相关文章
- Linux文件IO操作
来源:微信公众号「编程学习基地」 目录 文件操作 Linux文件类型 Linux文件权限 修改文件权限 Linux error 获取系统调用时的错误描述 打印错误信息 系统IO函数 open/clos ...
- 树莓派学习笔记——使用文件IO操作GPIO SysFs方式
0 前言 本文描写叙述假设通过文件IO sysfs方式控制树莓派 GPIO端口.通过sysfs方式控制GPIO,先訪问/sys/class/gpio文件夹,向export文件写入GPIO编号, ...
- linux文件IO操作篇 (一) 非缓冲文件
文件IO操作分为 2 种 非缓冲文件IO 和 缓冲文件IO 它们的接口区别是 非缓冲 open() close() read() write() 缓冲 fopen() fclose() fread() ...
- Linux 学习笔记 1 使用最小的系统,从分区安装系统开始
我们常用的linux系统在安装过程中大多都省略了对系统进行分区的操作,以至于后期,不了解什么是分区以及分区当中最基本的一些概念, 我们不说最细的知识,只求了解这个过程,那直接步入正题,开始第一节的学习 ...
- 9.2 Go 文件IO操作
9.2 Go 文件IO操作 1.1.1. bufio包 带有缓冲区的IO读写操作,用于读写文件,以及读取键盘输入 func main() { //NewReader返回一个结构体对象指针 reader ...
- Delphi关于记录文件的操作
http://www.cnblogs.com/railgunman/archive/2010/08/16/1801004.html Delphi关于记录文件的操作 本例子几个变量的说明TFileR ...
- imx6用文件io操作gpio
具体请参考: http://blog.csdn.net/u014213012/article/details/53140781 这里要注意的是: 要让linux支持文件io方式操作gpio,首先驱动必 ...
- 文件IO操作
前言 本文介绍使用java进行简单的文件IO操作. 操作步骤 - 读文件 1. 定义一个Scanner对象 2. 调用该对象的input函数族进行文件读取 (参见下面代码) 3. 关闭输入流 说明:其 ...
- Linux学习之文件特殊权限详解(SetUID、SetGID、Sticky BIT)(十一)
Linux学习之文件特殊权限详解(SetUID.SetGID.Sticky BIT) 目录 SetUID SetGID Sticky BIT SetUID SetUID简介 只有可以执行的二进制程序和 ...
随机推荐
- Python爬虫入门:Urllib库的高级使用
1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...
- w3wp.exe已附加有调试器,但没有该调试器配置为调试此未经处理的异常,若要调试此异常,必须分离当前的调试器。
之前通过使用VS2010附加进程调试项目后,今天开机发现调试本机的项目报错如下图: 到网上到处查看无果,经过反复实验找到解决方法,我的项目是发布到IIS的 1.首先删除IIS上面的项目 2.在VS右击 ...
- Oracle Database 12c Release 2安装详解
第1章 Oracle Database 12c Release 2安装详解 1.1 下载方法 oracle官网https://www.oracle.com 1)打开官方网站,找到下载连接 2)选择更多 ...
- NoSQL:linux操作memcached
缓存数据库 一 NoSQL简介 NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL",泛指非关系型的数据库,随着互联网web2.0网站的兴起,传统的关系 ...
- Linux系列教程(十九)——Linux文件系统管理之手工分区
上篇博客我们首先介绍了硬盘为什么要分区,以及Linux系统的几种分区类型,然后介绍了Linux系统几个常用的文件系统命令,最后讲解了挂载命令,并通过实例演示了如何挂载光盘和U盘. 本篇博客我们将介绍l ...
- Python中的三种数据结构
Python中,有3种内建的数据结构:列表.元组和字典.1.列表 list是处理一组有序项目的数据结构,即你可以在一个列表中存储一个序列的项目.列表中的项目.列表中的项目应该包括在方括号中,这 ...
- 结合程序崩溃后的core文件分析bug
引言 在<I/O的效率比较>中,我们在修改图1程序的BUF_SIZE为8388608时,运行程序出现崩溃,如下图1: 图1. 段错误 一般而言,导致程序段 ...
- canvas图表(2) - 折线图
原文地址:canvas图表(2) - 折线图 话说这天气一冷啊, 就患懒癌, 就不想码代码, 就想着在床上舒舒服服看视频. 那顺便就看blender视频, 学习下3D建模, 如果学会了建3D模型, 那 ...
- robotframework自动化系列:删除操作流程以及总结
之前已经完成了登录.新增和修改的操作流程,这一节主要说明删除操作流程以及自动化的过程中出现的问题,算是对这个项目自动化的一个总结. 删除操作流程 对于系统账号管理中删除功能,删除的测试点主要如图所示 ...
- JavaScript学习笔记(八)——变量的作用域与解构赋值
在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...