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

2024-03-19 02:12

本文主要是介绍【GameFramework框架内置模块】8、文件系统(File System),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

推荐阅读

  • 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 来消除 GCAllocbool 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 : EditorWindowprivate 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和坑,让后来人可以有些参考。

这篇关于【GameFramework框架内置模块】8、文件系统(File System)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/824458

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

数据治理框架-ISO数据治理标准

引言 "数据治理"并不是一个新的概念,国内外有很多组织专注于数据治理理论和实践的研究。目前国际上,主要的数据治理框架有ISO数据治理标准、GDI数据治理框架、DAMA数据治理管理框架等。 ISO数据治理标准 改标准阐述了数据治理的标准、基本原则和数据治理模型,是一套完整的数据治理方法论。 ISO/IEC 38505标准的数据治理方法论的核心内容如下: 数据治理的目标:促进组织高效、合理地

ZooKeeper 中的 Curator 框架解析

Apache ZooKeeper 是一个为分布式应用提供一致性服务的软件。它提供了诸如配置管理、分布式同步、组服务等功能。在使用 ZooKeeper 时,Curator 是一个非常流行的客户端库,它简化了 ZooKeeper 的使用,提供了高级的抽象和丰富的工具。本文将详细介绍 Curator 框架,包括它的设计哲学、核心组件以及如何使用 Curator 来简化 ZooKeeper 的操作。 1

【Kubernetes】K8s 的安全框架和用户认证

K8s 的安全框架和用户认证 1.Kubernetes 的安全框架1.1 认证:Authentication1.2 鉴权:Authorization1.3 准入控制:Admission Control 2.Kubernetes 的用户认证2.1 Kubernetes 的用户认证方式2.2 配置 Kubernetes 集群使用密码认证 Kubernetes 作为一个分布式的虚拟

Spring Framework系统框架

序号表示的是学习顺序 IoC(控制反转)/DI(依赖注入): ioc:思想上是控制反转,spring提供了一个容器,称为IOC容器,用它来充当IOC思想中的外部。 我的理解就是spring把这些对象集中管理,放在容器中,这个容器就叫Ioc这些对象统称为Bean 用对象的时候不用new,直接外部提供(bean) 当外部的对象有关系的时候,IOC给它俩绑好(DI) DI和IO

Jenkins构建Maven聚合工程,指定构建子模块

一、设置单独编译构建子模块 配置: 1、Root POM指向父pom.xml 2、Goals and options指定构建模块的参数: mvn -pl project1/project1-son -am clean package 单独构建project1-son项目以及它所依赖的其它项目。 说明: mvn clean package -pl 父级模块名/子模块名 -am参数

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类