本文共 12896 字,大约阅读时间需要 42 分钟。
r Open text file for reading. The stream is positioned at the beginning of the file. 只读方式打开,文件指针指向文件的首位置
r+ Open for reading and writing. The stream is positioned at the beginning of the file. 读写方式打开,文件指针指向文件的首位置
w Truncate(缩短) file to zero length or create text file for writing. The stream is positioned at the beginning of the file. 只写方式打开,清空文件内容,如果文件不存在则创建文件,文件指针指向文件的首位置
w+ Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file. 读写方式打开,文件不存在则创建文件,如果文件存在则清空原来内容,文件指针指向文章的首位置
a Open for appending (writing at end of file). The file is created if it does not exist. The stream is positioned at the end of the file.
以追加写的方式打开,写到文件的结尾处,文件不存在则创建文件,文件指针指向文件的末尾位置
a+ Open for reading and appending (writing at end of file). The file is created if it does not exist. The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.
以读和追加写的方式打开,文件不存在则创建文件,如果文件存在则从文件的末尾位置开始追加
1 #include2 #include 3 #include 4 int main() 5 { 6 FILE* fp=fopen("test.txt","w+"); 7 if(fp==NULL) 8 { 9 printf("文件打开失败!\n"); 10 exit(1); 11 } 12 fwrite("bit person!",sizeof(char),11,fp); 13 fseek(fp,0,SEEK_CUR); 14 char arr[100]; 15 fread(arr,sizeof(char),strlen(arr),fp); printf("%s\n",arr); 16 fclose(fp); 17 return 0; 18 }
1 #include2 #include 3 #include 4 int main() 5 { 6 FILE* fp=fopen("test.txt","a+"); 7 if(fp==NULL) 8 { 9 printf("打开文件失败!\n"); 10 exit(1); 11 } 12 char *arr="bit education!\n"; 13 fwrite(arr,sizeof(char),strlen(arr),fp); 14 fclose(fp); 15 return 0; 16 }
fwrite(msg,strlen(msg),sizeof(char),fp);//往log.txt文件里面写
1 #include2 #include 3 int main() 4 { 5 FILE *fp=fopen("log.txt","w"); 6 if(NULL==fp) 7 { 8 printf("打开文件失败!\n"); 9 } 10 else 11 { 12 /* char c='A'; 13 for(;c<'Z';c++) 14 { 15 fputc(c,fp); 16 }*/ 17 const char* msg="Hello bit!\n"; 18 // fwrite(msg,strlen(msg),sizeof(char),fp);//往log.txt文件里面写 19 fwrite(msg,strlen(msg),sizeof(char),stdout);//输出,往显示屏上输出 20 21 } 22 fclose(fp); 23 return 0; 24 }
fwrite(msg,strlen(msg),sizeof(char),stdout);//输出,往显示屏上输出
操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问,先来直接以代码的形式,实现和上面一模一样的代码:
写文件
1 #include读文件2 #include 3 #include 4 #include 5 #include 6 #include 7 int main() 8 { 9 int fd=open("myfile",O_WRONLY|O_CREAT,0644); 10 if(fd<0) 11 { 12 printf("文件打开失败!\n"); 13 exit(1); 14 } 15 char* arr="bit education!"; 16 write(fd,arr,strlen(arr)-1); 17 close(fd); 18 return 0; 19 }
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 int main() 8 { 9 int fd=open("myfile.txt",O_RDONLY); 10 if(fd<0) 11 { 12 printf("文件打开失败!\n"); 13 exit(1); 14 } 15 char* arr="hello bit!"; 16 char buff[100]; 17 read(fd,buff,strlen(arr)-1); 18 printf("%s\n",buff); 19 close(fd); 20 return 0; 21 }
open man open
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); pathname: 要打开或创建的目标文件 flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。 参数: O_RDONLY: 只读打开 O_WRONLY: 只写打开 O_RDWR : 读,写打开 这三个常量,必须指定一个且只能指定一个 O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限 O_APPEND: 追加写 返回值: 成功:新打开的文件描述符 失败:-1
mode_t理解:直接 man 手册,比什么都清楚。
open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。1 #include而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。2 #include 3 #include 4 #include 5 #include 6 int main() 7 { 8 char buff[100]; 9 int fd=read(0,buff,sizeof(buff)); 10 write(1,buff,strlen(buff)-1); 11 write(2,buff,strlen(buff)-1); 12 return 0; 13 }
输出发现fd是3:
1 #include关闭0或者2,在看:2 #include 3 #include 4 #include 5 #include 6 int main() 7 { 8 int fd=open("myfile",O_RDONLY|O_CREAT); 9 if(fd<0) 10 { 11 std::cout<<"文件打开失败!"<
1 #include发现是结果是: fd: 0 或者 fd 2 可见,文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。 ----------------------最小未分配原则----------------------2 #include 3 #include 4 #include 5 #include 6 int main() 7 { 8 close(0); 9 // close(2); 10 int fd=open("myfile",O_RDONLY|O_CREAT,0664); 11 if(fd<0) 12 { 13 std::cout<<"文件打开失败!"<
我们发现第一次写的hello world被第二次写的你好呀覆盖了,这就是清空重定向。
我们发现第一次写的hello没有被第二次写的你覆盖,而是追加在hello后面,这就是追加重定向。
那如果关闭1呢?看代码:
1 #include此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这种现象叫做输出重定向。常见的重定向有:>, >>, <2 #include 3 #include 4 #include 5 #include 6 #include 7 int main() 8 { 9 close(1); 10 int fd=open("myfile",O_WRONLY|O_CREAT,0644); 11 if(fd<0) 12 { 13 std::cout<<"文件打开失败!"<
来段代码在研究一下:
1 #include但如果对进程实现输出重定向呢? ./hello > file , 我们发现结果变成了:2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 int main() 9 { 10 int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0644); 11 if(fd<0) 12 { 13 std::cout<<"文件打开失败!"<
综上: printf、fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区,都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不再我们讨论范围之内。那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统调用的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,足以说明,该缓冲区是二次加上的,又因为是C,所以由C标准库提供。
如果有兴趣,可以看看FILE结构体:
typedef struct _IO_FILE FILE; 在/usr/include/stdio.h
在/usr/include/libio.h struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. / #define _IO_file_flags _flags //缓冲区相关 / The following pointers correspond to the C++ streambuf protocol. / / Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. / char _IO_read_ptr; /* Current read pointer / char _IO_read_end; /* End of get area. / char _IO_read_base; /* Start of putback+get area. / char _IO_write_base; /* Start of put area. / char _IO_write_ptr; /* Current put pointer. / char _IO_write_end; /* End of put area. / char _IO_buf_base; /* Start of reserve area. / char _IO_buf_end; /* End of reserve area. / / The following fields are used to support backing up and undo. */ char _IO_save_base; / Pointer to start of non-current get area. */ char _IO_backup_base; / Pointer to first valid character of backup area */ char _IO_save_end; / Pointer to end of non-current get area. / struct _IO_marker _markers; struct _IO_FILE _chain; int _fileno; //封装的文件描述符 #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; / This used to be _offset but it’s too small. / #define __HAVE_COLUMN / temporary / / 1+column number of pbase(); 0 is unknown. / unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1]; / char _save_gptr; char _save_egptr; */ _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE };
#include <unistd.h> int dup2(int oldfd, int newfd);
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 int main() 9 { 10 int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0644); 11 if(fd<0) 12 { 13 std::cout<<"文件打开失败!"<
我们使用ls -l的时候看到的除了看到文件名,还看到了文件元数据。
ls -l读取存储在磁盘上的文件信息,然后显示出来 其实这个信息除了通过这种方式来读取,还有一个stat命令能够看到更多信息 上面的执行结果有几个信息需要解释清楚:
inode: 为了能解释清楚inode我们先简单了解一下文件系统:
将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们通过touch一个新文件来看看如何工作。
[root@localhost linux]# touch abc [root@localhost linux]# ls -i abc 263466 abc
新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。
我们看到,真正找到磁盘上文件的并不是文件名,而是inode。 其实在linux中可以让多个文件名对应于同一个inode。
动态链接生成的可执行程序比静态链接生成的可执行程序小的原因?
#ifndef __MYLIB_H__#define __MYLIB_H__ #includevoid print();#endif
写出mylib.c代码:
#include"mylib.h"void print(){ printf("Hello Linux!\n");}
写出main.c代码:
#include"mylib.h"int main(){ print(); return 0;}
生成静态库第一步,先生成目标文件: gcc -c mylib.c -o mylib.o 第二步,用目标文件生成静态库:ar -rc libmylib.a mylib.o ar是gnu归档工具,rc表示(replace and create) 可以查看静态库中的目录列表: t:列出静态库中的文件 v:verbose 详细信息 第三步运行main.c得到结果。 gcc main.c -L. -lmylib -L 指定库路径 -l 指定库名 测试目标文件生成后,静态库删掉,程序照样可以运行。
#ifndef __MYLIB_H__#define __MYLIB_H__ #includevoid print();#endif
写出mylib.c代码:
#include"mylib.h"void print(){ printf("Hello Linux!\n");}
写出main.c代码:
#include"mylib.h"int main(){ print(); return 0;}
生成动态库第一步,先生成目标文件: ** gcc -fPIC -c mylib.c**
第二步,用目标文件生成动态库:gcc -shared -o libmylib.so *.o
第三步运行main.c得到结果。 gcc main.c -o main -L. -lmylib
以上就是今天要讲的内容,本文仅仅简单介绍了进场基础IO的使用,而系统编程提供了大量能使我们快速便捷地处理数据的函数和方法,我们务必掌握。到这里,进程IO就结束了,后序将会有更重要的文章陆续更新,希望大家多多支持!另外如果上述有任何问题,请懂哥指教,不过没关系,主要是自己能坚持,更希望有一起学习的同学可以帮我指正,但是如果可以请温柔一点跟我讲,爱与和平是永远的主题,爱各位了。
转载地址:http://culzi.baihongyu.com/