转载请注明出处:http://blog.csdn.net/suool/article/details/38129201

问题引入

文件的种类

依据数据存储的方式不同,能够将文件分为文本文件和二进制文件.详细的差别和关系例如以下:

文本文件与二进制文件在计算机文件系统中的物理存储都是二进制的,也就是在物理存储方面没有差别都是01码,这个没有异议。他们的差别主要在逻辑存储上,也就是编码上。

文本文件格式存储时是将值作为字符然后存入其字符编码的二进制文本文件用‘字符’作为单位来表示和存储数据,比方对于1这个值,文本文件会将其看做字符‘1’然后保存其ASCII编码值(这里假定是ASCII编码),这样在物理上就是0x31这个二进制值。而若是二进制保存1,则直接保存其二进制值,比方假设程序中是处理1为整数则保存的二进制值就是 0x00000001 (4字节)。

当然假设程序本来就是按字符保存的 也就是 char ch ='1' ;则二进制保存后值就是其ASCII码。由于该变量的二进制本来就是其ASCII码。

能够总结出二进制文件就是值本身的编码,那么就是不定长的编码了,由于值本身就是不等字节的,如整数4个字节那么保存在二进制文件就是这四个字节的原生二进制值。

综上,能够知道文本文件与二进制文件就是编码方式不一样而已,而这个是用户行为,把一个数据以什么样的编码(字符还是值本身)存入文件是由用户主动选择的,也就是写入的接口选择。假设以二进制接口方式写入文件那么就是一个二进制文件,假设以字符方式写入文件就是一个文本文件了。

既然有写入时候的编码也就会有读出的编码,仅仅有两个编码相应才干读出正确的结果。如用记事本打开一个二进制文件会呈现乱码的。这里略微提一下后缀名,后缀名并不能确定其是否就是文本文件,二进制文件也能够是txt后缀名,后缀名仅仅是用来关联打开程序,给用户做备注用的。与文件的详细编码没有关系



能够使用字符接口读写二进制文件。仅仅须要做些处理就可以,所以所谓的二进制文件,文本文件主要体如今读写方式这里。此外windows有一个明显的差别是对待文本文件读写的时候,会将换行 \n自己主动替换成 \r\n。

最后文本文件和二进制文件主要是windows下的概念,UNIX/Linux并没有区分这两种文件。他们对全部文件一视同仁。将全部文件都看成二进制文件。

文件操作方式

依据应用程序对文件的訪问方式不同,能够分为带缓冲区的文件操作和非缓冲文件操作,详细差别简介例如以下:

缓冲文件操作:高级文件操作,将在用户空间中自己主动为正在使用的文件开辟内存缓冲区,遵循ANSI C标准的I/O函数就是缓冲文件操作

非缓冲文件操作:低级文件操作,假设须要,仅仅能由用户自己在程序中为每一个文件设置缓冲区,遵循POSIX标准的系统调用I/O函数就是这样的类型.

详细的差别见:http://www.360doc.com/content/11/0521/11/5455634_118306098.shtml

ANSI C库函数为了实现他的特性,採用了流的概念,在流的实现中,缓冲区是最重要的单元,依据须要能够分为全缓冲,行缓冲,无缓冲.

以下就详细讲一下关于ANSI  C的流和文件I/O相关的方法和函数.

问题解析

关于流及其功能

在linux系统中,系统默觉得每一个进程打开了三个文件,即是每一个进程能够默认操作三个流:标准输入流,输出流,错误流.

在系统源文件里的宏定义例如以下:

文件流的主要功能是:

1'格式化内容:实现不同输入输出格式转换.

2'缓冲功能:将数据读写集中,从而降低系统调用次数

文件流指针

在应用编程层面上,程序对流的操作主要是体如今文件流指针FILE上,操作一个文件之前,须要使用fopen打开文件,之后返回该文件的文件流指针与该文件关联,全部针对该文件的读写操作都是通过文件指针完毕.以下是在应用层可以訪问的FILE的结构体,因此结构体成员可以在用户空间訪问:

struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
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. */
..............
int _fileno; / 文件描写叙述符
#if 0
}

上面那个结构体中包括了I/O库为管理该流所须要的全部信息.

以下是打印了一个打开的文件流指针指针成员信息的演示样例程序,在此程序中,使用标准的C库函数实现了文件的复制操作,在复制过程中,实时打印当前的读写位置和缓冲区信息.

代码例如以下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define prt(CONTENT,MSG) printf(CONTENT":\t%p\n",MSG) int main(int argc, char *argv[])
{
FILE *fp_src,*fp_des; // 文件读写指针
char buffer[10],buffer1[128]; // 文件读写缓冲区
int i;
if((fp_src=fopen(argv[1],"r+"))== NULL) // 从第一个命令行文件參数,读文件
{
perror("open1");
exit(EXIT_FAILURE);
}
if((fp_des=fopen(argv[2],"w+"))== NULL) // 从第二个命令行文件參数,写文件
{
perror("open2");
exit(EXIT_FAILURE);
}
setvbuf(fp_src,buffer1,_IOLBF,128); // 显式设置缓冲区的位置和类型
do
{
/*
* 下面的prt内容均是属于提示性内容,是读取应用层所能訪问的FILE结构体得到的.
*/
prt("src_IO_read_ptr",fp_src->_IO_read_ptr); // 源文件读位置,source
prt("_IO_read_end",fp_src->_IO_read_end);
prt("_IO_read_base",fp_src->_IO_read_base); prt("src_IO_write_ptr",fp_src->_IO_write_ptr);
prt("_IO_write_base",fp_src->_IO_write_base);
prt("_IO_write_end",fp_src->_IO_write_end); prt("_IO_buf_base",fp_src->_IO_buf_base); // 源文件缓冲区位置
prt("_IO_buf_end",fp_src->_IO_buf_end); memset(buffer,'\0',10);
i = fread(buffer,1,10,fp_src); // 读
fwrite(buffer,1,i,fp_des); // 写 prt("des_IO_read_ptr",fp_des->_IO_read_ptr);
prt("des_IO_write_ptr",fp_des->_IO_write_ptr); // 目标文件写位置 }while(i==10);
fclose(fp_src);
fclose(fp_des); // 关闭文件读写
}

执行结果例如以下:

终于成功复制.

缓冲区类型

刚刚说了三种缓冲区类型,他们依旧在系统源码文件有所定义.

对于标准流ANSI C有例如以下的要求:

1.标准输入输出:当且仅当不涉及交互作用设备时,他们才是全缓冲的

2.标准错误:绝不会是全缓冲的

以下是用于測试缓冲区类型的演示样例程序.

代码:

#include <stdio.h>

void pr_stdio(const char *, FILE *);
int main(void)
{
FILE *fp;
fputs("enter any character\n", stdout);
if(getchar()==EOF)
printf("getchar error");
fputs("one line to standard error\n", stderr);
pr_stdio("stdin", stdin); // test for standard input stream
pr_stdio("stdout", stdout); // test for standard output stream
pr_stdio("stderr", stderr); // test for standard error stream if ( (fp = fopen("/etc/motd", "r")) == NULL) // 普通文件
printf("fopen error");
if (fgetc(fp) == EOF)
printf("getc error");
pr_stdio("/etc/motd", fp);
return(0);
}
void pr_stdio(const char *name, FILE *fp)
{
printf("stream = %s, ", name);
if (fp->_flags & _IO_UNBUFFERED) // 无缓冲
printf("unbuffered");
else if (fp->_flags & _IO_LINE_BUF) // 行缓冲
printf("line buffered");
else
printf("fully buffered"); // 全缓冲
printf(", buffer size = %ld\n", fp->_IO_buf_end-fp->_IO_buf_base);
}

结果例如以下:

指定缓冲区类型,通过sretbuf函数.当中三种缓冲的定义例如以下:

一个演示样例代码例如以下:

/* Example show usage of setbuf() &setvbuf() */
#include<stdio.h>
#include<error.h>
#include<string.h>
int main( int argc , char ** argv )
{
int i;
FILE * fp;
char msg1[]="hello,wolrd\n";
char msg2[] = "hello\nworld";
char buf[128]; //open a file and set nobuf(used setbuf).and write string to it,check it before close of flush the stream
if(( fp = fopen("no_buf1.txt","w")) == NULL)
{
perror("file open failure!");
return(-1);
}
setbuf(fp,NULL); // set the buff NULL
memset(buf,'\0',128);
fwrite( msg1 , 7 , 1 , fp ); // write message to file
printf("test setbuf(no buf)!check no_buf1.txt\n");
printf("now buf data is :buf=%s\n",buf); // test buff printf("press enter to continue!\n");
getchar();
fclose(fp); //open a file and set nobuf(used setvbuf).and write string to it,check it before close of flush the stream
if(( fp = fopen("no_buf2.txt","w")) == NULL)
{
perror("file open failure!");
return(-1);
}
setvbuf( fp , NULL, _IONBF , 0 );
memset(buf,'\0',128); // clear the buff
fwrite( msg1 , 7 , 1 , fp );
printf("test setvbuf(no buf)!check no_buf2.txt\n"); printf("now buf data is :buf=%s\n",buf); printf("press enter to continue!\n");
getchar();
fclose(fp); //open a file and set line buf(used setvbuf).and write string(include '\n') to it,
//
//check it before close of flush the stream
if(( fp = fopen("l_buf.txt","w")) == NULL)
{
perror("file open failure!");
return(-1);
}
setvbuf( fp , buf , _IOLBF , sizeof(buf) );
memset(buf,'\0',128);
fwrite( msg2 , sizeof(msg2) , 1 , fp );
printf("test setvbuf(line buf)!check l_buf.txt, because line buf ,only data before enter send to file\n"); printf("now buf data is :buf=%s\n",buf);
printf("press enter to continue!\n");
getchar();
fclose(fp); //open a file and set full buf(used setvbuf).and write string to it for 20th time (it is large than the buf)
//check it before close of flush the stream
if(( fp = fopen("f_buf.txt","w")) == NULL)
{
perror("file open failure!");
return(-1);
}
setvbuf( fp , buf , _IOFBF , sizeof(buf) );
memset(buf,'\0',128);
fwrite( msg2 , sizeof(msg2) , 1 , fp );
printf("test setbuf(full buf)!check f_buf.txt\n"); printf("now buf data is :buf=%s\n",buf); // check data of the current buff
printf("press enter to continue!\n");
getchar(); fclose(fp); }

result:

ANSI C 文件I/O操作

1.打开关闭文件三个函数:

fopen()

fclose()

fflush()  // 刷新流

详细代码见stdio.h源码

2.读写文件

字符单位

1.字符读

从流中读取

从stdin中:

/* Read a character from stdin.

   This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int getchar (void);

2.字符写

/* Write a character to STREAM.

   These functions are possible cancellation points and therefore not
marked with __THROW. These functions is a possible cancellation point and therefore not
marked with __THROW. */
extern int fputc (int __c, FILE *__stream);
extern int putc (int __c, FILE *__stream); /* Write a character to stdout. This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int putchar (int __c);

行单位

行读出&行写入

/* Write a string to STREAM.

   This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int fputs (const char *__restrict __s, FILE *__restrict __stream); /* Write a string, followed by a newline, to stdout. This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int puts (const char *__s);



块单位

读写

/* Read chunks of generic data from STREAM.

   This function is a possible cancellation point and therefore not
marked with __THROW. */
extern size_t fread (void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __stream) __wur;
/* Write chunks of generic data to STREAM. This function is a possible cancellation point and therefore not
marked with __THROW. */
extern size_t fwrite (const void *__restrict __ptr, size_t __size,
size_t __n, FILE *__restrict __s);

文件流检測

即是检測文件是否已经读写到末尾或者出错.,使用feof函数.

对于ascii码文件,能够通过是否=EOF推断

对于二进制文件,则须要使用feof来推断是否结束,结束返回1.否则返回0.

ferror函数推断是否出错,无错返回0.

文件流定位

ftell()函数返回流的当前读写位置距离文件開始的字节数

fseek()函数改动当前读写位置

rewind()函数重置读写位置到开头.

/* Seek to a certain position on STREAM.

   This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int fseek (FILE *__stream, long int __off, int __whence);
/* Return the current position of STREAM. This function is a possible cancellation point and therefore not
marked with __THROW. */
extern long int ftell (FILE *__stream) __wur;
/* Rewind to the beginning of STREAM. This function is a possible cancellation point and therefore not
marked with __THROW. */
extern void rewind (FILE *__stream);

实例应用

为实现磁盘文件的复制,在ANSI C 的标准下,首先须要将源文件和目标文件建立联系以读的方式打开源文件,以写的方式打开目标文件,先将源文件的数据集中写到缓冲区,然后从内存写入目标文件所在的磁盘.

当中最重要的是推断文件的是否结束.一种方式是使用feof函数,还有一种方式是使用读操作的返回值,比方,每次读128字节,仅仅有读到结束位置的时候毒的字节数会小于128,假设出错则返回-1.

一种实现代码例如以下:

#include<stdio.h>
int main(int argc,char *argv[])
{
FILE *fp=NULL;
char ch;
if(argc<=1)
{
printf("check usage of %s \n",argv[0]);
return -1;
}
if((fp=fopen(argv[1],"r"))==NULL) //以仅仅读形式打开argv[1]所指明的文件
{
printf("can not open %s\n",argv[1]);
return -1;
}
while ((ch=fgetc(fp))!=EOF) //把已打开的文件里的数据逐字节的输出到标准输出stdout
fputc(ch,stdout);
fclose(fp); //关闭文件
return 0;
}

详细结果就不演示了.能够自行编译验证.

ElSE

流的格式化输入和输出操作

事实上就是几个函数的解说,这个部分非常多资料,所以不在讲了,详细的能够自己google或者看源码了.

1.

printf()和scanf(0函数.

2.

fprintf()函数和fscanf()函数

3.sprintf函数

4.sscanf()函数

以下贴一下一个使用sscanf获取cpu频率的演示样例程序:

#include <stdio.h>
#include <string.h>
float get_cpu_clock_speed ()
{
FILE* fp;
char buffer[1024];
size_t bytes_read;
char* match;
float clock_speed; fp = fopen ("/proc/cpuinfo", "r");
bytes_read = fread (buffer, 1, sizeof (buffer), fp);
fclose (fp);
if (bytes_read == 0 || bytes_read == sizeof (buffer))
return 0;
buffer[bytes_read] = '\0';
match = strstr (buffer, "cpu MHz"); //匹配
if (match == NULL)
return 0;
sscanf (match, "cpu MHz : %f", &clock_speed); //读取
return clock_speed;
}
int main (void)
{
printf ("CPU clock speed: %4.0f MHz\n", get_cpu_clock_speed ());
return 0;
}

result:

reference

关于二进制和文本文件 http://www.cnblogs.com/whutzhou/p/3215210.html

linux高级程序设计 李宗德

NEXT

POSIX 文件及文件夹管理

普通文件\连接文件及文件夹文件属性管理

转载请注明出处:http://blog.csdn.net/suool/article/details/38129201

Linux 编程学习笔记----ANSI C 文件I/O管理的更多相关文章

  1. Linux 编程学习笔记----动笔makefile档

    Befroe Beginning. 在设置暑假的plan ,关于Linux的书籍如今在看的是ALP和Linux高级程序设计(杨宗德)第三版.在计划中的是Linux高级环境编程. 如今開始关于Linux ...

  2. Linux 编程学习笔记----命令行参数处理

    转载请注明出处.http://blog.csdn.net/suool/article/details/38089001 问题引入----命令行參数及解析 在使用linux时,与windows最大的不同 ...

  3. Linux编程学习笔记(一)

    Linux的发展趋势势在必行,国内的服务器的操作系统Linux占到主导地位,不光是操作系统,还有嵌入式系统. 1. 今天就Linux的其中一个版本做一介绍,如下是Centos的版本之间的区别. ins ...

  4. Linux 编程学习笔记----过程管理和项目发展(在)

    转载请注明出处,http://blog.csdn.net/suool/article/details/38406211,谢谢. Linux进程存储结构和进程结构 可运行文件结构 例如以下图: 能够看出 ...

  5. Linux编程学习笔记(二)

    续上个章节,这个章节主要是Linux的远程登录系统操作笔记 一. Linux一般作为服务器使用,但是服务器都是在机房的,所以不可能经常跑到机房去操作系统,所以使用远程登录系统,在Linux的系统一般使 ...

  6. Linux学习笔记之1——文件和目录管理(硬连接和软连接)(连结档,相当于快捷方式)

    在这节将要学习linux的连接档,在之前用"ls -l" 查看文件属性的命令时, 其中第二个属性是连接数.那么这个连接数是干什么的?这就要理解inode. 先说一下文件是怎么存储的 ...

  7. LINUX编程学习笔记(十四) 创建进程与 父子进程内存空间

    1什么是进程:进程是一个执行中的程序 执行的程序: 代码->资源->CPU 进程有很多数据维护:进程状态/进程属性 所有进程属性采用的一个树形结构体维护 ps  -a//所有进程 ps - ...

  8. Linux 编程学习笔记----文档管理系统

    本文从网络上完成的第 Linux在文件系统管理. 1.VFS文件系统概述 linux採用VFS来管理文件系统,并且linux设计的原则之中的一个就是everything is file.因此文件管理系 ...

  9. LINUX编程学习笔记(十三) 遍历目录的两种方法

    1 默认情况下  实际用户和有效用户是一样的 实际用户:执行用户   有效用户:权限用户 getuid()  实际用户 geteuid() 有效用户 chmod u+s 之后 ,其他人执行文件时,实际 ...

随机推荐

  1. sql plus 抢救数据(測)

    有索引 --运行plsql脚本 DECLARE  TYPE RowIDTab ISTABLE OF ROWID INDEXBY BINARY_INTEGER;    CURSORc1 IS selec ...

  2. Java 反射机制[Method反射]

    Java 反射机制[Method反射] 接着上一篇Java 反射机制[Field反射],通过调用Person类的setName方法将obj的name字段的Value设置为"callPerso ...

  3. 腾讯測试project师笔试面试记录

        从3月29日參加腾讯笔试開始,開始了为期1周的腾讯之旅,尽管最后还是跪在了二面上,可是感觉收获非常多,至少明确了自己与向往的BAT公司的差距,明确了自己还是路漫漫其修远兮.     腾讯非常注 ...

  4. Android程序的目录结构

    本篇文章我们将介绍Android应用程序的目录结构.本目录下有如图的目录结构: 下面我们来一 一介绍: 1.     Src:该目录中存放的是该项目的源代码 2.     Gen:该目录下的文件全部都 ...

  5. vijos P1352 最大获利(最小割)

    请不要随便指点别人该怎么做.每一个人的人生都应该自己掌握.你给不了别人一切.你也不懂别人的忧伤. 微笑不代表快乐.哭泣不一定悲伤 不努力怎么让关心你的人幸福.不努力怎么让看不起你的人绝望. 我用生命在 ...

  6. 【Bug Fix】Error : Can&#39;t create table &#39;moshop_1.#sql-534_185&#39; (errno: 150)

    运行alter操作, alter table xx_shop_info add index FK9050F5D83304CDDC (shop_area), add constraint FK9050F ...

  7. poj 1011 Sticks ,剪枝神题

    木棒 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 118943 Accepted: 27429 Description 乔治拿 ...

  8. 收集经常使用的.net开源项目

    Json.NET http://json.codeplex.com/ Json.Net是一个读写Json效率比較高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单.通过Lin ...

  9. Python使用MySQLdb操作MySQL

    import MySQLdb,sys try: conn=MySQLdb.connect(host=,user=',db='db1') except Exception,e: print e sys. ...

  10. 【Java】运用JDBC实现一个注册、登录系统的编写

    数据库的建立 首先,建立一个数据库,存储注册成功的账户信息. 其SQL的DDL语句如下: CREATE TABLE `jdbctest` ( `id` int(10) NOT NULL auto_in ...