文件描述符
- 对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write;按照惯例,UNIX shell使用文件描述符0与进程的标准输入相结合,文件描述符1与标准输出相结合,文件描述符2与标准错误相结合。STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO这几个宏代替了0,1,2这几个数。
- 文件描述符,这几个数字在一个进程中表示一个特定的含义,当open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字和内存中维护的这个动态文件的这些数据结构绑定上了,之后应用程序如果要操作这个动态文件,只需要用这个文件描述符区分。
- 文件描述符的作用域就是当前进程,出了这个进程文件描述符就没意义了。
Linux系统默认文件描述符:0(标准输入),1(标准输出),2(标准错误)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
char readBuf[128];
int n_read = read(0, readBuf, 5);//标准输入
int n_write = write(1, readBuf, strlen(readBuf));//标准输出
printf("\ndone!\n");
return 0;
}
一些注意:
- 在Linux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写或其他操作,一定要注意最后close关闭文件(否则可能会造成文件损坏)。
- 文件平时是存放在块设备中的文件系统文件中,此文件称为静态文件,当open打开一个文件时,Linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核中特定地址管理存放(称为动态文件)。
- 打开文件以后,对此文件的读写操作都是针对内存中的这一份动态文件而不是静态文件。对动态文件进行读写以后,此时内存中动态文件和块设备文件中的静态文件就不同步了,当close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件。
- 不对块设备直接操作是因为块设备读写不灵活,是按块读写的,而内存是按字节操作的,可以随机操作。
通过代码实现linux cp命令的代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int fdSrc;
int fdDes;
char *readBuf = NULL;
if(argc != 3)
{
printf("error\n");
exit(-1);
}
fdSrc = open(argv[1], O_RDWR);
int size = lseek(fdSrc, 0, SEEK_END);//计算字节长度
lseek(fdSrc, 0, SEEK_SET);
readBuf = (char *)malloc(sizeof(char)*size + 8);
int n_read = read(fdSrc, readBuf, size);
fdDes = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0600);//文件不存在创建文件,并且将原本存在的文件删除
int n_write = write(fdDes, readBuf, size);
close(fdSrc);
close(fdDes);
return 0;
}
修改程序的配置文件
/*
SPEED=3 SPEED=3
LENG=3 --> LENG=5
SCORE=9 SCORE=9
LEVEL=5 LEVEL=5
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int fdSrc;
char *readBuf = NULL;
if(argc != 2)
{
printf("error\n");
exit(-1);
}
fdSrc = open(argv[1], O_RDWR);
int size = lseek(fdSrc, 0, SEEK_END);
lseek(fdSrc, 0, SEEK_SET);
readBuf = (char *)malloc(sizeof(char)*size + 8);
int n_read = read(fdSrc, readBuf, size);
char *p = strstr(readBuf, "LENG=");
if(p == NULL)
{
printf("no found\n");
exit(-1);
}
p = p + strlen("LENG=");
*p = '5';
lseek(fdSrc, 0, SEEK_SET);
int n_write = write(fdSrc, readBuf, size);
close(fdSrc);
return 0;
}
写一个整数到文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int fd;
int data = 100;
int data2;
fd = open("./file1", O_RDWR);
int n_write = write(fd, &data, sizeof(int));
lseek(fd, 0, SEEK_SET);
int n_read = read(fd, &data2, sizeof(int));
printf("read %d\n", data2);
close(fd);
return 0;
}
写一个结构体到文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
struct Test
{
int a;
char b;
};
int main(int argc, char **argv)
{
int fd;
struct Test data1[2] = {{100, 'a'}, {200, 'b'}};
struct Test data2[2];
fd = open("./file1", O_RDWR);
int n_write = write(fd, &data1, sizeof(struct Test)*2);
lseek(fd, 0, SEEK_SET);
int n_read = read(fd, &data2, sizeof(struct Test)*2);
printf("read %d, %c\n", data2[0].a, data2[0].b);
printf("read %d, %c\n", data2[1].a, data2[1].b);
close(fd);
return 0;
}
//写入一个链表时要遍历链表
*关于open…与fopen…区别
- open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符,是文件在文件描述符表里的索引;fopen是ANSIC标准中的C语言库,返回的是一个指向文件结构的指针。
- fopen是C语言标准函数有良好的移植性;open是UNIX系统调用,移植性有限,实现windows下相似功能使用API函数‘CreatFile’。
- 进程间通信用的管道用open等,fopen操纵普通文件;open属于低级IO函数,fopen属于高级IO函数。
- open无缓冲,fopen有缓冲,open与read,write等配合使用,fopen与fread,fwrite等配合使用。
标准c库打开创建文件读写文件光标移动
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fd;
char *buf = "you are beautiful";
char readBuf[128] = {0};
fd = fopen("./you.txt", "w+");
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
fwrite(buf, sizeof(char), strlen(buf), fd);//fwrite(buf, sizeof(char)*strlen(buf), 1, fd);
fseek(fd, 0, SEEK_SET);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread(readBuf, sizeof(char), strlen(buf), fd);//fread(readBuf, sizeof(char)*strlen(buf), 1, fd);
printf("read:%s\n", readBuf);
fclose(fd);
return 0;
}
//fread,fwrite返回值与strlen(buf)有关,不是绝对
标准c库写入结构体到文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
struct Test
{
int a;
char b;
};
int main(int argc, char **argv)
{
FILE* fd;
struct Test data1[2] = {{100, 'a'}, {200, 'b'}};
struct Test data2[2];
fd = fopen("./file1", "w+");
int n_write = fwrite(&data1, sizeof(struct Test), 2, fd);
fseek(fd, 0, SEEK_SET);
int n_read = fread(&data2, sizeof(struct Test), 2, fd);
printf("read %d, %c\n", data2[0].a, data2[0].b);
printf("read %d, %c\n", data2[1].a, data2[1].b);
fclose(fd);
return 0;
}
fputc,fgetc,feof的使用
//fputc写入文件一个字符
#include <stdio.h>
int main()
{
FILE *fd;
char a = 'a';
fd = fopen("./test.txt", "w+");
fputc(a, fd);
fclose(fd);
return 0;
}
//fputc写入文件字符串
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fd;
int i;
char *a = "you are beautiful";
fd = fopen("./test.txt", "w+");
int len = strlen(a);
for(i = 0; i < len; i++)
{
fputc(*a, fd);
a++;
}
fclose(fd);
return 0;
}
//fgetc, feof
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fd;
char c;
fd = fopen("./test.txt", "r");
while(!feof(fd))//feof文件结束标识符,未结束返回0,结束为非零
{
c = fgetc(fd);
printf("%c", c);
}
printf("\n");
fclose(fd);
return 0;
}