文件IO编程

news2024/9/24 1:46:32

文章目录

    • 文件描述符
    • 相关系统调用
    • 文件有关的系统调用
      • 文件操作函数--creat函数
      • 文件操作函数--open函数
      • 文件操作函数--read函数
      • 文件操作函数--write函数
      • 文件操作函数--close函数
      • 文件操作函数--lseek函数
      • 缓冲区的大小对性能的影响
    • 实验:调用系统函数,实现文件的复制功能

文件描述符

对于内核而言,所有打开文件都由文件描述符引用

  • 文件描述符是一个非负整数
  • 打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。

当读,写一个文件时,用open或creat返回的文件描述符标识该文件,然后将其作为参数传送给read或write.

  • 按照惯例,linux shell使文件描述符0与进程的标准输入相结合,文件描述符1标准输出相结合,文件描述符2与标准出错输出相结合。
  • 文件描述符的本质是一个非负整数,当打开一个文件时,该整数由系统来分配。文件描述符的范围是0-OPEN_MAX 早期的UNIX版本OPEN_MAX=19,即允许每个进程同时打开20个文件,现在很多系统则将其增加至1024.

  • 静态文件
    • 未打开时,存放在块设备中的文件系统中的文件

  • 动态文件
    • 当打开文件时,Linux内核会在进程中建立一个该文件的数据结构,记录该文件已被打开,同时申请一段内存空间,再将静态文件的内容从块设备中读取到内存中特定的地址管理存放

    • 当关闭动态文件时,close内部内核将内存中的动态文件更新至静态文件。

相关系统调用

  • 系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务。

    • 例如用户可以通过进程控制相关的系统调用创建进程实现进程调度进程管理等。
  • 为什么用户程序不能直接访问系统内核提供的服务呢?
    为了更好地保护内核空间,将程序的运行空间分为内核空间用户空间(内核态和用户态)。

  • 用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。

  • 在有些情况下,用户空间的进程需要获得一定的系统服务(调用内核空间程序),这时操作系统就必须利用系统提供给用户的“特殊接口”——系统调用规定用户进程进入内核空间的具体位置

  • 进行系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后再返回到用户空间。

  • 系统调用按照按照功能逻辑可分为:

    • 进程控制
    • 进程间通信
    • 文件系统控制
    • 系统控制
    • 存储管理
    • 网络管理
    • socket控制
    • 用户管理

    系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获取内核服务的接口。
    在实际使用中程序员调用的通常是用户编程接口——API
    系统命令相对API更高了一层,它实际上一个可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能。
    在这里插入图片描述

文件有关的系统调用

  • creat
  • open
  • read
  • write
  • lseek
  • close
  • perror
#include <fcntl.h>
#include <unistd.h>

int fd = creat(char *filename, mode_t mode)
int  fd = open(char *name, int how)
ssize_t numread = read(int fd, void *buf, size_t qty)
ssize_t result = write(int fd, void *buf, size_t amt)
off_t oldpos = lseek(int fd, off_t dist, int base)
int resule = close(int fd)

文件操作函数–creat函数

在这里插入图片描述

  • creat告诉内核创建一个名为filename的文件,如果这个文件不存在,就创建它,如果已存在,就把它的内容清空,把文件的长度设为0

在这里插入图片描述

  • 如果内核成功地创建了文件,文件的许可权限将被设置为由mode指定的值。
    如:fd = creat(“test”,0644);
    名为test的文件权限被设为-rw-r--r--

文件操作函数–open函数

在这里插入图片描述

  • O_RDONLY, O_WRONLY, O_RDWR分别对应:只读、只写、可读可写
  • 在这里插入图片描述

文件操作函数–read函数

在这里插入图片描述

  • 从文件描述符fd所指定的文件中读取qty个字节到buf所指向的缓冲区中,返回值为实际读取字节数
    • 1.如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。
    • 2.有多种情况可使实际读到的字节数少于要求读字节数:
      • 读普通文件时,在读到要求字节数之前已到达了文件尾端。例如,若在到达文件尾端之前还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将返回0 (文件尾端)。
      • 当从终端设备读时,通常一次最多读一行
      • 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
      • 某些面向记录的设备,例如磁带,一次最多返回一个记录。

文件操作函数–write函数

在这里插入图片描述

  • 把amt个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数

文件操作函数–close函数

在这里插入图片描述

  • 不需要再对文件进行读写操作时,就要把文件关闭。
  • close会关闭进程和文件fd之间的连接。

文件操作函数–lseek函数

在这里插入图片描述

  • off_t oldpos = lseek(int fd, off_t dist, int base)
    offset可取负值,表示向前移动。
    如:lseek(fd, -5, SEEK_CUR)
    下述调用可将文件指针相对当前位置向前移动5个字节

缓冲区的大小对性能的影响

在这里插入图片描述

实验:调用系统函数,实现文件的复制功能

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


//用法:cp /etc/passwd /root/passwd

main(int argc, char *argv[])
{
	int read_fd, write_fd;
	unsigned char buf[128];
	int num_read;
	int write_result;

	//判断用户输入的字串是否为两个
	if(argc != 3)
	{
		printf("Usage Error\n");
		exit(1);
	}	
	
	write_fd = creat(argv[2], 0644);
	if(write_fd == -1)
	{
		printf('create file error!\n');
		exit(1);
	}
	printf("write_fd=%d\n",write_fd);

	read_fd = open(argv[1],O_RDONLY);	
	if(read_fd == -1)
	{
		printf('open file error!\n');
		exit(1);
	}
	printf("read_fd=%d\n",read_fd);
	int x=0;
	while(1)
	{
		num_read = read(read_fd, buf, 128);
		if(num_read==0)
		{
			printf("all successful finished!\n");
			break;
		}
		if(num_read==-1)
		{
			printf("read error!\n");
			break;
		}
		printf("num_read=%d\n",num_read);
		
		write_result = write(write_fd, buf, sizeof(buf));
		buf[0]='\0';
		printf("write_result=%d\n",write_result);
	}
	
	
	close(read_fd);
	close(write_fd);
}
  • 具体思路如下:

    • 1.实现复制第一步,我们需要打开我们要复制的文件,并获取其中的内容:
      • (1)因此我们调用int fd=open(charname,int how)来打开文件
        (2)再根据fd,使用read函数读取文件内容:read(int fd,void
        buf,size_t num);
        (3)读取的内容我们读取在了buf字符数组中。
    • 2.实现复制第二步,获取数据后我们要写入要复制到的文件中,而复制到的目标文件我们需要先创建,然后再写入数据:
      • (1)创建文件:creat(char*filename,mode_t mode);
      • (2)写入文件:write(int fd,void*buf,size_t amt);
    • 3.由于我们不知道要复制的文件中有多少个字节,因此我们可以加一个循环,由read函数系统调用后若返回0,代表读取完毕,此时我们就可以退出循环了。
  • 实验运行结果:
    我尝试将/etc/fstab文件copy到当前目录下来,并查看copy过来的文件,成功复制了过来,实验截图如下:
    在这里插入图片描述

    为再次确认其复制功能,我将/etc/passwd复制到wyl的家目录下,并查看复制过来的文件看是否正确。实验截图如下:
    在这里插入图片描述
    在这里插入图片描述

  • 我们发现内容成功复制!接下来我们对结果进行分析:

  • 在这里插入图片描述由上图我们发现最后复制的passwd文件发现了一个问题,对比两个文件发现行数不同,发现复制的文件比原来的文件多了以下数据:

nager:/var/lib/gdm3:/bin/false
wyl:x:1000:1000:Ubuntu18.04,,,:/home/wyl:/bin/bash
sshd:x:122:65534::/run/ssh

而fstab却不会出现此问题。

我总结推测这是因为当我们运行这个程序的时候,会创建一些系统用户来执行,会被记录在/etc/passwd中,而程序结束后,此记录又会消失,所以出现了行数不同,并多出了上方数据。

以上内容仅供参考,如有不对,欢迎指正!谢谢

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2126560.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux:体系结构和操作系统管理

目录 一、冯诺依曼体系结构 1.问题1 2.问题2 二、操作系统管理 一、冯诺依曼体系结构 本章将会谈论一下对冯诺依曼计算机体系结构的理解。 在2024年&#xff0c;几乎所有的计算机&#xff0c;都遵守冯诺依曼体系结构。 冯诺依曼体系结构是应用在硬件层面的&#xff0c;而硬…

Docker高级管理--Compose容器编排与私有仓库(Docker技术集群与应用)

本文介绍了Docker的三大工具&#xff1a;Docker Machine用于创建和管理Docker主机&#xff0c;Docker Compose用于单引擎模式下的多容器应用部署和管理&#xff0c;而Docker Swarm则是一个集群管理工具&#xff0c;提供微服务应用编排功能。Docker Machine支持在不同环境配置Do…

【代码随想录训练营第42期 Day56打卡 - 图论Part6 - 并查集2 - 冗余连接问题

目录 一、做题心得 二、题目与题解 题目一&#xff1a;108. 冗余连接 题目链接 题解&#xff1a;并查集 题目二&#xff1a;109. 冗余连接II 题目链接 题解&#xff1a;并查集 三、小结 一、做题心得 冗杂连接问题是图论章节应用并查集的经典问题。所有的顶点通过边相…

Redis 篇- 实战项目中使用 Redis 实现经典功能(异步秒杀商品、点赞功能、共同关注的好友、投喂功能)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 使用 Redis 实现异步秒杀 1.1 基于 Lua 脚本判断是否符合条件&#xff1a;库存是否充足、一人一单 1.2 基于 Redis 中的 Stream 实现消息队列 1.3 使用 Java 操作…

Unity Hub自动安装指定版本Unity的Android开发环境

Unity开发Android环境要求SDK、DNK、JDK、Gradle版本都要对才能发布APK&#xff0c;自己去配置很容易出错。Unity Hub可以自动安装指定版本Unity的Android开发环境。 1.安装国内用的UnityHub&#xff08;我这里用的3.3.2-c6&#xff09; 2.找到对应的Unity版本 3.点击【从Unit…

docker管理redis集群

1.拉取redis镜像 docker pull redis拉取完成 [rootlocalhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE redis latest a617c1c92774 3 years ago 105MB2.运行redis容器 docker run -itd --name redis-test01 -p 6379:6379…

谈谈PCIe VID、DID、SSID、SSVID背后的智慧

PCIe Vendor ID 想了半天还是觉得从“ID是什么”这个问题开始比较好。那么ID是什么&#xff1f;ID就是身份。那身份又是什么&#xff1f;身份就是一个合理存在&#xff0c;用于区分不同个体。为什么叫“合理存在”呢&#xff1f;如果国家不给你发身份证&#xff0c;你就是黑户…

记一次导入dbf文件后数据为空问题的解决方法

前言 省流&#xff1a;这篇文章最终采用的是更换导出文件格式的方法&#xff0c;看到这里觉得方法不适用的小伙伴可以不用浪费几秒钟看完这篇文章哦。 问题描述 作者使用的是Navicat数据库管理工具&#xff0c;然后在将源数据库的数据表导出为dbf格式文件后&#xff0c;再将…

F110批量付款如何Debug BTE增强(后台JOB的调试方法)

F110批量付款如何Debug BTE增强&#xff08;后台JOB的调试方法&#xff09; SAP系统中的F110&#xff08;Automatic Payment&#xff09;是一个常用的付款程序&#xff0c;在实施过程中&#xff0c;也经常会遇到一些运行的错误&#xff0c;而对于此类的错误&#xff0c;通常的…

基于SpringBoot的租房网站系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 工具&#xff1a;ECLIPSE 系统展示 首页 管理员功能界面 用户信息界面 预约看房界…

动手学深度学习(pytorch)学习记录28-使用块的网络(VGG)[学习记录]

目录 VGG块VGG网络训练模型 VGG块 定义了一个名为vgg_block的函数来实现一个VGG块 import torch from torch import nn from d2l import torch as d2ldef vgg_block(num_convs, in_channels, out_channels):layers []for _ in range(num_convs):layers.append(nn.Conv2d(in_…

线程池原理及改造

目录 一 线程池执行原理 二 线程池改造(一) 三 线程池改造(二) 一 线程池执行原理 首先我们先了解一下线程池里面几个参数&#xff1a; 第一个是核心线程数&#xff0c;第二个是线程池最大线程数。&#xff08;线程池里面的线程分为核心线程和非核心线程&#xff0c;既然核心…

人物化身持有者每月奖励:九月版

世界急需英雄。你准备好响应号召了吗&#xff1f; 穿上你的斗篷&#xff0c;戴上你的面具&#xff0c;用你的风格保卫 The Sandbox 的街道吧&#xff01;本月为人物化身持有者准备的独家奖励是 The Sandbox 超级套装&#xff01; 本月我们将首次向我们生态系统中的所有人物化…

Vulnhub-RickdiculouslyEasy靶机攻略

御剑扫描到ip 一.第一个flag 主机扫描 目录扫描 二.网页信息收集-第二个flag 9090也开放了web服务所以我们在IP地址后面加端口试试&#xff0c;如下图&#xff0c;加上了端口&#xff0c;并且发现了第二个flag&#xff0c;也对第二个flag进行了简单的探索也没有发现什么可以…

Kubernetes上安装Metallb和Ingress并部署应用程序

视频和代码仓库 视频教程地址&#xff1a;https://www.bilibili.com/video/BV1QV4rebEb8 代码仓库地址&#xff1a;https://github.com/xiaohh-me/kubernetes-yaml 网络规划 之前已经写了几篇安装Kubernetes文章&#xff0c;这次来讲讲在Kubernetes上安装Ingress&#xff0c…

【Linux】Linux介绍及CentOS虚拟机环境搭建

内容大纲介绍 文章目录 内容大纲介绍1.计算机简介2.Linux系统介绍3.虚拟化软件介绍4.Linux环境搭建5.扩展_虚拟机的快照6.Linux的目录介绍 1.计算机简介 概述 全称叫电子计算机, 英文名叫Computer, 俗称叫: 电脑, 简称叫: PC, 就是有硬件和软件组成的电子设备. 组成 计算机硬件…

IO复用-epoll基础

文章目录 IO复用认识epollepoll原理重要结构体 epoll的ET、LTepoll高效的原因epoll需要解决的问题对于使用epoll的建议 IO复用 IO等待拷贝 IO复用是一种通过减少等待时间&#xff0c;来提高IO效率的方式。 其原理是通过同时管理多个IO接口&#xff08;文件描述符&#xff09;…

VS2022搭建Linux开发环境

一、VS2022按钮Linux开发组件 双击启动后 选择Linux开发组件 点击修改&#xff0c;开始按钮Linux组件 二、创建新项目 三、远程连接Linux系统 选择工具&#xff0c;点击选项 选择跨平台中的连接管理器&#xff0c;点击添加 配置信息&#xff0c;输入你需要连接到的Linux…

《论面向服务架构设计及其应用》写作框架,软考高级系统架构设计师

论文真题 面向服务架构(Service-Oriented Architecture, SOA) 是一种应用框架,将日常的业务应用划分为单独的业务功能服务和流程,通过采用良好定义的接口和标准协议将这些服务关联起来。通过实施基于SOA的系统架构,用户可以构建、部署和整合服务,无需依赖应用程序及其运…

PyCharm的安装步骤

如何在本机上下载和安装PyCharm&#xff0c;请看以下讲解&#xff1b; 目录 一、下载 二、安装 第 1 步&#xff1a; 第 2 步&#xff1a; 第 3 步&#xff1a; 第 4 步&#xff1a; 第 5 步&#xff1a; 三、配置 第 1 步&#xff1a; 第 2 步&#xff1a; 第 3 步…