【GameFramework框架内置模块】8、文件系统(File System)

news2024/10/5 20:19:10

推荐阅读

  • CSDN主页
  • GitHub开源地址
  • Unity3D插件分享
  • 简书地址

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

【GameFramework框架】系列教程目录:
https://blog.csdn.net/q764424567/article/details/135831551

最近好忙,鸽了好久。不能颓废了,继续发力。

今天分享的是GF框架的File System文件系统。

二、正文

2-1、介绍

首先,引用比较官方的说法:

GF的FileSystem虚拟文件系统,使用类似磁盘存储的感念对零散的文件进行集中管理,优化资源加载时产生的内存分配,也可以对资源进行局部片段加载,极大的提升了资源加载的性能。

通俗点讲就是,我这个模块就是加载磁盘文件的,优化加载时产生的内存分配。

那么,它是怎么优化的呢?

比如说一个文件夹里面有几千个文件,传输的话会非常的慢,因为普通的文件系统是一个一个读取写入,每次读取写入都是一次磁盘IO,所以花费大量时间,而这个文件系统将会将整个文件夹当成一个压缩包,然后再进行读取写入,那么就减少了大量的IO,提高了性能。

2-2、使用说明

查看文件是否存在:

using GameFramework.FileSystem;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityGameFramework.Runtime;

public class TestFileSystem : MonoBehaviour
{
    void Start()
    {
        FileSystemComponent fileSystemComponent = GameEntry.GetComponent<FileSystemComponent>();
        string fullPath = System.IO.Path.Combine(Application.persistentDataPath, "FileSystem.dat");

         检查是否存在文件系统,参数要传递的是文件系统的完整路径
        bool hasFileSystem = fileSystemComponent.HasFileSystem(fullPath);
        Debug.Log(hasFileSystem);
    }
}

读写文件:

using GameFramework.FileSystem;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityGameFramework.Runtime;

public class TestFileSystem : MonoBehaviour
{
    void Start()
    {
        FileSystemComponent fileSystemComponent = GameEntry.GetComponent<FileSystemComponent>();
        // 要创建的文件系统的完整路径
        string fullPath = Path.Combine(Application.persistentDataPath, "FileSystem.dat");

        // 要创建的文件系统最大能容纳文件数量
        int maxFileCount = 16;
        // 要创建的文件系统最大能容纳的块数据数量
        int maxBlockCount = 256;

        // 创建文件系统(使用读写模式进行访问)
        IFileSystem fileSystem = fileSystemComponent.CreateFileSystem(fullPath, FileSystemAccess.ReadWrite, maxFileCount, maxBlockCount);

        // 将字节数组写入指定文件
        byte[] buffer = new byte[1024]; // 读取文件片段使用的 buffer,用此方式能够复用 buffer 来消除 GCAlloc
        bool result = fileSystem.WriteFile("FileName.dat", buffer);

        // 将流写入指定文件
        FileStream fs = new FileStream("FileName.dat", FileMode.Create, FileAccess.Write);
        bool result2 = fileSystem.WriteFile("FileName.dat", fs);

        // 将物理文件写入指定文件
        bool result3 = fileSystem.WriteFile("FileName.dat", @"E:\PhysicalFileName.dat");

    }
}

2-3、实现及代码分析

File System虽说是一个独立的模块,但是一般不直接使用,通常要配合其他模块,比较典型的例子就是资源打包和读取额时候。

因为在做资源更新的时候,会将资源进行整理分包加载,资源管理器ResourceComponent继承了File System文件系统,只需要在构建ResoucrceCollection.xml时,在对应的资源Resources标签下指定FileSystem属性即可:在这里插入图片描述
Build资源的时候,会自动将此Resource放入指定的文件系统,运行加载资源时,也会自动去对应的FileSystem文件中进行加载。

下面就以打包和加载来分析FileSystem文件系统的代码实现。

2-3-1、打包代码分析

1、点击Start Build Resource按钮后,会调用BuildResource函数:
在这里插入图片描述
在这里插入图片描述

/// 资源生成器。
internal sealed class ResourceBuilder : EditorWindow
  private void BuildResources()
    {
        if (m_Controller.BuildResources())
        {
            Debug.Log("Build resources success.");
            SaveConfiguration();
        }
        else{
            Debug.LogWarning("Build resources failure.");
        }
    }
}

2、创建文件系统,存储在文件系统中:

public sealed partial class ResourceBuilderController
{
    public bool BuildResources()
    {
    	......
		AssetBundleManifest assetBundleManifest = BuildPipeline.BuildAssetBundles(workingPath, assetBundleBuildDatas, buildAssetBundleOptions, GetBuildTarget(platform));
		......
		if (OutputPackageSelected)
        {
            CreateFileSystems(m_ResourceDatas.Values, outputPackagePath, m_OutputPackageFileSystems);
        }
        ......
}

3、创建文件系统后,遍历所有的打包资源,获取标记了FileSystem标签的项,加入文件系统:

private void CreateFileSystems(IEnumerable<ResourceData> resourceDatas, string outputPath, Dictionary<string, IFileSystem> outputFileSystem)
{
    outputFileSystem.Clear();
    string[] fileSystemNames = GetFileSystemNames(resourceDatas);
    if (fileSystemNames.Length > 0 && m_FileSystemManager == null)
    {
        m_FileSystemManager = GameFrameworkEntry.GetModule<IFileSystemManager>();
        m_FileSystemManager.SetFileSystemHelper(new FileSystemHelper());
    }

    foreach (string fileSystemName in fileSystemNames)
    {
        int fileCount = GetResourceIndexesFromFileSystem(resourceDatas, fileSystemName).Length;
        string fullPath = Utility.Path.GetRegularPath(Path.Combine(outputPath, Utility.Text.Format("{0}.{1}", fileSystemName, DefaultExtension)));
        IFileSystem fileSystem = m_FileSystemManager.CreateFileSystem(fullPath, FileSystemAccess.Write, fileCount, fileCount);
        outputFileSystem.Add(fileSystemName, fileSystem);
    }
}

4、写入文件系统,把每个经过加密处理的资源写入到指定的文件系统中:

public sealed partial class ResourceBuilderController
{
    private bool ProcessOutput(Platform platform, string outputPackagePath, string outputFullPath, string outputPackedPath, bool additionalCompressionSelected, string name, string variant, string fileSystem, ResourceData resourceData, byte[] bytes, int length, int hashCode, int compressedLength, int compressedHashCode)
    {
        string fullNameWithExtension = Utility.Text.Format("{0}.{1}", GetResourceFullName(name, variant), GetExtension(resourceData));

        if (OutputPackageSelected)
        {
            if (!string.IsNullOrEmpty(fileSystem))
            {
                if (!m_OutputPackageFileSystems[fileSystem].WriteFile(fullNameWithExtension, bytes))
                {
                    return false;
                }
            }
        }
	}
}
2-3-2、加载代码分析

1、使用ResourceManager加载资源:

internal class ResourceManager : GameFrameworkModule, IResourceManager
{
    /// 异步加载资源。
    public void LoadAsset(string assetName, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData){
        m_ResourceLoader.LoadAsset(assetName, assetType, priority, loadAssetCallbacks, userData);
    }
}

2、使用Resource任务池加载,使用多个LoadResourceAgent代理,异步加载资源,每个资源加载都是一个LoadAssetTask,每个任务开始时都会分配一个LoadResourceAgent代理:

internal sealed class TaskPool<T> where T : TaskBase
{
    public void Update(float elapseSeconds, float realElapseSeconds)
    {
        ProcessRunningTasks(elapseSeconds, realElapseSeconds);
        ProcessWaitingTasks(elapseSeconds, realElapseSeconds);
    }
    //处理任务池等待列表
	private void ProcessWaitingTasks(float elapseSeconds, float realElapseSeconds)
    {
        LinkedListNode<T> current = m_WaitingTasks.First;
        while (current != null && FreeAgentCount > 0)
        {
            ITaskAgent<T> agent = m_FreeAgents.Pop();
            LinkedListNode<ITaskAgent<T>> agentNode = m_WorkingAgents.AddLast(agent);
            T task = current.Value;
            LinkedListNode<T> next = current.Next;
            //LoadResourceAgent代理开始读取资源
            StartTaskStatus status = agent.Start(task);
            current = next;
            ...
        }
    }
}

3、资源文件的读取,使用了资源加载代理辅助器,分别为LoadFromFile、LoadFromMemory两种不同的加载方式:

/// 默认加载资源代理辅助器。
public class DefaultLoadResourceAgentHelper : LoadResourceAgentHelperBase, IDisposable
{
    /// 通过加载资源代理辅助器开始异步读取资源文件。
    public override void ReadFile(string fullPath)
    {
        m_FileAssetBundleCreateRequest = AssetBundle.LoadFromFileAsync(fullPath);
    }

    /// 通过加载资源代理辅助器开始异步读取资源文件。
    public override void ReadFile(IFileSystem fileSystem, string name)
    {
        FileInfo fileInfo = fileSystem.GetFileInfo(name);
        m_FileAssetBundleCreateRequest = AssetBundle.LoadFromFileAsync(fileSystem.FullPath, 0u, (ulong)fileInfo.Offset);
    }

    /// 通过加载资源代理辅助器开始异步读取资源二进制流。
    public override void ReadBytes(string fullPath)
    {
        m_UnityWebRequest = UnityWebRequest.Get(Utility.Path.GetRemotePath(fullPath));
        m_UnityWebRequest.SendWebRequest();
    }

    /// 通过加载资源代理辅助器开始异步读取资源二进制流。
    public override void ReadBytes(IFileSystem fileSystem, string name)
    {
        byte[] bytes = fileSystem.ReadFile(name);
        m_LoadResourceAgentHelperReadBytesCompleteEventHandler(this, LoadResourceAgentHelperReadBytesCompleteEventArgs.Create(bytes));
    }
}

4、最后,通过LoadMain,从Bundle中读取资源,最后运行监听事件LoadComplete,加载全部完成:

/// 默认加载资源代理辅助器。
public class DefaultLoadResourceAgentHelper : LoadResourceAgentHelperBase, IDisposable
{
    /// 通过加载资源代理辅助器开始异步读取资源文件。
    public override void ReadFile(string fullPath)
    {
        m_FileAssetBundleCreateRequest = AssetBundle.LoadFromFileAsync(fullPath);
    }

    /// 通过加载资源代理辅助器开始异步读取资源文件。
    public override void ReadFile(IFileSystem fileSystem, string name)
    {
        FileInfo fileInfo = fileSystem.GetFileInfo(name);
        m_FileAssetBundleCreateRequest = AssetBundle.LoadFromFileAsync(fileSystem.FullPath, 0u, (ulong)fileInfo.Offset);
    }

    /// 通过加载资源代理辅助器开始异步读取资源二进制流。
    public override void ReadBytes(string fullPath)
    {
        m_UnityWebRequest = UnityWebRequest.Get(Utility.Path.GetRemotePath(fullPath));
        m_UnityWebRequest.SendWebRequest();
    }

    /// 通过加载资源代理辅助器开始异步读取资源二进制流。
    public override void ReadBytes(IFileSystem fileSystem, string name)
    {
        byte[] bytes = fileSystem.ReadFile(name);
        m_LoadResourceAgentHelperReadBytesCompleteEventHandler(this, LoadResourceAgentHelperReadBytesCompleteEventArgs.Create(bytes));
    }
}

三、后记

如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。


你的点赞就是对博主的支持,有问题记得留言:

博主主页有联系方式。

博主还有跟多宝藏文章等待你的发掘哦:

专栏方向简介
Unity3D开发小游戏小游戏开发教程分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。
Unity3D从入门到进阶入门从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。
Unity3D之UGUIUGUIUnity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。
Unity3D之读取数据文件读取使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。
Unity3D之数据集合数据集合数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。
Unity3D之VR/AR(虚拟仿真)开发虚拟仿真总结博主工作常见的虚拟仿真需求进行案例讲解。
Unity3D之插件插件主要分享在Unity开发中用到的一些插件使用方法,插件介绍等
Unity3D之日常开发日常记录主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等
Unity3D之日常BUG日常记录记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。

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

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

相关文章

代码随想录算法训练营第二十七天(第二十六天休息)|40.组合总和II

40.组合总和II 题目 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 说明&#xff1a; 所有数字&#xff08;包括目标数&#xff09;都是正整数。解集…

Android 开发环境搭建(Android Studio 安装图文详细教程)

Android Studio 下载 https://developer.android.google.cn/studio?hlzh-cn Android Studio 安装 检查电脑是否启用虚拟化 如果没有开启虚拟化&#xff0c;则需要进入电脑的 BIOS 中开启 直接 next选择安装的组件&#xff0c;Android Studio 和 Android 虚拟设备&#xff…

使用蜂鸟地图完成楼层自定义、房间着色、热力图、添加图片覆盖物、添加dom覆盖物、定位到固定区域的中心点

项目里有用到蜂鸟地图的地方&#xff0c;虽然有跟她们对接&#xff0c;但看他们文档也挺费劲的&#xff0c;要自己慢慢研究好久&#xff0c;有些实在研究不出来让他们帮忙看代码发现一些问题&#xff0c;所以把我发现的需要注意的一些点发上来&#xff0c;希望可以帮助到部分有…

深入探讨ChatGPT:技术突破与应用前景

目录 一、ChatGPT究竟是什么&#xff1f; 二、ChatGPT的发展脉络 三、ChatGPT的突出优势 强大的语言生成能力 多场景适应性 多语言处理能力 广泛的应用范围 数据敏感性的重视 四、结语&#xff1a;ChatGPT的未来与挑战 Tips&#xff1a;国内的ChatGPT ⭐ 点击进入Chat…

【GIS系列】GeoTools简介及工具类分享

本文将对GeoTools相关概念进行介绍&#xff0c;同时会给大家分享我工作中用到的工具类及使用方法。 作者&#xff1a;后端小肥肠 目录 1.前言 2. GeoTools简介 3. Geotools使用示例 3.1. 开发环境搭建 3.1.1. 所需版本和工具 3.1.2. pom依赖​​​​​​​ 4. 工具类介绍…

为什么不用 index 做 key 引出的 Diff 算法

文章目录 问题分析 问题 大家耳熟能详的最常见的问题就是 为什么不用 index 做 key &#xff0c;在刚开始学习的时候&#xff0c;只是知道在 v-for 做循环遍历的时候需要加上唯一标识 key&#xff0c;但好像都是这么写的 v-for"(item,index) in dictList" :key"…

IT系统可观测性

什么是可观测性 可观测性&#xff08;Observability&#xff09;是指能够从系统的外部输出推断出系统内部状态的能力。在IT和云计算领域&#xff0c;它涉及使用软件工具和实践来收集、关联和分析分布式应用程序以及运行这些应用程序的硬件和网络产生的性能数据流。这样做可以更…

数据分析-Pandas序列时间移动窗口化操作

数据分析-Pandas序列时间移动窗口化操作 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表…

【考研数学】全年保姆级规划+资料选择

直接跟考研课学即可 跟宋浩学第一遍说是基础&#xff0c;但宋浩的课程毕竟针对的是大学期末考试&#xff0c;基础知识方面讲的可能没有考研课程全面&#xff0c;毕竟大学课程的授课时间和考核要求不同于考研。 备考之前对自己做一个评估&#xff0c;每一个要准备的科目和其中…

代码随想录 动态规划-0-1背包问题

目录 标准0-1背包问题 二维dp数组01背包 一维dp数组01背包&#xff08;滚动数组&#xff09; 416.分割等和子集 1049.最后一块石头的重量|| 494.目标和 474.一和零 背包问题的分类 标准0-1背包问题 46. 携带研究材料&#xff08;第六期模拟笔试&#xff09; 时间限制…

超越传统的极限:解密B树与B+树的数据结构之美!

超越传统的极限&#xff1a;解密B树与B树的数据结构之美&#xff01; B树和B树是在计算机科学中常用的平衡查找树数据结构&#xff0c;它们在处理大规模数据和磁盘存储方面具有重要的优势。本文将深入介绍B树和B树的基本概念、特点以及它们在数据库和文件系统中的应用&#xff…

【德语常识】分类单词

【德语常识】分类单词 一&#xff0c;Colors二&#xff0c;Countries & Languages三&#xff0c; 一&#xff0c;Colors 二&#xff0c;Countries & Languages 三&#xff0c;

JNDI注入原理及利用IDEA漏洞复现

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

VMware虚拟机Centos7硬盘扩容详细图文教程

这里写自定义目录标题 设置扩容空间容量10G为列子开机后输入df -h 查看磁盘空间运行fdisk -l&#xff0c;查看硬盘信息运行fdisk /dev/sda输入m&#xff0c;查看n为add new partition&#xff0c;输入n输入p &#xff0c;p之后的东西都选择为默认再输入t&#xff0c;分区号根据…

洛谷-P1449 后缀表达式

目录 何为后缀表达式&#xff1f; 模拟过程 AC代码 采用STL的stack 题目链接&#xff1a;P1449 后缀表达式 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 何为后缀表达式&#xff1f; 那后缀表达式是怎么算的呢 那显然就需要引用最开始说的栈了 因为后缀表表达式本来就是栈…

HTML5+CSS3+JS小实例:全屏范围滑块

实例:全屏范围滑块 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale…

零延迟轻量级网站指纹防御

文章信息 论文题目&#xff1a;Zero-delay Lightweight Defenses against Website Fingerprinting 期刊&#xff08;会议&#xff09;&#xff1a; 29th USENIX Security Symposium 时间&#xff1a;2020 级别&#xff1a;CCF A 文章链接&#xff1a;https://www.usenix.org/s…

PHP反序列化---字符串逃逸(增加/减少)

一、PHP反序列化逃逸--增加&#xff1a; 首先分析源码&#xff1a; <?php highlight_file(__FILE__); error_reporting(0); class A{public $v1 ls;public $v2 123;public function __construct($arga,$argc){$this->v1 $arga;$this->v2 $argc;} } $a $_GET[v…

一文了解如何做全基因集GSEA富集分析

原文链接:一文完成全基因集GSEA富集分析 本期内容 写在前面 我们前面分享过一文掌握单基因GSEA富集分析的教程,主要使用单基因的角度进行GSEA富集分析。 我们社群的同学咨询,全基因集的GSEA如何分析呢??其实,原理都是大同小异的,那么今天我们就简单的整理一下吧。 若…

PyTorch学习笔记之激活函数篇(二)

文章目录 2、Tanh函数2.1 公式2.2 对应的图像2.3 对应生成图像代码2.4 优点与不足2.5 torch.tanh()函数 2、Tanh函数 2.1 公式 Tanh函数的公式&#xff1a; f ( x ) e x − e − x e x e − x f(x)\frac{e^x-e^{-x}}{e^xe^{-x}} f(x)exe−xex−e−x​ Tanh函数的导函数&am…