fopen
fopen
新建的文件,如果是相对路径,在进程的工作路径下创建-w
:清空写入a
:追加fwrite
、fread
、rewind
、fclose
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 int main() {
5 FILE* f = fopen("bite.txt", "w+");
6 const char* msg = "linux so easy\n";
7 fwrite(msg, strlen(msg), 1, f);
8
9 rewind(f); //重置偏移量!!!
10 char buffer[strlen(msg)];
11 fread(buffer, 1, strlen(msg), f);
12 printf("%s\n", buffer);
13 fclose(f);
14 }
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);
flags
mode
file descriptor
当调用write
时,将fd
传递给进程,进程根据files
指针找到文件描述符表,然后由对应下标(fd
)找到打开的文件file
FILE
是C语言自己封装的结构体,里面一定含由文件描述符cout << stdin->_fileno << endl; //0
cout << stdout->_fileno << endl; //1
cout << stderr->_fileno << endl; //2
#include <unistd.h>
ssize_t write(int fd, const void* buf, size_t count);
strlen(messsage)
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
struct file
操作系统维护一个被打开文件的信息:struct file
, 包含:
struct file* next
指针,将不同文件链接起来task_struct
中含有一个stuct files_struct *files
记录自己打开文件的信息,stuct files_struct *file
里包含一个struct file *fd_array[]
指针数组,存放文件指针(所以open时,会选择一个空的fd_array
位置的下标返回)struct file *fd_array[]
文件描述符表,数组加标0、1、2分别指向三个默认打开的文件:stdin(键盘文件)
、stdout(显示器文件)
、stderr(显示器文件)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7
8 int main() {
9 const char* msg = "hello\n";
10 write(1, msg, strlen(msg)); //想显示器写入
11
12 char buffer[1024];
13 ssize_t s = read(0, buffer, sizeof(buffer)); //向键盘读数据
14 buffer[s] = '\0';
15 printf("echo : %s\n", buffer);
16 return 0;
17 }
从0下标开始,寻找最小没有使用的数组位置
int main() {
close(1);
int fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC, 0666);
if (fd < 0) {
perror("open");
return 1;
}
const char *msg = "hello\n";
for (int i = 0; i < 5; i++) {
//因为关闭了1,open文件之后占用1这个位置,写入从显示器重定向到了文件中
write(1, msg, strlen(msg));
}
close(fd);
}
dup2
#include <unistd.h>
int dup2(int oldfd, int newfd) //makes newfd be the copy of oldfd
重定向:将文件描述符对应下标的指针拷贝到要重定向的文件的位值的指针
fd_array[oldfd]
拷贝到fd_array[newfd]
, 拷贝之后需要close(oldfd)
;stdout
和stderr
int mian() {
fprintf(stdout, "normal msg");
fprintf(stdout, "normal msg");
fprintf(stdout, "normal msg");
fprintf(stderr, "error msg");
fprintf(stderr, "error msg");
fprintf(stderr, "error msg");
}
//gcc test.c -o test
./test > normal.log
:normal msg重定向到normal.log, error msg打印到屏幕将stdout
和stderr
都重定向到一个文件all.log
./test &>all.log
./test >&all.log
./test >all.log 2>&1
./test 2>all.log 1>all.log
C的输出接口输出到用户级缓冲区(该缓冲区不在系统中)
显示器的文件的刷新方案是行刷新,所以在printf
执行完成遇到\n
就会将数据进行刷新
缓冲区刷新策略:
fprintf/fwrite
等向用户级缓冲区中写入,当缓冲区刷新时调用write
系统调用接口(因此,C中fflush
函数一定封装了write
),write
向系统级缓冲区中写入
为什么要有用户级的缓冲区
用户及的缓冲区在哪里?—— 存在FILE结构体中,
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4
5 int main() {
6 const char* fstr = "hello fwrite\n";
7 const char* str = "hello write\n";
8
9 printf("hello printf, pid:%d, ppid:%d\n", getpid(), getppid());
10 fprintf(stdout, "hello fprintf, pid:%d, ppid:%d\n", getpid(), getppid());
11 fwrite(fstr, strlen(fstr), 1, stdout);
12
13 write(1, str, strlen(str));
14
15 fork();
16
17 }
write为系统调用接口,直接刷新,而由于重定向输出到文件,用户级缓冲区的刷新策略更改为全缓冲,fork后子进程写时拷贝 ,而缓冲区也会随着FILE结构体的拷贝而拷贝,当子进程退出后刷新缓冲区,接着父进程退出也刷新缓冲区
在/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
};
inode
定位一个扇区:面(定位该用哪个磁头) -> 磁道(柱面) -> 扇区 (CHS寻址方式)
建立联系,
在Linux中,用于标识文件, 找到inode
编号->inode table
-> struct inode
-> blocks[]
-> 文件内容
struct inode {
inode number
//文件类型
//权限 : w/r/x
//引用计数
//拥有者
//所属组
//ACM时间
int blocks[N] //
}
inode table
: 存放inode
, 每个inode
有唯一的编号(一个文件一个inode, 一个inode可能对应多个block)
ls -li
: 查看inode
编号Block Bitmap
:位图,标记块是否被使用
inode Bitmap
:位图,标记inode
编号是否是有效的
Group Descriptor Table
:
Super Block
:文件系统的基本信息,包含整个分区的基本使用情况
dentry
缓存
ln -s file.txt soft-link
inode
,也有独立的数据块,它的数据块里面保存的是指向文件的路径(类似于快捷方式)ln test.txt hard-link
inode
,本质上是在当前目录下,建立新的文件名字与inode
链接(取别名/引用).
和 ..
),不然会造成查找路径的环路问题libXXX.a
libXXX.so
.o
文件的集合ar
是gun归档工具, 用于打包静态库,rc
表示replace and createlib=libmymath.a
$(lib):mymath.o //可能有多个.o文件
ar -rc $@ $^
mymath.o:mymath.c
gcc -c $^
.PHONY:
clean:
rm -f *.a *.o
.PHONY:output
output:
mkdir -p lib/include
mkdir -p lib/mymathlib
cp *.h lib/include
cp *.a lib/mymathlib
使用库:
-I
-L
-l
(去掉lib
,去掉.a
,剩下的名字) ;第三方库必须指定库名称gcc main.c -I ./lib/include/ -L ./lib/mymathlib/ -lmymath
ldd a.out
sudo cp lib/include/math.h /usr/include/
sudo cp lib/mymathlib/libmymath.a /lib64/
.o
文件gcc -fPIC -c mylob.c
(-c
不知名目标文件时,生成的时同名.o
文件)
.so
文件gcc -shared -o libmymethod *.o
(不加-shared
生成的是可执行文件)
.so
文件自动带有x
可执行权限dy-lib=libmymethod.so
static-lib=libmymath.a
.PHONY:all
all: $(dy-lib) $(static-lib)
$(static-lib):mymath.o
ar -rc $@ $^
mymath.o:mymath.c
gcc -c $^
$(dy-lib):mylog.o myprint.o
mylog.o:mylog.c
gcc -fPIC -c $^
myprint.o:myprint.c
gcc -fPIC -c $^
.PHONY:clean
clean:
rm -rf *.o *.a *.so mylib
.PHONY:output
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp *.h mylib/include
cp *.a mylib/lib
cp *.so mylib/lib
-fPIC
:与地址无关码四种方法:
/lib64
下/lib64
下的软连接ln -s xxx(绝对路径) /lib64/xxx
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/xxx/xxxx/xx(绝对路径)
cd /etc/ld.so.conf.d
.conf
文件ldconfig
动态库在系统中加载后,会被所有进程共享
共享库中的全局变量,既然会被共享,那么会不会冲突? 不会,因为会发生写时拷贝
.o
)时,需要带选项-fPIC
:(position independent code)
3. 添加到环境变量
```bash
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/xxx/xxxx/xx(绝对路径)
cd /etc/ld.so.conf.d
.conf
文件ldconfig
动态库在系统中加载后,会被所有进程共享
共享库中的全局变量,既然会被共享,那么会不会冲突? 不会,因为会发生写时拷贝
.o
)时,需要带选项-fPIC
:(position independent code)因篇幅问题不能全部显示,请点此查看更多更全内容