Linux 的文件既可以是真实保存到存储介质的文件,也可以是自身内核提供的虚拟文件,还可以是设备节点。
内核提供的虚拟文件系统在/sys目录下
int open(const char *pathname, int flags);
int open(const char *pathname, int flags,mode_t mode);
返回值:
参数说明:
对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件 描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。
按照惯例,UNIX shell使用文件描述符0与进程的标准输入相结合,文件描述符1与标准输出相结合,文件描述符2与标准错误输出相结合。STDIN_FILENO、STDOUT _FILENO、STDERR_FILENO这几个宏代替了0、1、这几个魔数。
文件描述符,这个数字在一个进程中表示一个特定含义,当我们open—个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回 给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护的这个动态文件的这些数据结构绑定上了,以后我们应用程序如果要操作这个动态文件,只需要用这个文件描述符区分。
文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了。
int n_read = read(0,buf,10);
int n_write=write(1,buf,sizeof(buf));
int close(int fd);
写入成功后要关闭文件,此时光标就在文件头
ssize_twrite (int fd,const void * buf, size_t count);
函数说明:write() 会把参数 buf 所指的内存写入 count 个字节到参数 fd 所指的文件内。
返回值:
参数说明:
ssize_tread(int fd,void * buf, size_t count);
函数说明:从打开的 fd 设备或文件中读取 count 个字节到 buf 中
返回值:
参数说明:
注意:count常用sizeof
off_t lseek(int fd, off_t offset, int whence);
函数说明:将文件读写指针相对whence移动offset个字节
返回值:成功则返回文件读写距离文件开头的字节大小,出错返回 -1
参数说明:
注:返回值是相对文件头的字节数,可以将光标定位到末尾,然后调用该函数得到该文件的字符个数
int creat (const char *filename,mode_t mode )
参数说明:
常见的创建模式:
宏表示 | 数字 | 作用 |
---|---|---|
S_IRUSR | 4 | 可读 |
S_IWUSR | 2 | 可写 |
S_IXUSR | 1 | 可执行 |
S_IRWXU | 1 | 可读可写可执行 |
ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下:
int ioctl(int fd, ind cmd, …);
mmap将文件的内容映射给应用程序,应用程序通过访问内存的形式访问,该文件可以是普通文件,也可以是设备文件
#include
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
#include
#include
#include
#include
#include
#include
/*
* ./copy 1.txt 2.txt
* argc = 3
* argv[0] = "./copy"
* argv[1] = "1.txt"
* argv[2] = "2.txt"
*/
int main(int argc, char **argv)
{
int fd_old, fd_new;
struct stat stat;
char *buf;
/* 1. 判断参数 */
if (argc != 3)
{
printf("Usage: %s \n" , argv[0]);
return -1;
}
/* 2. 打开老文件 */
fd_old = open(argv[1], O_RDONLY);
if (fd_old == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
/* 3. 确定老文件的大小 */
if (fstat(fd_old, &stat) == -1)
{
printf("can not get stat of file %s\n", argv[1]);
return -1;
}
/* 4. 映射老文件 */
buf = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd_old, 0);
if (buf == MAP_FAILED)
{
printf("can not mmap file %s\n", argv[1]);
return -1;
}
/* 5. 创建新文件 */
fd_new = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (fd_new == -1)
{
printf("can not creat file %s\n", argv[2]);
return -1;
}
/* 6. 写新文件 */
if (write(fd_new, buf, stat.st_size) != stat.st_size)
{
printf("can not write %s\n", argv[2]);
return -1;
}
/* 5. 关闭文件 */
close(fd_old);
close(fd_new);
return 0;
}
int main(int argc,char *argv[ ])
注意:在使用带参数的main函数时,第一个形参必须是int型,用来接收形参个数,第二个参数必须是字符指针数组,用来接收从操作系统命令行传来字符的地址。
cp指令使用时,首先给出cp命令,若将源文件a.c复制成目标文件b.c,因此一共有3个参数,即argc的值为3。argv里面共有三个地址,argv[0]指向cp,argv[1]指向a.c地址,argv[2]指向b.c地址。
打开被复制的源文件src.c
读取源文件src.c中的内容到读取缓冲器readBuf中
打开或者创建一个目标文件src.c,该文件是用于将复制的内容写入的地方
将读取缓冲器readBuf中的内容写入到目标文件src.c中
关闭源文件和目标文件,防止文件受损
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char **argv)
{
int fdSrc;
int fdDes;
char *readBuf=NULL;
if(argc!=3){
printf("param error\n");
exit(-1);
}
fdSrc=open(argv[1],O_RDWR);
int size=lseek(fdSrc,0,SEEK_END);
readBuf=(char *)malloc(sizeof(char)*size+8);
lseek(fdSrc,0,SEEK_SET);
int n_read=read(fdSrc,readBuf,size);
fdDes=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
int n_write=write(fdDes,readBuf,strlen(readBuf));
close(fdSrc);
close(fdDes);
return 0;
}
转自:总结open与fopen的区别
1. 来源
2. 移植性
3. 适用范围
4. 文件IO层次
5. 缓冲
缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。
非缓冲文件系统
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。
6. 总结
就是open无缓冲,fopen有缓冲。前者与read, write等配合使用, 后者与fread,fwrite等配合使用。
使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:read,write);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。
Linux 下有 3 大帮助方法:help、man、info
。
1 Executable programs or shell commands // 命令
2 System calls (functions provided by the kernel) // 系统调用,比如 man 2 open
3 Library calls (functions within program libraries) // 函数库调用
4 Special files (usually found in /dev) // 特殊文件, 比如 man 4 tty
5 File formats and conventions eg /etc/passwd // 文件格式和约定, 比如 man 5 passwd
6 Games // 游戏
7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) // 杂项
8 System administration commands (usually only for root) // 系统管理命令
9 Kernel routines [Non standard] // 内核例程
例如查看 open 函数的用法
执行:man 2 open
在 man 命令中可以及时按“h”查看帮助信息了解快捷键。常用的快捷键是:
f 往前翻一页
b 往后翻一页
q 退出
/patten 往前搜
?patten 往后搜