==============================================================================
LINUX中
1. LINUX几乎将所有的东西看成是文件(网络稍微特殊点)
文件:一组相关数据的有序集合。
文件按类型分类:
1、常规文件:ASCII码文件、二进制的文件
2、目录
3、字符设备
4、块设备
5、有名管道
6、套接口
7、符号连接
2. 应用实现策略,驱动实现机制
对文件进行操作的两种方式:
------------------------------------------------------------------------------
1.标准IO(标准C库函数):不依赖于系统,建立在系统调用的基础上,带缓冲
2.文件IO(系统调用):依赖于系统,不同的系统有差异
IO: In/Out,输入/输出,对文件进行读写
系统调用和库函数的差别
------------------------------------------------------------------------------
LINUX系统中大概有200多个不到300个系统调用函数
库函数可以有很多。 比如数学库,浮点库(不需要系统调用)
系统调用与库函数的比较
所有的操作系统都提供多种服务的入口点,通过这些入口点,程序向内核请求服务
从执行者的角度来看,系统调用和库函数之间有重大的区别,但从用户的角度来看,其区别并不非常的重要。
应用程序可以调用系统调用或者库函数,库函数则会调用系统调用来完成其功能,库函数并不必须需要系统调用,比如数学库,浮点库
系统调用通常提供一个访问系统的最小界面,而库函数通常提供比较复杂的功能。
标准IO与文件IO最大差别:
------------------------------------------------------------------------------
标准IO 有缓冲,文件IO无缓冲
标准IO基本概念:
------------------------------------------------------------------------------
标准IO,由库在内存中开辟一个缓冲区,读写的时候是对缓冲区操作,以提高系统的效能
1. 缓冲区分三种类型:一般缓冲区的最佳大小:1024 或者是 4096 (查看系统缓冲的命令:ulimit -n)
全缓冲:
当填满I/O缓冲后才进行实际I/O操作(缓冲区满, 文件关闭, 调用fflush())
行缓冲(当且仅当标准输入和标准输出不涉及交互式设备时是全缓冲)
当在输入和输出中遇到新行符(‘\n’)时,进行I/O操作('\n', fflush(), 进程结束/文件关闭)
不带缓冲(标准错误输出就是不带缓冲):
标准出错是不带缓冲的,打开至终端设备的流是行缓冲;其他所有流则是全缓冲。
2.改变缓冲的特性:(做了解)
2.1. setbuf()和setvbuf()可以更改缓冲的类型
//这两个函数将使得打开文件后,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。
void setbuf(FILE *steam, char *buf); //把缓冲区与流相联 参数buf必须指向一个长度为BUFSIZ的缓冲区。
程序例:
#include <stdio.h>
/* BUFSIZ is defined in stdio.h */
char outbuf[BUFSIZ];
int main(void)
{
/* attach a buffer to the standard output stream */
setbuf(stdout, outbuf);
/* put some characters into the buffer */
puts("This is a test of buffered output.\n\n");
puts("This output will go into outbuf\n");
puts("and won't appear until the buffer\n");
puts("fills up or we flush the stream.\n");
/* flush the output buffer */
fflush(stdout);
return 0;
}
int setvbuf(FILE *stream, char *buf, int type, unsigned size);
type 值含义
_IOFBF 文件全部缓冲,即缓冲区装满后,才能对文件读写
_IOLBF 文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写
_IONBF 文件不缓冲,此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲
程序例:
#include <stdio.h>
int main(void)
{
FILE *input, *output;
char bufr[512];
input = fopen("file.in", "r+b");
output = fopen("file.out", "w");
/* set up input stream for minimal disk access,
using our own character buffer */
if (setvbuf(input, bufr, _IOFBF, 512) != 0)
printf("failed to set up buffer for input file\n");
else
printf("buffer set up for input file\n");
/* set up output stream for line buffering using space that
will be obtained through an indirect call to malloc */
if (setvbuf(output, NULL, _IOLBF, 132) != 0)
printf("failed to set up buffer for output file\n");
else
printf("buffer set up for output file\n");
/* perform file I/O here */
/* close files */
fclose(input);
fclose(output);
return 0;
}
2.2.使用fflush()强制刷新
形式: int fflush(FILE *stream);
3.文件指针:
每个被使用的文件都在内存中开辟一个区域,用来存放文件的有关信息,这些信息是保存在一个结构体类型的变量中,该结构体类型是由系统定义的,取名为FILE
FILE *, 文件指针, 指向FILE结构体
FILE 结构体: /usr/include/libio.h
struct _IO_FILE {
/*读写文件指针位置*/
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
//...
int _fileno; //文件IO关联
};
4.流:
标准I/O库的所有操作都是围绕流(stream)来进行的,在标准I/O中,流用FILE *来描述。
5.每个进程在创建的时候,会自动打开3个标准终端:
------------------------------------------------------------------------------------------------
描述 文件指针(FILE *) 文件描述符(int) 文件描述符对应的宏(int)
1.标准输入(行缓冲) stdin 0 STDIN_FILENO
2.标准输出(行缓冲) stdout 1 STDOUT_FILENO
3.标准错误输出(无缓冲) stderr 2 STDERR_FILENO
6.标准IO的库函数
--------------------------------------------------------------------------------------------------
6.1.fopen() //按照指定方式打开一个流
形式:
FILE *fopen(const char *path, const char *mode);
mode:
主要特性: r(read),w(write),a(add), b(binary)
附加特性: + (增加读写的另外特性)
操作ASCII的文件: r+, w+, a+
操作二进制:rb+, wb+ ab+
freopen()//重定位流
FILE *freopen(const char *path, const char *mode, FILE *stream);
---------------------------------------------------------------
例子:freopen("1.txt", "w+", stdout);//将stdout重定位到文件1.txt
思考:如何再定位回来?/dev/tty
附:errno: 错误号 /usr/include/asm-generic/errno-base.h
全局错误码errno:每个进程或线程独有自己独立一个errno,它记录的是上一次出现错误的原因(错误号)
#include <errno.h>
EACCES Permission denied (POSIX.1) //权限不允许
EAGAIN Resource temporarily unavailable //资源临时不可用
EBUSY Device or resource busy //设备忙
EEXIST File exists //文件已经存在
EINTR Interrupted function call, // 被“中断”打断
相关函数:
error(3), perror(3), strerror(3)
// FIX!!! fopen()没有设定创建文件权限的参数,可以通过umask命令修改
创建文件的默认权限:0666&~umask 若umask默认为0002 则文件权限是0664
创建目录的默认权限:0777&~umask 若umask默认为0002 则目录权限是0775
umask 文件 目录
6.2.int fclose(FILE *stream);//关闭流
6.3.对文件的读写:
6.3.1.一个字符读:
int fgetc(FILE *stream)//函数
int getc(FILE *stream)//宏
int getchar()//等价于getc(stdin)//宏
返回值:出错或到达文件尾均为EOF(-1),正确为读到的字符
注意:不管是出错还是到达文件尾端,这三个函数都返回同样的值。为了区分这两种不同的情况,必须调用ferror()或feof()
文件结束判断:
feof()
判断文件是否结束,可用于二进制文件和ASCII文件。
int ch;
while (!feof(fp) && !ferror(fp)) {
ch = fgetc(fp);
}
6.3.2.一个字符写:
int fputc(int c, FILE *stream)//函数
int putc(int c, FILE *stream)//宏
int putchar(int c)//等价于putc(c,stdout)//宏
返回值:出错为EOF(-1),正确为写的字符c
***********************************************************************
6.3.3.一行读:
char *gets(char *s)//不含换行符,容易造成缓冲区溢出, 绝对不推荐使用
char *fgets(char *s, int size, FILE *stream)//会加入换行符
返回值:成功返回s指针,处于文件尾端或出错则为NULL
6.3.4.一行写:
int puts(const char *s);//虽然不会溢出但会自动加入一个换行符,不推荐使用
int fputs(const char *s, FILE *stream);
返回值:若成功则为非负值,若出错则为EOF
***********************************************************************
6.3.5.直接读:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *strem);
6.3.6.直接写:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *strem);
两个函数的返回值:读或写的对象数
7.扩展函数:
ftell():
形式long ftell(FILE *stream);
ftell()用于取得当前的文件指针位置,并不调整文件指针
fseek():
形式:
int fseek(FILE *stream, long offset, int whence);
调整文件指针到 whence + offset
第三个参数:whence:
SEEK_SET: 调整文件指针到文件起始位置
SEEK_CUR: 调整文件指针到当前位置
SEEK_END: 调整文件指针到文件结束
void rewind(FILE *stream)等价于(void)fseek(stream, 0L, SEEK_SET) //把文件指针调整到文件头
8.时间相关函数
世界标准时间:格林威治标准时间(1970年1月1日0点)
time_t time(time_t *tloc)//获取日历时间,即从1970年1月1日0点到现在所经历的秒数。
struct tm *gmtime(const time_t *timep)//将日历时间转化为格林威治时间,并保存至tm结构。
struct tm *localtime(const time_t *timep)//将日历时间转换为本地时间,并保存至tm结构。
/*struct tm分解时间表示*/
struct tm {
int tm_sec; /* 秒 – 取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值等于实际年份减去1900 tm_year+1900=实际年份*/
int tm_wday; /* 本周第几日,其中0代表星期天,1代表星期一,以此类推 */
int tm_yday; /* 本年第几日,其中0代表1月1日,1代表1月2日,以此类推 */
int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时tm_isdst()为负。*/
};
char *asctime(const struct tm *tm)//将tm格式的时间转化为字符串,如:Sat Jul 30 08:43:03 2005
char *ctime(const time_t *timep)//将日历时间转化为本地时间的字符串形式。
unsigned int sleep(unsigned int seconds)//使程序睡眠seconds秒
void usleep(unsigned long usec)//使程序睡眠usec微秒。
======================================================================================================