基于文件指针的文件操作

核能气质少年 提交于 2020-01-10 00:26:12

基于文件指针的文件操作(缓冲)

linux的文件和文件描述符

linux中对目录和设备的操作都是文件操作,文件分为普通文件,目录文件,链接文件和设备文件

普通文件:也称磁盘文件,并且能够进行随机的数据存储(能够自由seek定位到某一个位置)

管道:是一个从一端发送数据,另一端接收数据的数据通道;

目录:也称为目录文件,它包含了保存在目录中文件列表的简单文件。

设备:该类型的文件提供了大多数物理设备的接口。它又分为两种类型:字符型设备和块设备。

字符型设备一次只能读出和写入一个字节的数据,包括调制解调器、终端、打印机、声卡以及鼠标;

块设备必须以一定大小的块来读出或者写入数据,块设备包括CD-ROMRAM驱动器和磁盘驱动器等,一般而言,字符设备用于传输数据,块设备用于存储数据。

 链接:类似于Windows的快捷方式和Linux里的别名,指包含到达另一个文件路径的文件。

套接字:Linux,套接字也可以当作文件来进行处理。

基于文件指针的文件操作函数是ANSI标准函数库的一部分。

1文件的创建,打开与关闭

原型为:

#include <stdio.h>  //头文件包含

FILE *fopen(const char *pach,const char *mode);  //文件名  模式

int fclose(FILE *stream);

fopen以mode的方式打开或创建文件,如果成功,将返回一个文件指针,失败则返回NULL.

fopen创建的文件的访问权限将以0666与当前的umask结合来确定。 

mode的可选模式列表

模式

位置

截断原内容

创建

rb

Y

N

文件头

N

N

r+b

Y

Y

文件头

N

N

wb

N

Y

文件头

Y

Y

w+b

Y

Y

文件头

Y

Y

ab

N

Y

文件尾

N

Y

a+b

Y

Y

文件尾

N

Y

在Linux系统中,mode里面的’b’(二进制)可以去掉,但是为了保持与其他系统的兼容性,建议不要去掉。aba+b为追加模式,在此两种模式下,无论文件读写点定位到何处,在写数据时都将是在文件末尾添加,所以比较适合于多进程写同一个文件的情况下保证数据的完整性。

2 读写文件

基于文件指针的数据读写函数较多,可分为如下几组:

数据块读写:

#include <stdio.h>

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

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

fread从文件流stream 中读取nmemb个元素,写到ptr指向的内存中,每个元素的大小为size个字节。

fwrite从ptr指向的内存中读取nmemb个元素,写到文件流stream中,每个元素size个字节。

所有的文件读写函数都从文件的当前读写点开始读写,读写完以后,当前读写点自动往后移动size*nmemb个字节。

格式化读写:

#include <stdio.h>

int printf(const char *format, ...);                   //相当于 fprintf(stdout,format,…);

int scanf(const char *format, …);

 

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

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

 

int sprintf(char *str, const char *format, ...);          // eg:   sprintf(buf,”the string is;%s”,str);

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

f开头的将格式化后的字符串写入到文件流stream中 

s开头的将格式化后的字符串写入到字符串str

单个字符读写:

使用下列函数可以一次读写一个字符

#include <stdio.h>

int fgetc(FILE *stream);

int fputc(int c, FILE *stream);

 

int getc(FILE *stream);    //等同于 fgetc(FILE* stream)

int putc(int c, FILE *stream);   // 等同于 fputc(int c, FILE* stream)

 

int getchar(void);    //等同于 fgetc(stdin);

int putchar(int c);    // 等同于 fputc(int c, stdout);

getcharputchar从标准输入输出流中读写数据,其他函数从文件流stream中读写数据

字符串读写:

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

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

int puts(const char *s);// 等同于 fputs(const char *s, int size, stdout);

char *gets(char *s);     // 等同于 fgets(const char *s, int size,stdin);

fgetsfputs从文件流stream中读写一行数据;

putsgets标准输入输出流中读写一行数据。

fgets可以指定目标缓冲区的大小,所以相对于gets安全,但是fgets调用时,如果文件中当前行的字符个数大于size,则下一次fgets调用时,将继续读取该行剩下的字符,fgets读取一行字符时,保留行尾的换行符

fputs不会在行尾自动添加换行符,但是puts会在标准输出流中自动添加一换行符

 

文件定位:

文件定位指读取或设置文件当前读写点,所有的通过文件指针读写数据的函数,都是从文件的当前读写点读写数据的。

常用的函数有:

#include <stdio.h>

int feof(FILE * stream);   //通常的用法为while(!feof(fp))

int fseek(FILE *stream, long offset, int whence);//设置当前读写点到偏移whence 长度为offset

long ftell(FILE *stream); //用来获得文件流当前的读写位置

void rewind(FILE *stream); //把文件流的读写位置移至文件开头 fseek(fp, 0, SEEK_SET);

feof判断是否到达文件末尾的下一个(注意到达文件末尾之后还会做一次)

fseek设置当前读写点到偏移whence 长度为offset处,whence可以是:

SEEK_SET (文件开头  ->0)

SEEK_CUR (文件当前位置  ->1)

SEEK_END (文件末尾  ->2)

ftell获取当前的读写点

rewind将文件当前读写点移动到文件头

 

注:基于文件指针的文件操作请参考《C语言文件操作常用函数详解.doc

3目录操作

改变目录或文件的访问权限

#include <sys/stat.h>

int chmod(const char* path, mode_t mode); //mode形如:0777

path参数指定的文件被修改为具有mode参数给出的访问权限。

 

获取、改变当前目录:

原型为:

#include <unistd.h>   //头文件

char *getcwd(char *buf, size_t size); //获取当前目录,相当于pwd命令

int chdir(const char *path); //修改当前目录,即切换目录,相当于cd命令

 

其中getcwd()函数:将当前的工作目录绝对路径复制到参数buf所指的内存空间,参数size为buf的空间大小. 在调用此函数时,buf所指的内存空间要足够大,若工作目录绝对路径的字符串长度超过参数size大小,则回值NULL,errno的值则为ERANGE。

倘若参数buf为NULL,getcwd()会依参数size的大小自动配置内存(使用malloc()),如果参数size也为0,则getcwd()会依工作目录绝对路径的字符串程度来决定所配置的内存大小,进程可以在使用完此字符串后自动利用free()来释放此空间。所以常用的形式:getcwd(NULL, 0);

chdir()函数:用来将当前的工作目录改变成以参数path所指的目录

Example:

1 #include<unistd.h>
2 int main()
3 {
4 
5   chdir(“/tmp”);
6   printf(“current working directory: %s\n”,getcwd(NULL,0));
7       return 0;
8 
9 }
View Code

创建和删除目录:

原型为:

#include <sys/stat.h>

#include <sys/types.h>

#include <unistd.h>

int mkdir(const char *pathname, mode_t mode); //创建目录,mode是目录权限,没用

int rmdir(const char *pathname); //删除目录

 

获取目录信息:

原型为:

#include <sys/types.h>

#include <dirent.h>

DIR *opendir(const char *name); //打开一个目录,返回一个目录流

struct dirent *readdir(DIR *dir); //读取目录的一项信息,并返回该项信息的结构体指针

void rewinddir(DIR *dir); //重新定位到目录文件的头部

void seekdir(DIR *dir,off_t offset);//用来设置目录流目前的读取位置

off_t telldir(DIR *dir); //返回目录流当前的读取位置

int closedir(DIR *dir); //关闭目录文件

 

读取目录信息的步骤为:

1 用opendir函数打开目录;

2使用readdir函数迭代读取目录的内容,如果已经读取到目录末尾,又想重新开始读,则可以使用rewinddir函数将文件指针重新定位到目录文件的起始位置;

3 用closedir函数关闭目录

opendir()用来打开参数name指定的目录,并返回DIR*形态的目录流,和文件操作函数open()类似,接下来对目录的读取和搜索都要使用此返回值。函数失败则返回NULL;

readdir()函数用来读取目录的信息,并返回一个结构体指针,该指针保存了目录的相关信息。有错误发生或者读取到目录文件尾则返回NULL;dirent结构体如下:

struct dirent

{

  ino_t  d_ino;           /* inode number(此目录进入点的inode) */

  off_t  d_off;             /* offset to the next dirent(目录开头到进入点的位移 */

  unsigned short d_reclen;  /* length of this record(目录名的长度) */

  unsigned char d_type;     /* type of file(所指的文件类型) */

  char   d_name[256];       /* filename(文件名) */

};

seekdir()函数用来设置目录流目前的读取位置,再调用readdir()函数时,便可以从此新位置开始读取。

参数offset代表距离目录文件开头的偏移量。

telldir()函数用来返回目录流当前的读取位置。

示例:返回指定目录下的文件

 1 #include <stdio.h>
 2 
 3 #include <sys/types.h>
 4 
 5 #include <dirent.h>
 6 
 7  
 8 
 9 int main(int argc,char *argv[])
10 
11 {
12 
13     struct dirent *pDirInfo;
14 
15     DIR *pDir;
16 
17     if(argc < 2)
18 
19         pDir = opendir(".");
20 
21     else
22 
23         pDir = opendir(argv[1]);
24 
25 if(NULL == pDir)
26 
27 {
28 
29         perror("open dir fail!");
30 
31         return -1;
32 
33     }
34 
35     while( (pDirInfo = readdir(pDir)) != NULL )
36 
37         printf("%s\n",pDirInfo->d_name);
38 
39       closedir(pDir);
40 
41         return 0;
42 
43 }
View Code

Example:以树形结构的形式输出指定目录下面的所有文件

 1 #include <unistd.h>
 2 
 3 #include <stdio.h>
 4 
 5 #include <dirent.h>
 6 
 7 #include <string.h>
 8 
 9 #include <sys/stat.h>
10 
11 #include <stdlib.h>
12 
13 void printdir(char *dir, int depth)//depth为缩进空格数
14 
15 {
16 
17     DIR *dp = opendir(dir);
18 
19    if(NULL == dp) 
20 
21    {
22 
23         fprintf(stderr,"cannot open directory: %s\n", dir);
24 
25         return;
26 
27     }
28 
29   chdir(dir);
30 
31     struct dirent *entry;
32 
33     struct stat statbuf;
34 
35 while((entry = readdir(dp)) != NULL) 
36 
37 {
38 
39         stat(entry->d_name,&statbuf);
40 
41         if(S_ISDIR(statbuf.st_mode)) //是目录
42 
43 {
44 
45             if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
46 
47                 continue; 
48 
49             printf("%*s%s/\n",depth,"",entry->d_name);
50 
51             printdir(entry->d_name,depth+4);//递归
52 
53         }
54 
55         else //是文件
56 
57     printf("%*s%s\n",depth,"",entry->d_name);
58 
59     //printf(“%*s”,4,”*”); 该函数表示输出“___*”,前面输出3个空格。
60 
61     //如果是printf(“%*s”,4,“**”);则表示输出“__**”,前面输出2个空格。
62 
63     }
64 
65     chdir("..");
66 
67     closedir(dp);
68 
69 }
70 
71  
72 
73 int main(int argc, char* argv[])
74 
75 {
76 
77     char *topdir, pwd[2]=".";
78 
79     if (argc < 2)
80 
81         topdir=pwd;
82 
83     else
84 
85         topdir=argv[1];
86 
87     printf("Directory scan of %s\n",topdir);
88 
89     printdir(topdir,0);
90 
91     printf("done.\n");
92 
93     exit(0);
94 
95 }
View Code

4标准输入/输出流

在进程一开始运行,就自动打开了三个对应设备的文件,它们是标准输入、输出、错误流,分别用全局文件指针stdin、stdout、stderr表示,stdin具有可读属性,缺省情况下是指从键盘的读取输入,stdout和stderr具有可写属性,缺省情况下是指向屏幕输出数据。

示例:

 

 1 #include <stdio.h>
 2 
 3 #include <unistd.h>
 4 
 5 int main()
 6 
 7 {
 8 
 9     char szBuf[32];
10 
11     printf("Input string:");     //向屏幕输出一字符串
12 
13     fgets(szBuf,sizeof(szBuf),stdin);//从键盘读入一行字符串
14 
15     fprintf(stdout,"The string is:%s",szBuf);//向屏幕输出一行字符串
16 
17     return 0;
18 
19 }
View Code

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!