linux目录及文件操作
linux文件目录分布
常用的Linux指令:
vi编辑器
vi是一种方便的代码编辑器,Linux系统一般是自带的
linux文件
-rw-rw-r-- 1 cc cc 41 May 2 06:53 1q
-rw-rw-r-- 1 cc cc 13 May 2 05:53 a.c
-rw-rw-r-- 1 cc cc 42 May 2 06:54 add.c
-rw-rw-r-- 1 cc cc 1232 May 2 06:54 add.o
-rw-r--r-- 1 cc cc 363 May 2 05:31 cat.c
-rwxrwxr-x 1 cc cc 8656 May 2 02:04 demo
例如文件a.c:用户的权限是:可读可写,组用户的权限是:可读可写,其他用户的权限是:可读
1.open函数
//包含的头文件:
#include <sys/types.h>//这里提供类型pid_t和size_t的定义
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags); /*比较常用*/
int open(const char *pathname, int flags, mode_t mode);
返回值:
const char *file_path = "/home/user/test.txt";
访问模式标志:
O_RDONLY:以只读模式打开文件。
O_WRONLY:以只写模式打开文件。
O_RDWR:以读写模式打开文件。
其他常用标志:
O_CREAT:如果文件不存在,就创建该文件。当使用这个标志时,需要提供第三个参数 mode 来指定文件的权限。
O_EXCL:和 O_CREAT 一起使用时,如果文件已经存在,open() 调用会失败。
O_TRUNC:如果文件已经存在并且以写模式打开,会将文件截断为长度为 0。
O_APPEND:每次写操作都会将数据追加到文件末尾。
// 以只读模式打开文件
int fd1 = open("/home/user/test.txt", O_RDONLY);
// 如果文件不存在则创建它,以读写模式打开
int fd2 = open("/home/user/new_file.txt", O_RDWR | O_CREAT, 0666);
2.close函数
#include <unistd.h>//包含的头文件
int close(int fd);
参数是文件的句柄,功能就是简单的关闭文件
3.write函数
#include <unistd.h>
ssize_t write (int fd,const void * buf, size_t count);
参数说明:
fd: 文件描述符
4.read函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数说明:
fd: 文件描述符
main函数参数
int main(int argc,char *argv[])
{
return 0;
}
下面实现cp指令来理解main函数的参数:
编写demo.c:
include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
int src_fd;
int des_fd;
char sendBuffer[128]={0};
int ByteNum = 0;
src_fd = open(argv[1],O_RDWR);
if(src_fd < 0)
{
printf("open file %d failed\n",src_fd);
return -2;
}
des_fd = open(argv[2],O_RDWR|O_CREAT,0755);
if(des_fd <0)
{
printf("open file %d failed\n",des_fd);
return -1;
}
while(1)
{
ByteNum = read(src_fd,&sendBuffer[0],128);
if(ByteNum<128)
break;
write(des_fd,&sendBuffer[0],ByteNum);
memset(sendBuffer,0,128);
}
write(des_fd,sendBuffer,ByteNum);
close(src_fd);
close(des_fd);
return 0;
}
此时在命令行编译demo.c生成可执行文件a.out后
在命令行输入./a.out demo.c demo1.c即可实现cp demo.c demo1.c 的效果
此时main函数的参数argc的值为3,数组argv[0]存放的是./a.out,argv[1]存放的是demo.c,argv[2]存放的是demo1.c
5.lseek函数
off_t lseek(int fd, off_t offset, int whence);//设置光标偏移量
文件IO和标准IO
概念层面
- 文件 I/O:也被称为低级 I/O 或者系统调用 I/O,它直接使用操作系统提供的系统调用来进行文件操作,如在 Unix/Linux 系统中的
open
、read
、write
、lseek
和close
等函数。这些系统调用是操作系统内核的一部分,提供了对文件最基本的访问方式。 - 标准 I/O:又称为高级 I/O,它是基于 C 标准库实现的一套文件操作接口,如
fopen
、fread
、fwrite
、fseek
和fclose
等函数。标准 I/O 库对底层的文件 I/O 系统调用进行了封装,提供了更方便、更高级的文件操作功能。
缓冲机制
- 文件 I/O:通常是无缓冲或者使用内核缓冲。无缓冲意味着每次调用
read
或write
函数时都会直接进行系统调用,与磁盘或其他设备进行数据交互,这可能会导致频繁的系统调用,从而影响性能。内核缓冲由操作系统内核管理,应用程序无法直接控制。 - 标准 I/O:使用用户空间的缓冲区,标准 I/O 库会在内存中为每个文件流分配一个缓冲区。当调用
fread
或fwrite
函数时,数据会先被读写到缓冲区中,只有当缓冲区满或者调用fflush
函数时,才会将缓冲区中的数据实际写入磁盘或从磁盘读取数据到缓冲区。这种缓冲机制可以减少系统调用的次数,提高 I/O 性能。
可移植性
- 文件 I/O:不同的操作系统提供的文件 I/O 系统调用可能有所不同,因此使用文件 I/O 编写的代码可移植性较差。例如,Windows 系统和 Unix/Linux 系统的文件 I/O 接口存在差异。
- 标准 I/O:C 标准库定义了一套统一的标准 I/O 接口,这些接口在不同的操作系统和编译器上具有较好的可移植性。只要是支持 C 标准库的系统,都可以使用标准 I/O 函数进行文件操作。
错误处理
- 文件 I/O:文件 I/O 系统调用通常通过返回值和
errno
变量来进行错误处理。返回值可以表示操作的结果,如open
函数返回 -1 表示打开文件失败,而errno
变量可以进一步指示具体的错误类型。 - 标准 I/O:标准 I/O 函数通常通过返回值来表示操作的结果,如
fopen
函数返回NULL
表示打开文件失败。同时,标准 I/O 库还提供了ferror
和feof
等函数来检查文件流的错误和结束状态。
操作灵活性
- 文件 I/O:文件 I/O 提供了对文件操作的底层控制,例如可以直接设置文件偏移量、指定读写的字节数等,适合对文件进行底层的、精细的操作。
- 标准 I/O:标准 I/O 提供了更高级的功能,如格式化输入输出(
fprintf
和fscanf
)、行缓冲等,适合进行更方便、更复杂的文件操作。
缓冲类型
标准 C 库有三种缓冲类型:
- 无缓冲(Unbuffered):在无缓冲模式下,每次进行 I/O 操作都会立即调用底层的系统调用,数据不会在用户空间的缓冲区中停留。标准错误输出流
stderr
通常就是无缓冲的,这样能保证错误信息及时输出,方便用户及时发现程序问题。 - 行缓冲(Line-buffered):行缓冲模式下,数据会先被存储在用户空间的缓冲区,直到遇到换行符
\n
或者缓冲区满了,才会调用底层系统调用将缓冲区中的数据写入内核。标准输入流stdin
和标准输出流stdout
在与终端交互时一般采用行缓冲模式,以确保用户输入的一行数据能及时处理,程序输出的一行信息能及时显示。 - 全缓冲(Fully-buffered):全缓冲模式下,数据会被存放在用户空间的缓冲区,直至缓冲区被填满,才会调用底层系统调用将数据写入内核。磁盘文件默认使用全缓冲模式,通过减少系统调用次数来提高 I/O 性能。
#include "stdio.h"
int main()
{
char buf[]="hello linux";
printf("%s",buf);
while(1);
return 0;
}
此时buf的内容不会打印到显示器上面
6.fopen函数

#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
/*
* @description : 打开一个文件
* @param ‐ pathname : 指定文件路径,如:"./test.txt"
* @param ‐ mode :指定文件的打开方式,如下:
* @return : 成功,返回指向该文件的文件指针; 若失败,返回 NULL
*/
7.fread函数
从文件中读取数据到指定地址中
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
/*
* @description :对已打开的流进行数据读取
* @param ‐ ptr :指向 数据块的指针
* @param ‐ size :指定读取的每个数据项的字节数
* @param ‐ nmemb : 指定要读取的数据项的个数
* @param ‐ stream :要读取的文件流
* @return : 返回实际读取数据项的个数;
*/
8.fwrite函数
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
/*
* @description :对已打开的流进行写入数据块
* @param ‐ ptr :指向 数据块的指针
* @param ‐ size :指定写入的每个数据项的字节数,如调用sizeof(char)
* @param ‐ nmemb :指定写入的数据项的个数
* @param ‐ stream :要写入的文件流
* @return : 返回实际写入的数据项的个数
*/
9.fseek函数
重定位文件内部的指针
int fseek(FILE *stream,long offset,int framewhere)
10.fclose函数
#include <stdio.h>
int fclose(FILE *stream);
/*
* @description :关闭一个已打开的流
* @param ‐ stream :文件指针(流)
* @return : 成功,返回0; 若失败,返回EOF
*/
11.fgets和fputs
char *fgets (char *s, int size,FILE *stream)
int fputs(const char *s,FILE *stream);
12.刷新缓存函数
把库函数中的缓存内容强制写到内核中。
ffluash(FIFE *fp)
13.调整读写位置指针函数
14.fprintf、printf、sprintf
15.fgetc和fputc
int fgetc(FILE *fp)
int fputc(int c, FILE *fp)
返回值:成功则返回输入的字符,出错返回EOF。
int feof(FILE *stream)
int ferror(FILE *stream);
void clearerr(FILE *stream);
#include <stdio.h>
int main(int argc,char *argv[])
{
FILE*fp;
int nRet = 0;
if(argc != 2)
{
printf("failed\n");
return -1;
}
fp = fopen(argv[1],"r");
if(fp == NULL)
{
printf("open file failed\n");
return -2;
}
while(1)
{
nRet = fgetc(fp);
if(feof(fp))
{
break;
}
fputc(nRet,stdout);
}
fclose(fp);
return 0;
}
编译后在命令行输入./a.out cat.c 即可实现cat cat.c 的效果
静态库和动态库
静态库的制作
1.创建库文件
gcc -c mylib.c -o mylib.o
ar rcs libmylib.a mylib.o
#1.先用.c文件生成.o文件
#2.再用.o文件生成静态库libxxx.a
2.使用库文件
gcc main.c -o main -L. -lmylib
./main
#1.-l是指定要用的静态库,库名去掉头尾 -L是让gcc从-L指定的路径找,-L.是当前工作目录
#2.运行可执行文件
动态库的制作
gcc -c file.c
2.生成libaddsub.so 动态函数库
gcc -shared -fpic -o libfile.so file.o
‐fpic:产生位置无关代码
‐shared:指定生成动态库
gcc main.c -o out ‐L. ‐lfile
sudo cp /path/to/libaddsub.so /usr/lib/
#将 /path/to/ 替换为实际路径(例如 ./libaddsub.so 表示当前目录)
#使用 sudo 确保有足够权限修改 /usr/lib
2.更新动态链接库缓存
sudo ldconfig
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/path/to/your/library"
#将 /path/to/your/library 替换为动态库所在实际路径
sudo nano /etc/ld.so.conf
2.在文件末尾添加一行,内容为你动态库所在的目录路径
/opt/mylibs # 添加此行(替换为实际库目录)
3.更新动态链接库缓存
sudo ldconfig