Bootstrap

linux读写的字节数和效率,Linux 文件流与目录流管理

Linux应用开发_04文件流与目录流管理

本课目标

(1)编程目标:

(a)实现磁盘文件的拷贝操作。

(b)缓冲区类型对磁盘真正写入操作的影响。

(2)理解文件流操作以及缓冲区概念。

(3)掌握ansi c 文件流相关操作函数。

(4)理解与掌握目录流操作。

主要知识点

(1)流的基本原理及作用,与文件描述符的关系。标准输入输出流基本概念,文件流结构体。

(2)缓冲区类型以及缓冲区作用。如何修改缓冲区。setbuf,setvbuf

(3)文件流操作。

(4)流的效率与可移植性。

(5)目录流操作与编程。

课程内容

文件流概念

FILE *fp = fopen();

typedef struct _IO_FILE FILE;

struct _IO_FILE {

int _flags; /* High-order word is _IO_MAGIC; rest isflags. */

#define _IO_file_flags _flags

/* The following pointers correspond to the C++ streambufprotocol. */

/* Note: Tk uses the _IO_read_ptr and _IO_read_end fieldsdirectly. */

char* _IO_read_ptr; /* Current read pointer */

char* _IO_read_end; /* End of get area. */

char* _IO_read_base; /* Start of putback+get area. */

char* _IO_write_base; /* Start of put area. */

char* _IO_write_ptr; /* Current put pointer. */

char* _IO_write_end; /* End of put area. */

char* _IO_buf_base; /* Start of reserve area. */

char* _IO_buf_end; /* End of reserve area. */

/* The following fields are used to support backing upand undo. */

char *_IO_save_base; /* Pointer to start of non-currentget area. */

char *_IO_backup_base; /* Pointer to first validcharacter of backup area */

char *_IO_save_end; /* Pointer to end of non-current getarea. */

struct _IO_marker *_markers;

struct _IO_FILE *_chain;

int _fileno; //关联的文件描述符

#if 0

int _blksize;

#else

int _flags2;

#endif

_IO_off_t _old_offset; /* This used to be _offset butit's too small. */

#define __HAVE_COLUMN /* temporary */

/* 1+column number of pbase(); 0 is unknown. */

unsigned short _cur_column;

signed char _vtable_offset;

char _shortbuf[1];

/* char* _save_gptr; char* _save_egptr; */

_IO_lock_t *_lock;

#ifdef _IO_USE_OLD_IO_FILE

};

流是在用户空间在文件描述符基础上进行的封装,添加了如下信息,使功能更强。

(1)缓冲区

(2)读写位置。

流的一个重要提高效率的方法是使用缓冲区,将多次的系统调用合并成一次系统调用,节约执行的

时间。

流和缓冲区:

(1)全缓冲。只有当数据量达到某个限制后(不同的平台有差异4096),或者主动的要求刷新缓冲

区(fclose/fflush),才真正执行一次系统调用操作。常见的哪些流是全缓冲:文件流,即以fopen 打开的

文件。

(2)行缓冲。只有当数据量达到某个限制(128,1024)或者遇到换行,或者主动要求(fclose/fflush)

刷新缓冲区后,才真正执行一次系统调用操作。常见的是终端命令行。

printf(“step 1\n”);

printf(“step 2\n”);

(3)无缓冲。需要实时显示信息的,例如标准的错误输出。fprintf(stderr,);

默认的三个打开的文件对应的流

/* Standard streams. */

extern struct _IO_FILE *stdin; /* Standard input stream.*/

extern struct _IO_FILE *stdout; /* Standard outputstream. */

extern struct _IO_FILE *stderr; /* Standard error outputstream. */

如果要修改缓冲的类型或者自己指定对应缓冲区的位置。可以使用 setbuf,setvbuf

#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_tsize);

_IONBF unbuffered

_IOLBF line buffered

_IOFBF fully buffered

通过程序来验证缓冲区的问题:

文件流的操作:编程中用到的函数,ANSI C 库函数。open/read/write/close 是系统调用函数。

1.打开/关闭

fopen

fclose

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

第一个参数为打开文件的路径(字符串),第二参数为打开的方式(字符串)。

r:只读。open O_RDONLY

w:只读。 open->O_WRONLY|O_CREAT|O_TRUNC

a:追加。open->O_APPEND|O_CREAT|O_WRONLY

X+:可读可写。open O_RDWR

FILE *fdopen(int fd, const char *mode);//将一个文件描述符封装成一个流

FILE *freopen(const char *path, const char *mode, FILE*stream);

使用完成后,全用flose 关闭这个流对象,期间会刷新流的缓冲区。

2、读写

一个字符一个字符的读写

fgetc/fputc

int fgetc(FILE *stream); //返回的是这个字符的sacii 值

int getc(FILE *stream); //类似于fgetc

int getchar(void);//从标准的输入流中读取一个字符。返回其Ascii 值

int ungetc(int c, FILE *stream);

int fputc(int c, FILE *stream); //将c 写入到stream流所指向的文件中

int putc(int c, FILE *stream);

int putchar(int c); //将c 字符写入到标准的输出流。

一行一行的读写

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

//从stream 流中期望读取大小为 size 个byte 的字符串,存储在s 指向的内存空间中,返回字符的位

置。

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

将s 指向的内存空间字符串写入到stream流中,返回写入的数据量。

char *gets(char *s); //从标准的输入流读取一行。

int puts(const char *s); //将一行字符串写入到标准的输出流中。

任意的大小读写

fread/fwrite

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

期望从stream 流所指向的文件读取nmemb 个大小为size 的数据,并存储在ptr 所指向的内存空间

中。返回是真正读出的个数。

size_t fwrite(const void *ptr, size_t size, size_t nmemb,

FILE *stream);

将存储在ptr 开始的内存空间中 nmemb 个大小为size 的数据写入到stream 流所指向的文件。

强调一下,read 函数返回的和write 返回的值是真正读写的字节数,而fread/fwrite 返回的是真正读

写的个数。字节数= size* nmemb。

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

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

3. 文件流状态的检测和设置

(1)读写出错的状态:

void clearerr(FILE *stream);

int ferror(FILE *stream);

如果读写出错,ferror 返回非0 值,可以全用clearerr 函数清除这个错误。

(2)读写结束的状态:feof(stream);

int feof(FILE *stream);,如果流的读写位置已经在文件尾部,返回非0 值.

文件流的读写位置

在流读写相关函数操作流时,文件的读写位置会自动的跟着移动。

文件的读写位置有三个参考点

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

long ftell(FILE *stream);//返回当前的读写位置距离文件头的字节数。

void rewind(FILE *stream); //将文件读写位置置到文件开头。

int fgetpos(FILE *stream, fpos_t *pos);

int fsetpos(FILE *stream, fpos_t *pos);

4. 写一个简单拷贝程序,从一个文件拷贝到另一个文件,分别用字节读,行读,任意大小读的方

式。

#include

#include

#include

int main(int argc,char *argv[])//argv[1]:src file,argv[2]:dst file

{

if(argc!=3)

{

printf("pls usage:%s src_filedst_file\n",argv[0]);

exit(EXIT_FAILURE);

}

FILE *fp_src = fopen(argv[1],"r");

if(NULL == fp_src)

{

printf("fopen error\n");exit(EXIT_FAILURE);

}

FILE *fp_dst = fopen(argv[2],"w");

if(NULL == fp_dst)

{

printf("fopen dst error\n");exit(EXIT_FAILURE);

}

/*

char ch;

while(1)

{

ch = fgetc(fp_src);

if(feof(fp_src))

{

break;

}

fputc(ch,fp_dst);

}

char buf[128];

while(1)

{

memset(buf,'\0',128);

fgets(buf,127,fp_src);

fputs(buf,fp_dst);

if(feof(fp_src))

break;

}

fclose(fp_src);

fclose(fp_dst);

}

5. 流的格式化输入输出的问题

printf/scanf 这一类函数的实现相当的复杂。

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

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

int sprintf(char *str, const char *format, ...);

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

返回值:返回真正打印字符的字节数。

printf 是fprintf 的特例。

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

将列表中的数据以指定的格式format 写入到stream 所指向的流中。printffprintf(stdout,format….);

格式化串的标准格式:具体可以参阅手册。

%[标志 ] [最小字段宽度] .[精度 ] [参数长度] [转换类型]

标志

-:表示左对齐

+

空格

#

0

最小字段宽度表示输出数据最小宽度,如果不够,空格补充。

精度表示最少输出数据的位数,浮点数转为小数后最小位数,字符串转换后的最大字符数。

参数长度

hh

h

l

l

L

转换类型:

d

o

u

x

f

e

c

s

p

int scanf(const char *format, ...);是fscanf 的特例,fscanf(stdio,format,,)

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

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

可变参数为存放数据的地址列表。

format 串的格式是

%[*][最大宽度][转换类型]

[*]抑制转换,按这个格式输入但不存入后面的内存空间。

sprint/sscanf 将数据输入/输入到字符串中。

;