linux c文件操作,Linux C 文件的输入/输出操作

10.1 文件I/O操作概述

在Linux系统中,文件I/O操作可以分为两类,一类是基于文件描述符的I/O操作,另一类是基于数据流的I/O操作。

10.1.1 文件描述符简介

在文件操作一章中,也经常提到文件描述符这个概念。所谓文件描述符,就是进程与打开的文件的一个桥梁,通过这个桥梁,才可以在进程中对这个文件进行读写等操作。

在Linux环境下,每打开一个磁盘文件,都会在内核中建立一个文件表项,文件表项中存储着文件的状态信息、存储文件内容的缓冲区和当前文件的读写位置。如果同一磁盘文件打开了3次,就会创建3个这样的文件表项(a,b和c),读写文件时,只会改变该文件表项中的文件读写位置。这3个文件表项存储在一个文件表数组table[3]中,在这里table[0]=a,table[1]=b,table[2]=c。这个文件表的下标就称之为文件描述符,将这个文件描述符存储在一个数组中des[3]={0,1,2},那么,在进程中就可以通过这个des数组下标引用文件表项。也就是说,通过文件描述符就可以访问到这个磁盘文件。

10.1.2 数据流概述

从数据操作方式这个角度来说,Linux系统中的文件(无论是普通文件还是设备文件)可以看做是数据流。对文件进行操作之前,必须先调用标准I/O库函数fopen()将数据流打开。打开数据流之后,就可以对数据流进行输入和输出的操作。

标准I/O库函数是C语言中所特有的用于高级接口的函数,这些库函数存放在C语言的stdio.h头文件中,因此这些用于数据流的I/O操作函数不仅适用于Linux系统,还适用于其他的操作系统。由此可见,此库函数的引用大大增加了程序的移植性。

要对数据流进行读写操作时,需要标准I/O库函数和FILE类型的文件指针一起来实现。这个文件指针石达开数据流时返回的指针,该指针用来表示要操作的数据流。

当执行程序时,有3个数据流不需要特定的函数进行打开的操作,他们会自动打开。这3个数据流是标准输入、标准输出和标准错误输出。他们是自动打开的,当不使用时,也会自动关闭。

然而,调用标准I/O库函数fopen()打开的数据流,在对数据流进行操作后,需要调用fclose()函数将其关闭。fclose()函数在关闭数据流之前,会清空在操作过程中分配的缓冲区并保存数据信息。

10.2 基于文件描述符的I/O操作

10.2.1 文件的打开与关闭

1)open()函数

#include

#include

#include

int open(const char *pathname, int flags)

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

int creat(const char *pathname, mode_t mode)

上述的两个open()函数和一个creat()函数在调用成功时,都会返回其新分配的文件描述符;否则返值为-1,并设置适当的error。

2)close()函数

#incldue

int close(int fd)

当一个进程终止时,内核对该进程的所有尚未关闭的文件描述符调用close()函数关闭,所以即使用户程序不调用close()函数,在终止时内核也会自动关闭它打开的所有文件。但是,对于网络服务器这种一直运行的程序,文件描述符一定要及时关闭,否则随着打开的文件越来越多,会占用大量文件描述符和系统资源。

有函数open()返回的文件描述符一定是该进程尚未使用的最小描述符。由于程序启动时自动打开标准输入、标准输出和标准错误输出,因此文件描述符0,1,2会存在,那么第一次调用open()函数打开文件时返回的文件描述符通常会是3,再调用open()函数就会返回4.可以利用这一点在标准输入、标准输出或标准错误输出上打开一个新文件,是想重定向的功能。例如,首先调用close()函数关闭文件描述符1,然后调用open()函数打开一个常规文件,则一定会返回文件描述符1,这是标准输出就不再是终端,而是一个常规文件了,再调用printf()函数就不打印到屏幕上,而是写到这个文件中了。在文件操作一章中讲到的dup2()函数就是另外一种在指定的文件描述符上打开文件的方法。

10.2.2 文件的读写操作

1)read()函数

#include

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

2)write()函数

#include

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

10.2.3 文件的定位

每个文件都记录着当前读写位置,打开文件时读写位置是0,表示文件开头,通常读写多少个自己就会将读写位置往后移多少个字节。

以O_APPEND方式打开文件,每次写操作都会在文件末尾追加数据,然后间读写位置移动到新的文件末尾。

1)lseek()函数

lseek()函数可以移动当前读写位置,通常称为偏移量,该函数的定义形式如下:

#include

#include

off_t lseek(int fildes, off_t offset, int whence)

10.3 基于数据流的I/O操作

10.3.1 文件的打开与关闭

在操作文件之前要用fopen()函数打开文件,操作结束后,要用fclose()函数关闭文件。

1)fopen()函数

#include

FILE *foepn(cosnt char *path, cosnt char *mode)

2)fclose()函数

#include

int fclose(FILE *fp)

10.3.2 字符输入/输出

1)fgetc()函数

fgetc()函数从指定的文件中读一个字节,该函数的定义形式如下:

#include

int fgetc(FILE *stream)

在程序中,偶尔会遇到getchar()函数,也是用于读取一个字节,但它是从标准输入读一个字节。在程序中调用getchar()函数相当于调动fgetc(stdin)

在使用fgetc()函数时需要注意一下几点:

①调用fgetc()函数时,指定的文件的打开方式必须是可读的。

②函数fgetc()调用成功时,返回的是读到的字节,应该为unsigned char,但fgetc()函数在原型中返回值类型时int,原因在于函数调用出错或读到文件末尾时fgetc()会返回EOF,即-1,保存在int型的返回值是0xffffffff,如果读到字节0xff,由unsigned char型转换int 型时0x000000ff,只有规定返回值是int型才能把这种情况区分开,如果规定返回值是unsigned char型,那么当返回值是0xff时则无法区分到底是EOF还是字节0xff。

2)fputc()函数

#include

int fputc(int c, FILE *stream)

10.3.3 字符串输入/输出

1)fgets()函数

#include

char *fgets(char *s, int size, FILE *stream)

对于fgets()函数而言,'\n'是一个特别的字符,作为结束符;而'\0'并无任何特别之处,只用作普通字符串读入。正因为'\0'作为一个普通的字符串,因此无法判断缓冲区中的'\0'究竟是从文件读上来的字符还是有fgets()函数自主添加的结束符,所以fgets()函数只用于读文本文件而不提倡读二进制文件,并且文本文件中的所有字符串不能有'\0'。

2)fputs()

#include

int fputs(const char *s, FILE *stream)

缓冲区s中保存的是以'\0'结尾的字符串,fputs()将该字符串写入文件stream,但并不写入结尾的'\0',且字符串中可以有'\n',也可以没有'\n'。

10.3.4 数据块输入/输出

1)fread()和fwrite()函数

#include

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

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

10.3.5 格式化输入/输出

所谓格式化输入/输出,就是按照一定的格式将数据进行输入/输出操作。在程序中经常用到的printf()函数和scanf()函数是用于对终端设备文件的读写操作,这两个函数被称为格式化输入/输出,因为在使用这两个函数时,需要制定读写数据的数据类型并按照一定的格式进行读写。

1)格式化输入函数

#include

int printf(const char *format,...)

int fprintf(FILE *stream, const char *format)

int sprintf(char *str, size_t size, const char *format,...)

2)格式化输出函数

#include

int scanf(const char *format,...)

int fscanf(FILE *stream, const char *format,...)

int sscanf(const char *str, const char *format,...)

10.3.6 操作读写位置的函数

1)fseek()函数

#inlcude

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

函数fseek()的作用是用来移动文件内部位置指针。

2)ftell()函数

#inlcude

long ftell(FILE *stream)

ftell()函数的作用是得到stream指定的流式文件中的位置。

3)rewind()函数

void rewind(FILE *stream)

rewind()函数的作用是使位置指针重新返回文件的开头,该函数没有返回值。

10.3.7 C标准的I/O缓冲区

C标准库在调用fopen()函数时,都会给此文件分配一个I/O缓冲区,可以加速读写操作,原因在于用户程序需要调用C标准I/O库函数(如fread()、fwrite()等基于文件流I/O操作)读写文件,当缓冲区装满后,再由系统调用的I/O函数(如read()、write()等基于文件描述符的I/O操作)把读写请求传给内核,最终由内核驱动磁盘或设备完成I/O操作。

由此看来,为文件分配的内存缓冲区大小,直接影响到实际操作外村设备的次数,内存中为未见分配的缓冲区越大,操作外存的次数会越小,因此读写数据的速度会越来越快,效率就会随之增高。

然而,有时用户程序等不及将缓冲区都装满之后再传给内核,进行I/O操作,而是希望把I/O缓冲区中的数据立刻传给内核,让内核写回设备,这种行为叫做flush操作,对应的库函数是fflush()。

C标准库的I/O缓冲区有全缓冲、行缓冲和无缓冲3种类型。

1)全缓冲:如果缓冲区写满了,就写回内核。普通文件通常是全缓冲的。

2)行缓冲:如果用户程序写的数据中有'\n',就把这一行写回内核,或者缓冲区写满后就写回内核。标准输入和标准输出对应中断设备时通常是行缓冲。

3)无缓冲:用户程序每次调库函数做写操作都要通过系统调用写回内核。标准错误输出通常是无缓冲的。这样用户程序产生的错误信息就可以尽快输出到设备。

使用缓冲区时,会使用到如下两类操作,一个是设置缓冲区属性,另外一个是清空缓冲区。

4)设置缓冲区属性

#include

void setbuf(FILE *stream, char *buf)

void setbuffer(FILE *stream, char *buf, size_t size)

void setlinebuf(FILE *stream)

int setvbuf(FILE *stream, char *buf, int mode, size_t size)

setbuf()函数主要实现了为参数buf所指定的缓冲区设置大小。此函数中,设定缓冲区大小的值只有两个,一个是常数BUFSIZ,另一个是NULL。当定义值为BUFSIZ时,代表设置缓冲区为全缓冲;若为NULL,则代表设置缓冲区为无缓冲形式。

setbuffer()与setbuf()功能相同,只是setbuffer()函数可以任意指定缓冲区大小为size

setlinebuf()函数实现了将stream指向的缓冲区设置为行缓冲。

setvbuf()函数融合了上述3种函数的功能,既可以设置缓冲区的任意大小size,也可以设置缓冲区的任意类型,如mode参数取值为_IOFBF(全缓冲类型)、_IOLBF(行缓冲类型)或_IONBF(无缓冲类型)。

5)清空缓冲区

#include

int fflush(FILE *stream)

fflush()函数实现将缓冲区中的尚未写入文件的数据强制性地写进stream所指定的文件中,然后清空缓冲区。如果stream为NULL,此函数会将所有打开的文件数据更新。

10.4 小结

本章主要介绍了Linux系统下的文件I/O操作。在Linux系统下存在两种文件I/O操作,一种是基于文件描述符的I/O操作,这里面的I/O操作都是Linux系统中提供并直接作用于内核的,是非缓冲的I/O操作;另一种I/O操作是基于数据流的I/O操作,是由C语言的stdio库所提供的,需要在内存中开辟一块缓冲区,在缓冲区中进行快速地读写操作。本章主要结合典型实例介绍了上述两种I/O操作方式对文件的打开、关闭、读、写、文件定位等操作。

注:感觉本文10.3.5之前的内容对我有用,让我大概明白了基于数据流的文件I/O和基于文件描述符的文件I/O操作之间的区别。但是如果在给出其中的从操作函数之后给出一些实例就更好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281617.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

个人中心标签页导航

新页面userbase.html,用<ul ><li role"presentation"> 实现标签页导航。<ul class"nav nav-tabs"> <li role"presentation"><a href"#">Home</a></li> <li role"presentation&qu…

智慧城市免费WiFi覆盖怎么实施?武邑开启智慧生活模式

“真没想到武邑这个国家级贫困县也能够随地使用无线网络&#xff0c;我初次考察就喜欢上了这里。”准备前来武邑县投资的客商王先生说。日前&#xff0c;随着县城广场、商场等公共场所的免费WiFi覆盖&#xff0c;及移动电子商务借势O2O的快速发展&#xff0c;衡水市武邑县正在逐…

Uno开发的小游戏

大家好&#xff0c;我是沙漠尽头的狼。刚在微信群里逛&#xff0c;有网友发了Uno的在线小游戏&#xff0c;站长觉得不错&#xff0c;简单分享下&#xff1a;群聊涨见识Uno是什么&#xff1f;使用 C# 和 WinUI 实现像素完美的多平台应用程序&#xff0c;用于构建适用于 Windows、…

sqlplus命令行登录oracle数据库的N种方法盘点

欢迎访问我的个人博客IT废柴&#xff0c;本文永久链接移至&#xff1a;sqlplus命令行登录oracle数据库的N种方法盘点 sqlplus有几种登陆方式Oracle数据库&#xff0c; 比如&#xff1a; 1.以操作系统权限认证的oracle sys管理员登陆 C: > sqlplus "/as sysdba" 2…

拉美光伏新兴市场热潮将至

国际油价下滑对油气生产国的影响是不言而喻的&#xff0c;受此拖累&#xff0c;可再生能源产业发展也承受了一定压力。然而&#xff0c;在多国拥有油气资源的拉美地区&#xff0c;情况却恰恰相反&#xff0c;许多国家的可再生能源产业非但没有受低油价拖累&#xff0c;反而快速…

linux下常见生产脚本,不看后悔的Linux生产服务器Shell脚本分享(2)

一、MySQL的热备份脚本这是MySQL的备份方式之一&#xff0c;脚本如下&#xff1a;#!/bin/bashPATH/usr/local/sbin:/usr/bin:/bin# The Directory of BackupBACKDIR/usr/mysql_backup# The Password of MySQLROOTPASSpassword# Remake the Directory of Backuprm -rf $BACKDIRm…

兄弟连学python——MongoDB相关

1.常用的命令 show dbs 显示数据库列表use dbname 进入dbname数据库&#xff0c;大小写敏感&#xff0c;没有这个数据库也不要紧show collections 显示数据库中的集合&#xff0c;相当于表格2.创建&新增 db.users.save({"name":"lecaf"}) …

WPF-12 路由事件之二

WPF 为我们提供了许多不同的事件处理机制——它们是冒泡、隧道和直接的。这些都称为路由事件直接事件直接在事件源上处理&#xff0c;这个有点像WinForms中的按钮OnClick事件&#xff0c;直接在事件处理程序中处理业务冒泡事件当事件没有被元素&#xff08;比如一个文本框&…

对01背包的分析与理解(图文)

首先谢谢Christal_R的文章(点击转到链接)让我学会01背包 本文较长&#xff0c;但是长也意味着比较详细&#xff0c;希望您可以耐心读完。 题目: 现在有一个背包(容器),它的体积(容量)为V,现在有N种物品(每个物品只有一个),每个物品的价值W[i]和占用空间C[i]都会由输入给出,现在…

linux内核源码剖析 博客,【Linux内存源码分析】页面迁移

页面迁移其实是伙伴管理算法中的一部分&#xff0c;鉴于其特殊性&#xff0c;特地另行分析。它是2007年的时候&#xff0c;2.6.24内核版本开发时&#xff0c;新增碎片减少策略(the fragmentation reduction strategy)所引入的。该策略也称之为反碎片技术(anti-gragmentation)。…

360的下一代SOC是这个样子的

几乎所有大型企业或机构的IT系统中&#xff0c;都会有安全运营中心(SOC)&#xff0c;它是网络安全防护体系从设备部署到系统建设&#xff0c;再到统一管理&#xff0c;这一发展过程的自然产物。但在国内的实际应用中&#xff0c;SOC的问题多多。 首先是数据类型不全&#xff0c…

【转载】利用scipy.misc等库对jpg以及png等图像数据预处理(用于深度学习喂数据)...

http://blog.csdn.net/qq_16949707/article/details/56306720 转载于:https://www.cnblogs.com/tenderwx/p/8057599.html

2018年下半年网络公式考试案例分析真题

阅读以下说明&#xff0c;回答问题1至问题3&#xff0c;将解答填入答题纸对应的解答栏内。【说明】某公司网络划分为两个子网&#xff0c;其中设备A是DHCP服务器&#xff0c;如图3-1所示。 【问题1】(6分&#xff0c;每空2分)DHCP在分配IP地址时使用 (1) 的方式&#xff0c; 而…

哪一个不是linux常用的shell,Linux下查看使用的是哪种shell的方法汇总

查看当前发行版可以使用的shell复制代码代码如下:[rootlocalhost ~]$ cat /etc/shells/bin/sh/bin/bash/sbin/nologin查看当前使用的shell方法一、最常用的查看shell的命令&#xff0c;但不能实时反映当前shell复制代码代码如下:[rootlocalhost ~]$ echo $SHELL/bin/bash二、下…

企业建设呼叫中心需要考虑哪些因素

呼叫中心发展至今&#xff0c;它的意义早已不是90年代末,只是简单地解决客户客服系统的要求。现在的呼叫中心有了新的使命&#xff0c;比如拓展成为一个信息服务中心&#xff0c;或者成为一个营销中心。客户如何能通过这样的手段&#xff0c;使企业与其他的企业之间形成差异化的…

【单片机入门】(三)应用层软件开发的单片机学习之路-----UART串口通讯和c#交互...

本文由网友投稿。作者&#xff1a;陈显达原文标题&#xff1a;【单片机入门】(三)应用层软件开发的单片机学习之路-----UART串口通讯和c#交互原文链接&#xff1a;https://www.cnblogs.com/1996-Chinese-Chen/p/16826558.html引言在第一章博客中&#xff0c;我们讲了Arduino对E…

linux中使用yum的优点,linux – 自动“yum update”以保证服务器安全 – 优点和缺点?...

这取决于根据我使用CentOS的经验,它非常安全,因为您只使用CentOS基本存储库.您是否应该偶尔尝试更新失败…是…在您应该期望出现故障的硬盘驱动器或偶尔出现故障的CPU的同一级别上.您永远不会有太多备份. &#x1f642;关于自动更新的好处是,您可以比手动修补更快(因此更安全).…

高能力成熟度软件企业中软件质量工程师的职责

随着科学技术的不断发展进步&#xff0c;企业之间的竞争越来越激烈。软件企业要想在竞争中发展生存&#xff0c;提高软件产品质量已成为必要条件。在一些高能力成熟度软件企业中&#xff0c;专门成立了质量保证和控制职能部门&#xff0c;起着提高项目管理透明性和确保软件产品…

存储过程和函数的区别

存储过程和函数的区别存储过程和函数目的是为了 可重复地 执行操作数据库的sql语句的集合。区别是写法和调用上。写法上&#xff1a;存储过程的参数列表可以有输入参数、输出参数、可输入输出的参数&#xff1b;函数的参数列表只有输入参数&#xff0c;并且有return <返回值…

机器学习案例丨基于广泛和深入的推荐 - 餐厅评级预测

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;18分钟&#xff09;Microsoft Azure Machine Learning Studio 是微软强大的机器学习平台&#xff0c;在设计器中&#xff0c;微软内置了15个场景案例&#xff0c;但网上似乎没有对这15个案例深度刨析的分析资料&#…