1684 字
8 分钟
Linux编程-文件IO

软连接与硬连接#

软连接#

ln -s file file.s #ln [选项]... [-T] 目标 链接名

类似于windows的快捷方式,file.s中存储的是访问路径,但是是相对的,如果将file.s的位置移动后,无法使用,如果想要使用绝对路径,则使用绝对路径创建

ln -s /home/kozakemi/test/linux_shell/file file.soft

这样操作后任意位置均可访问,因此,为了创建软连接是,尽量使用绝对路径创建软连接

实际上其原理为软连接文件存储的是路径

创建的软连接,文件名与日期均不同

文件类型为l

硬连接#

创建的软连接权限为全开放,但是文件是否可被操作,是由源文件决定

ln file file.h  

这两个文件任意修改一个,均会更改源文件,文件名不同,而日期一致

原理是两个文件为Inode一致,因此修改一个文件时,会同时修改是有的Inode一致的文件,及硬连接的文件,linux为每个文件赋予唯一的Inode

当删除时就不是这个问题,做法是将硬连接计数减1

文件类型由源文件决定

系统调用#

系统调用函数属于操作系统的一部分,是为了提供给用户进行操作的接口(API函数),使得用户态运行的进程与硬件设备(如CPU、磁盘、打印机、显示器)等进行交互。

image-20231016232409335

man#

太男人了

这是一个非常好用的工具,在linux查询c库与系统调用十分便捷

man man 
1   可执行程序或 shell 命令
2   系统调用(内核提供的函数)
3   库调用(程序库中的函数)
4   特殊文件(通常位于 /dev)
5   文件格式和规范,如  /etc/passwd
6   游戏
7   杂项(包括宏包和规范), man(7),groff(7), man-pages(7)
8   系统管理命令(通常只针对 root 用户)
9   内核例程 [非标准

文件IO#

open()#

概述#

open, creat - 打开和/或创建一个文件

#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)
int creat(const char *pathname, mode_t mode);

参数#

参数 pathname 为文件路径

flages是通过 O_RDONLY, O_WRONLYO_RDWR (指明 文件 是以 只读 , 只写 或 读写 方式 打开的)与下面的 零个 或 多个 可选模式 按位 -or 操作 得到的

       O_CREAT
             若文件 不存在 创建 一个 文件. 文件 属主 (用户ID) 被 设置 为 此 程序 的 有效 用户
 ID.  同样 文件 所属 分组 设置 程序 有效 分组 ID 或者 上层 目录  分组
             ID  (这 依赖 文件系统 类型 ,装载选项 上层目录 模式, 参考,在 mount(8)  描述 ext2
                  件系统 装载选项 bsdgroups sysvgroups )
       O_APPEND
              文件  追加  模式  打开  . 以前 , 文件 读写 指针 文件 末尾 .  as if with
              lseek.  O_APPEND may lead to corrupted files on NFS file systems if  more  than  one  process
              appends data to a file at once.  This is because NFS does not support appending to a file, so
              the client kernel has to simulate it, which can't be done without a race condition.
              
#其余详见`man 2 open` 

mode创建文件时指定权限

S_IRWXU
00700 允许 文件 属主 , 执行 文件

S_IRUSR (S_IREAD)
00400 允许 文件 属主 文件

S_IWUSR (S_IWRITE)
00200 允许 文件 属主 文件
#其余详见`man 2 open` 

返回值#

返回值为int类型,一般从3开始递增,

  • 文件描述符 0:标准输入(stdin)
  • 文件描述符 1:标准输出(stdout)
  • 文件描述符 2:标准错误输出(stderr)

以上三个描述符被系统占用,因此一般从3开始,例如下面的示例代码

示例代码#

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main() {
  int fd;

  // Open "tmp.txt" file in write-only mode
  fd = open("tmp.txt", O_WRONLY);
  if (fd == -1) {
    perror("Error opening tmp.txt");
    printf("Error opening tmp.txt: %s\n",strerror(errno));
  }
  printf("%d\n", fd);

  // Open "tmp.txt" file in append mode for writing
  fd = open("tmp.txt", O_WRONLY | O_APPEND);
  if (fd == -1) {
    perror("Error opening tmp.txt");
    printf("Error opening tmp.txt: %s\n",strerror(errno));
  }
  printf("%d\n", fd);

  // Open "Fol.txt" file in read-only mode, create if it doesn't exist with permissions 0777
  fd = open("Fol.txt", O_RDONLY | O_CREAT, 0777);//8进制0开头
  if (fd == -1) {
    perror("Error opening Fol.txt");
    printf("Error opening Fol.txt: %s\n",strerror(errno));
  }
  printf("%d\n", fd);

  return 0;
}

目录文件结构

[kozakemi@kozakemi-arch linux_ccode]$ ls -l                                       
总计 8
-rw-r--r-- 1 kozakemi kozakemi   6 10月16日 23:29 1.txt
-rw-r--r-- 1 kozakemi kozakemi 563 10月16日 23:50 file_w.c
-rwxr-xr-x 1 kozakemi kozakemi   0 10月16日 23:46 Fol.txt
-rw-r--r-- 1 kozakemi kozakemi   0 10月16日 23:47 tmp.txt

执行结果

[kozakemi@kozakemi-arch linux_ccode]$ gcc '/home/kozakemi/test/linux_ccode/file_w.c' && ./a.out 
3
4
5

write()#

概述#

在一个文件描述符上执行写操作

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

参数#

fd文件描述符,open的返回值

buf写入的字符串

count写入的大小

返回值#

ssize_t为写入的字节数

示例代码#

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

#include <unistd.h>
#include <errno.h>
#include <string.h>
int main() {
  int fd;
  ssize_t strno;
  fd=open("Fol.txt",O_WRONLY|O_APPEND);
  char infile_str[]="asdasdasd\n";
  if(-1==fd)
  {
    printf("error Fol.txt: %s",strerror(errno));
    perror("Fol.txt");
  }else{
    strno=write(fd, infile_str, strlen(infile_str));
    printf("%d=%d=%d-1",strno,strlen(infile_str),sizeof(infile_str));
  }
  return 0;
}

read()#

概述#

在文件描述符上执行读操作

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

参数#

fd文件描述符,open的返回值

buf读出的字符串

count读出的大小

  • 需要注意的是count不要大于buf值(必定报错[1] 17806 IOT instruction (core dumped) ),更不要大于文件中内容的大小否则会出现不可预料的错误(虽然我测试时未遇到)

返回值#

ssize_t为读出的字节数

示例代码#

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

#include <unistd.h>
#include <errno.h>
#include <string.h>
int main() {
  int fd;
  ssize_t strno;
  int readsize=10;
  fd=open("Fol.txt",O_RDONLY);
  char file_oustr[20]="";
  if(-1==fd)
  {
    printf("error Fol.txt: %s",strerror(errno));
    perror("Fol.txt");
  }else{
    strno=read(fd, file_oustr, readsize);
    printf("%d,%s",strno,file_oustr);
  }
  
  return 0;
}

close()#

概述#

关闭一个文件描述符

#include <unistd.h>

int close(int fd);

参数#

fd文件描述符

返回值#

-1为关闭失败,0为关闭成功

示例代码#

#include <unistd.h>  
。。。
fd=open("Fol.txt",O_RDONLY);
。。。
if(-1==close(fd)){
    printf("error close file: %s",strerror(errno));
    return -1;
}

lseek()#

这是一个系统调用

概述#

修改文件的描述符,偏移位置

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

参数#

fd文件描述符

offset偏移量

whence偏移方式 

  • SEEK_SET:偏移到文件头+ 设置的偏移量
  • SEEK_CUR:偏移到当前位置+设置的偏移量
  • SEEK_END:偏移到文件尾置+设置的偏移量

返回值#

off_t设置之后的文件偏移量,操作失败时返回-1,成功后返回偏移量

示例程序#

查看当前的位置

#include <fcntl.h>
#include <stdio.h>

#include <unistd.h>
#include <errno.h>
int main() {
  int fd,ret;
  fd=open("Fol.txt",O_RDWR);
  ret=lseek(fd,0,SEEK_CUR);
  printf("%d\n",ret);
  perror("lseek");
  return 0;
}

查看文件大小

#include <fcntl.h>
#include <stdio.h>

#include <unistd.h>
#include <errno.h>
int main() {
  int fd,ret;
  fd=open("Fol.txt",O_RDWR);
  ret=lseek(fd,0,SEEK_END);
  printf("%d\n",ret);
  perror("lseek");
  return 0;
}

将字符串插入到指定的位置后

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

int main()
{
  int fd,ret;
  char a[]="JMU WELCOME";
  fd=open("hello1.txt",O_RDWR|O_CREAT,0777);
  ret=lseek(fd,1000,SEEK_END);
  write(fd,a,strlen(a));
  printf("%d\n",ret);
  return 0;
}
Linux编程-文件IO
https://kozakemi.top/posts/linux编程-文件io/
作者
Kozakemi
发布于
2023-10-17
许可协议
CC BY-NC-SA 4.0