Linux文件基本操作
Linux 的设计哲学
在 Linux 中,一切皆文件!
什么是文件?
文件是具有永久存储性,按特定字节顺序组成的命名数据集
文件可分为:文本文件,二进制文件
文本文件:每个文件存放一个 ASCII 码
- 存储量大,速度慢,便于对字符操作
二进制文件:数据按照在内存中的存储形式原样存放
- 存储量小,速度快,便于存放中间结果
Linux 文件编程
在 Linux 中,除了常规文件,目录,设备,管道等,也属于文件
ASCII C 文件编程
标准 C 文件接口建立于 Linux 原生文件接口之上,使用缓冲区机制提高效率
缓冲区是一片特殊的内存空间,用于暂存文件中的数据
- 读:一次性将大量的数据读入缓冲区 (后续再从缓冲区中拿数据)
- 写:可先把数据写入输入缓冲区 (缓冲区满之后再把数据一次性写入文件)
- 缓冲区的引入是为了避免频繁的磁盘操作,提高文件读写的整体效率
深入 ASCII C 文件编程
由于引入了缓冲区,ASCII C 文件编程是一种基于数据流的编程
ASCII C 文件编程接口
ASCII C 文件打开模式
文本文件写示例
ASCII C 文件 "读写移动指针"
int fseek(FILE* stream, long offset, int whence);
- 移动文件读写指针,whence => SEEK_SET,SEEK_END,SEEK_CUR
long ftell(FILE* stream);
- 获取当前读写指针的位置 (对于文件起始位置)
void rewind(FILE* stream);
- 将读写指针置于文件起始位置,(void)fseek(stream, 0L, SEEK_SET)
二进制文件读写示例
ASCII C 文件编程初体验
test1.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
int main()
{
FILE* fp = NULL;
char student[50] = {0};
int i = 0;
if( (fp = fopen("input.txt", "w")) == NULL )
{
perror("open file error...\n");
exit(1);
}
for(i=0; i<3; i++)
{
printf("input name:");
scanf("%s", student);
fputs(student, fp);
fputs("\n", fp);
}
fclose(fp);
return 0;
}
第 13 行,我们以写的方式打开一个文本文件
第 23 行,通过 fputs(...) 将字符串写入到文本文件中
程序运行结果如下图所示:
test2.c
#include <stdio.h>
#include <stdlib.h>
#define N 3
struct student
{
long num;
char name[16];
int age;
};
int main()
{
int i = 0;
struct student s = {0};
FILE* fp = NULL;
if( (fp = fopen("student.dat", "wb+")) == NULL )
{
perror("open file error...\n");
exit(1);
}
for(i=0; i<N; i++)
{
printf("Number: %d\n", i + 1);
printf("ID:");
scanf("%ld", &s.num);
printf("Name:");
scanf("%s", s.name);
printf("Age:");
scanf("%d", &s.age);
printf("\n");
fwrite(&s, sizeof(s), 1, fp);
}
rewind(fp);
for(i=0; i<N; i++)
{
fread(&s, sizeof(s), 1, fp);
printf("%ld %s %d\n", s.num, s.name, s.age);
}
fclose(fp);
return 0;
}
第 19 行,我们以写入并新建文件的方式打开一个二进制文件
第 25 - 37 行,我们通过 scanf 来填充结构体的内容,并通过 fwrite 写入到二进制文件中
由于文件读写指针会在我们进行文件写入操作后,偏移位置在文件的末尾,所以在接下来我们需要读取文件内容的时候,可以使用 rewind(...) 函数,将文件读写指针偏移到文件的起始位置处,再进行读取
程序运行结果如下图所示:
ASCII 文件缓冲区类型
全缓冲区:默认缓冲器大小为 BUFSIZ,具体大小与系统相关
- 缓冲区满 或 调用 fflush() 才通过系统调用将数据写入磁盘 (设备)
行缓冲区:默认缓冲区大小为 128 字节,具体大小与系统有关
- 遇见 换行符 或 缓冲区满 或 调用 fflush() 后通过系统调用将数据写入磁盘 (设备)
无缓冲区:不对数据进行缓冲
- 相当于直接使用系统调用 write(),数据立即写入磁盘 (设备)
自定义文件缓冲区
缓冲区代码示例
文件缓冲区编程实验
test3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
int main()
{
FILE* fp = NULL;
char buf[128] = {0};
char* ps = "Delphi\nTang";
if( (fp = fopen("input.txt", "w")) == NULL )
{
perror("open file error...\n");
exit(1);
}
setvbuf(fp, buf, _IOLBF, sizeof(buf));
fwrite(ps, sizeof(*ps), strlen(ps), fp);
printf("ps = %s\n", buf);
fclose(fp);
return 0;
}
第 19 行,我们通过 setvbuf(...) 函数将 input.txt 这个文件的缓冲类型设置为行缓冲,缓冲区为我们定义的 buf,缓冲区大小为 128 字节
第 21 行,我们通过 fwrite(...) 将字符串写入到文件中,由于我们设置了行缓冲,数据会先写入到缓冲区中,当遇到换行符后,会将缓冲区的 "Delphi" 字符串写入到文件中,字符串 "Tang" 还暂存在缓冲区中
第 25 行,我们调用了 fclose(...),把缓冲区中的字符串 "Tang" 也写入到文件中
程序运行结果如下图所示:
缓冲区的内容为 "Tanghi",是因为 "hi" 为脏数据,是将 "Delphi" 写入到缓冲区时保留下来的
test4.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct student
{
long num;
char name[16];
int age;
};
int main(int argc, char* argv[])
{
FILE* fp = NULL;
char buf[BUFSIZ] = {0};
struct student s = {999, "tang", 888};
struct student* ps = NULL;
if( (fp = fopen("input.txt", "w")) == NULL )
{
printf("open file error: %d...\n", __LINE__);
exit(1);
}
printf("BUFSIZ = %d\n", BUFSIZ);
setvbuf(fp, buf, _IOFBF, sizeof(buf));
fwrite(&s, sizeof(s), 1, fp);
fclose(fp);
ps = (void*)buf;
printf("num = %ld, name = %s, age = %d\n", ps->num, ps->name, ps->age);
/
if( (fp = fopen("input.txt", "r")) == NULL )
{
printf("open file error: %d...\n", __LINE__);
exit(2);
}
setvbuf(fp, buf, _IOFBF, sizeof(buf));
memset(&s, 0, sizeof(s));
memset(buf, 0, sizeof(buf));
fread(&s, sizeof(s), 1, fp);
printf("num = %ld, name = %s, age = %d\n", s.num, s.name, s.age);
fclose(fp);
ps = (void*)buf;
printf("num = %ld, name = %s, age = %d\n", ps->num, ps->name, ps->age);
return 0;
}
第 31 行,打印系统预定义的文件默认缓冲区大小的宏
第 33 行,设置文件缓冲区为全缓冲
第 35 行,我们将结构体 s 的内容写入到文件中,由于设置的是全缓冲,写入的结构体大小没有超过缓冲区大小,所以会先将数据暂存在缓冲区 buf 中
第 37 行,关闭文件,会将缓冲区暂存的数据写入到文件中去
程序运行结果如下图所示: