例程见银行业务员系统那个编程作业。

fopen  

作用:打开文件

函数原型:FILE * fopen(const char * path, const char * mode);

返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回 NULL,并把错误代码存在 error 。

例:FILE *fp = fopen("test.txt","r+")

第三个参数:

 字符串   说明

  r            以只读方式打开文件,该文件必须存在。

  r+        以读/写方式打开文件,该文件必须存在。

  w          以只写方式打开文件, 若文件存在则覆盖,文件内容会消失,文件长度清零;不存在则创建该文件。

  w+       以读/写方式打开文件,若文件存在则覆盖,文件内容会消失,文件长度清零;不存在则创建该文件。

  a          以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则打开文件时,文件指

             针自动定位到文件末尾,即文件原先的内容会被保留(EOF 符保留)。

  a+       以附加方式打开可读/写的文件。若文件不存在,则会创建该文件;如果文件存在,则打开文件时,文

             件指针自动定位到文件末尾,加到文件尾后,即文件原先的内容会被保留(EOF符不保留)。


注意:

1. 所有的打开方式后边都可以加b或者t。b(binary):以二进制方式打开;t(text):以文本方式打开。不加时默认为文本方式(t)  例如:rb,rt+,wb.....。

    以 x 结尾的模式为独占模式,文件已存在或者无法创建(一般是路径不正确)都会导致 fopen 失败。文件以操作系统支持的独占模式打开。

    有些 C编译系统可能不完全提供所有功能,有的C版本不用"r+"、"w+"、"a+",而用"rw"、"wr"、"ar"等。

2. 一般情况下,不要直接使用附加方式打开文件然后操作,因为其附加方式很容易使文件位置混乱;附加方式只使用于一直追加,不对以前的值进行修改的操作。一般用附加方式来创建文件,例(本处暂不判断返回值):

  FILE *fp = NULL;

  fp = fopen("a.txt", "at+");

  fclose(fp);

  fp = fopen("a.txt", "rt+")

  ...

  fclose(fp);


  前半部分:at+方式打开文件,文件不存在时创建,存在时则什么也不做,然后关闭文件;

  后半部分:rt+方式打开文件,前边at+保证了文件是存在的,rt+可以对文件读写。如果用wt+,则会覆盖。

3.  回车问题

    文本文件中:windows以“\r\n”代表换行,linux是“\n”,mac是“\r”。

    二进制文件:windows以“\n”代表换行,linux是“\n”,mac是“\r”。

    Windows下: 若以文本模式打开文件,读写时回车如下操作:

        写:如果碰到 '\n',则在要写到文件中时,会在前边加一个'\r',即实际写入文件的是"\r\n",也就是0x0D,0X0A,这在文件中是占两个字节的,用fseek时要注意。

        读:如果碰到"\r\n",则只会将'\n'读到缓存中,但是"\r\n"要算两个字节长度。

    回车的显示问题:

        1. 如果在windows下编辑的文件,按下的回车都会转化为"\r\n",在linux下用vi显示就会有^M。

            如果在Linux用vi编辑的文件,按下的回车会转化为'\n',windows下不换行。

        2. UltraEdit在写文件时,回车都会转化为"\r\n",但它将'\n'显示换行,但记事本等不会换行。

4. '\0'问题

    '\0'仅仅用于方便操作字符串,用其表示字符串结束。将一个字符串写到文件中时,不会有'\0'写进去;从文件中读入字符串缓存时,也不会自动加'\0'。

    '\0'自动添加的情况:定义了字符串常量,例如 char *str1 = "hello world";它会保存在只读数据段,后边会自动添加'\0',也就是0x00.

    需要手动添加'\0'的情况:想要用到这个'\0'时,例如:用printf函数时,strlen函数时,strncpy时。因为printf和strlen的函数是通过判断'\0'来结束的,strncpy只会拷贝指定长度不会自动添加'\0',strcpy函数可以。

fwrite 

作用:向文件中写入数据

函数原型:size_t fwrite(const void *ptr, size_t size, size_t cnt, FILE *stream);

参数:buffer:是一个指针,对fwrite来说,是要获取数据的地址;

              size:要写入的单个数据项的字节数;

              cnt:要进行写入size字节的数据项的个数;

              stream:目标文件指针;

返回值:写入的数据的项数。

                 成功:返回值等于第三个参数cnt;

                 失败:返回0

例:struct mystruct

          {

              int i;

              char cha;

           }t_buf;

           fwrite(&t_buf, sizeof(t_buf), 1, fp);

fread  

作用:从文件中读出数据

函数原型:size_t fread(void *ptr, size_t size, size_t cnt, FILE *stream);

参数:buffer:是一个指针,对fwrite来说,是要获取数据的地址;

           size:要读出的单个数据项的字节数;

           cnt:要读出size字节的数据项的个数;

           stream:目标文件指针;

返回值:读出的数据的项数。

                 成功:返回值小于或者等于第三个参数cnt;

                 失败:设置errno,返回0

例:fread(&t_buf, sizeof(t_buf), 1, fp);

stat

可以用stat()、fstat()、lstat()获得​文件大小​,stat()效率最高、也比较稳定。

作用​:        将参数file_name所指的文件状态,复制到参数buf所指的结构中

头文件​:    #include <sys/stat.h> #include <unistd.h> 

函数原型​:int stat(const char * file_name, struct stat *buf);

返回值​:    执行成功则返回0,失败返回-1,错误代码存于errno 

示例​:

例1

int main(int argc, char **argv)

{

    struct stat buf; 

    stat (“/etc/passwd”, &buf); 

    printf(“/etc/passwd file size = %d /n”, buf.st_size); 

}

例2

int main(int argc, char **argv)

{   

    struct stat tStat;

    int fd;

    int ret;

    unsigned int size;  //文件大小

    fd = open("test.text",RDONLY);

    ret = fstat(fd, &tStat);

    if(ret)

    {

        return -1;

    }

    size = tStat.st_size;

}

struct stat内各参数的说明

struct   stat 

    dev_t     st_dev;     /*device:文件的设备编号 */ 

    ino_t     st_ino;     /*inode */ 

    mode_t    st_mode;    /*protection:文件的类型和存取的权限 */ 

    nlink_t   st_nlink;   /*number of hard links:连到该文件的硬连接数目,刚建立的文件值为1 */ 

    uid_t     st_uid;     /*user ID of owner:文件所有者的用户识别码 */ 

    gid_t     st_gid;     /*group ID of owner:文件所有者的组识别码 */ 

    dev_t     st_rdev;    /*device type:若此文件为装置设备文件,则为其设备编号 */ 

    off_t     st_size;    /*total size, in bytes*/ 

    unsigned  long   st_blksize;   /*blocksize for filesystem I/O   */ 

    unsigned  long   st_blocks;   /*number of blocks allocated:占用文件区块的个数,每一区块大小为512个字节*/ 

    time_t    st_atime;   /* time of lastaccess:文件最近一次被存取或被执行的时间,一般只有在用mknod、utime、read、write与tructate时改变 */ 

    time_t    st_mtime;   /* time of last modification:文件最后一次被修改的时间,一般只有在用mknod、utime和write时才会改变 */ 

    time_t    st_ctime;   /* time of last change:i-node最近一次被更改的时间,此参数会在文件所有者、组、权限被更改时更新。 */ 

}; 

先前所描述的st_mode则定义了下列数种情况 

    S_IFMT    0170000   文件类型的位遮罩 

    S_IFSOCK  0140000   scoket 

    S_IFLNK   0120000   符号连接 

    S_IFREG   0100000   一般文件 

    S_IFBLK   0060000   区块装置 

    S_IFDIR   0040000   目录 

    S_IFCHR   0020000   字符装置 

    S_IFIFO   0010000   先进先出 

    S_ISUID   04000     文件的(set user-id on execution)位 

    S_ISGID   02000     文件的(set group-id on execution)位 

    S_ISVTX   01000     文件的sticky位 

    S_IRUSR(S_IREAD)   00400   文件所有者具可读取权限 

    S_IWUSR(S_IWRITE)00200   文件所有者具可写入权限 

    S_IXUSR(S_IEXEC)   00100   文件所有者具可执行权限 

    S_IRGRP   00040   用户组具可读取权限 

    S_IWGRP   00020   用户组具可写入权限 

    S_IXGRP   00010   用户组具可执行权限 

    S_IROTH   00004   其他用户具可读取权限 

    S_IWOTH   00002   其他用户具可写入权限 

    S_IXOTH   00001   其他用户具可执行权限 

      上述的文件类型在POSIX中定义了检查这些类型的宏定义 

      S_ISLNK   (st_mode)   判断是否为符号连接 

      S_ISREG   (st_mode)   是否为一般文件 

      S_ISDIR   (st_mode)是否为目录 

      S_ISCHR   (st_mode)是否为字符装置文件 

      S_ISBLK   (s3e)   是否为先进先出 

      S_ISSOCK   (st_mode)   是否为socket 

      若一目录具有sticky   位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名。

fputc

作用:写一个字符到文件里

原型:int fputc (int c, File *fp)

参数:c为输出的字符量,虽然函数被定义为整型数,但仅用其低八位;fp为文件指针

返回值:成功:写入文件的字符的ASCII码值

        出错:EOF(-1)。

    当正确写入一个字符或一个字节的数据后,文件内部写指针会自动后移一个字节的位置。

    EOF是在头文件 stdio.h中定义的宏。

fputc和putc区别:

    putc()与fputc()作用相同,但putc()为宏定义,非真正的函数调用

fclose  

作用:关闭文件

函数原型:int fclose( FILE *fp );

返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。

(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)

例:ret = fclose(fp);

fseek/lseek

作用:设置文件指针位置。注意:\r和\n都会占一个字节的位置。

函数原型:int fseek(FILE *stream, long offset, int fromwhere)

返回值:

        成功:​函数返回0。 ​stream将指向以fromwhere为基准,偏移offset(指针偏移量)个字节的位置,。

        失败::(比如offset取值大于等于2*1024*1024*1024,即long的正数范围2G),则不改变stream指向的位置,

                    函数返回一个非0值,errno存放错误码。

    此函数第三个参数: SEEK_SET:文件开头      SEEK_CUR: 当前位置   SEEK_END: 文件结尾

    例1:fseek(fp, 0, SEEK_SET)       //跳转到首位置

    例2:fseek(fp, 0, SEEK_END)     //跳转到文件结尾

    例3:fseek(fp, 10, SEEK_CUR)   //跳转到当前位置向后偏移10个字节的位置

         ftell(fp)  //得到文件位置指针当前位置相对于文件首的偏移字节数


fseek函数和lseek函数类似,只是返回值不同:

    lseek 返回off_t(偏移值,即长度),而fseek返回的是一个整型(执行的结果)。

    lseek成功:返回目前的读写位置, 也就是距离文件开头多少个字节

             失败:返回-1, errno 会存放错误代码.

附加说明:Linux 系统不允许lseek()对tty 装置作用, 此项动作会令lseek()返回ESPIPE.

fprintf  

作用:以指定格式向文件写入

函数原型:int fprintf (FILE* stream, const char*format, [argument])

返回值:输出的字符数,发生错误时返回一个负值

例:fseek(fp,46*i,SEEK_SET);

        fprintf(fp,"%-10s",pwd);

fgetc

作用:从文件中读一个字节

函数原型:int fgetc(FILE *stream);

返回值:

        成功:返回所读取的一个字节。

        如果读到文件末尾或者读取出错:返回EOF。

例:char ch;

           ch = fgetc(fp)

fscanf

作用:以指定格式从文件读出。遇到空格或换行时结束。

函数原型:int fscanf(FILE*stream, constchar*format, [argument...])

返回值:整型,成功返回读入的参数的个数,失败返回EOF(-1)。

例:fseek(fp,46*i,SEEK_SET);

        fscanf(fp,"%d",&id);

fgets  

作用:从文件中读出字符串或者从屏幕上输入字符串。遇到空格不结束,遇到换行结束。

函数原型:char *fgets(char *s, int size, FILE *stream);

返回值:

        成功:返回第一个参数s;在读字符时遇到end-of-file,则eof指示器被设置

        失败:没读入任何字符就遇到end-of-file,则buf保持原来的内容,返回NULL;

                  发生读入错误,error指示器被设置,返回NULL,buf的值可能被改变。 

例1:fgets(buf,sizeof(buf),fp)

例2:fgets(buf,sizeof(buf),stdin)

详解:从fp所指文件中读入n-1个字符放入str为起始地址的空间内;

              如果在未读满n-1个字符之时,已读到一个换行符或一个EOF(文件结束标志),

          结束本次读操作,读入的字符串中最后包含读到的换行符(这就是为什么第二个

          参数是n,而最多只能读入n-1个字符的原因,这个地方一定要注意)

ftell  

作用:得到当前文件位置指针相对于文件首的偏移字节数

函数原型:long ftell(FILE *stream);

返回值:当前文件位置指针相对于文件首的偏移字节数

     该函数对大于231-1文件,即:2.1G以上的文件操作时可能出错。

例:fseek(fp, 0, SEEK_END)  //跳转到文件结尾

        ftell(fp)  //得到文件位置指针当前位置相对于文件首的偏移字节数

feof

作用:检测流上的文件结束符

函数原型:int feof(FILE *stream);

返回值:

        非0值:文件结束

        0值:其他情况

例:int c;

                while((c=fgetc(fp)) != EOF)

                {

                    printf("%X/n", c); 

                }

feof和eof的区别

两个的定义(stdio.h中)

#define  EOF  (-1) 

#define  _IOEOF  0x0010 

#define  feof(_stream)  ((_stream)->_flag & _IOEOF)

(1)EOF是文本文件结束的标志。文本文件中,数据是以字符的ASCⅡ代码值的形式存放,

    普通字符的ASCⅡ代码的范围是32到127(十进制),EOF的16进制代码为0xFF(十进制为-1),

    因此可以用EOF作为文件结束标志。

(2)EOF不是只能用于文本文件,要看定义的变量的类型。

例程1:

下面这段程序对文本文件和二进制文件都可以:

    int c;

    while((c=fgetc(fp)) != EOF)

    {

        printf("%X/n", c); 

    }

    如果读到了FF,由于c定义为int型,所以实际上c=0x000000FF,

不等于EOF(-1=0xFFFFFFFF),因此不会误判为文件结尾。

例程2:

如果把c定义为char类型,就有可能产生混淆了。

char c;

while((c=fgetc(fp)) != EOF)

{

    printf("%X/n", c); 

}

    因为文本文件中存储的是ASCII码,而ASCII码中FF代表空值(blank),一般不使用,

所以如果读文件返回了FF,说明已经到了文本文件的结尾。但是如果是二进制文件,

其中可能会包含FF,因此不能把读到EOF作为文件结束的条件,此时只能用feof()函数。

例程3:

VC中,只有当文件位置指针(fp->_ptr)到了文件末尾,然后再发生读/写操作时,

标志位(fp->_flag)才会被置为含有_IOEOF。然后再调用feof(),才会得到文件结束的信息。

因此,如果运行如下程序:

char c;

while(!feof(fp))

{

    c = fgetc(fp);

    printf("%X/n", c); 

}

会发现多输出了一个FF,原因就是在读完最后一个字符后,fp->flag仍然没有被置为_IOEOF,

因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到

文件结尾。这样就多输出了一个-1(即FF)。

正确的写法应该是:

char c;

c = fgetc(fp);

while(!feof(fp))

{

    printf("%X/n", c); 

    c = fgetc(fp);