2019-11-13 17:47:42 qq_42194657 阅读数 23

使用WWW功能,除了能够下载图片,还能下载声音,方法与下载图片类似,下面是一个简单的实例:

1.在网站的根目录放置一个声音文件Alarm01.wav(这个是window系统自带的找不到这个格式的可以直接在C盘搜索)

2.在WebManager.cs脚本中添加clipPath、audio、m_downloadClip属性和DownloadSound()函数:


    #region 声音下载

    string clipPath = "http://127.0.0.1:8088/Alarm01.wav";

    protected AudioClip m_downloadClip;

    AudioSource audio;
    #endregion

 IEnumerator DownloadSound()
    {
        WWW www = new WWW(clipPath);

        yield return www;

        if (www.error != null)
        {
            m_info = www.error;
            yield return null;
        }

        m_downloadClip = www.GetAudioClip(true,true,AudioType.WAV);
        audio.clip = m_downloadClip;
        audio.Play();
    }

3.在脚本挂载的游戏对象身上添加一个AudioSouce组件

4.在Awake函数中执行DownloadSound()函数并找到Audiosource组件

    private void Awake()
    {
        audio = GetComponent<AudioSource>();
        StartCoroutine(DownloadSound());
    }

注意:

这里的www.GetAudioClip(true,true,AudioType.WAV)的最后一个需要修改格式,在window平台下不支持直接读取MP3的音频文件,通常MP3文件我们会放在Unity的工程内打包处理,wav格式的通常是录音文件等。

2019-04-29 21:08:00 weixin_33797791 阅读数 109

Unity3D PC平台本身是支持直接用www读取本地ogg,wav的,但是并不能读取byte[],字节数组格式,这对用习惯了bass,fmod的人来说有点不方便。

搜了一圈发现了一个C#的音频库叫NAudio,开源并且免费。

https://archive.codeplex.com/?p=naudio

https://github.com/naudio/NAudio

简单粗暴的搞一份二进制release,然后nuget一下ogg扩展

Install-Package NAudio.Vorbis  

使用方面参考了下面3个地址

https://blog.csdn.net/qq992817263/article/details/54647741

https://gamedev.stackexchange.com/questions/114885/how-do-i-play-mp3-files-in-unity-standalone

https://stackoverflow.com/questions/24624939/using-vorbis-and-naudio-to-play-ogg-files

简单来说新建一个NAudioPlayer.cs文件,内容如下

using UnityEngine;
using System.IO;
using System;
using NAudio;
using NAudio.Wave;

public static class NAudioPlayer
{
    static NVorbis.VorbisReader vorbis;
    public static AudioClip FromOggData(byte[] data)
    {
        // Load the data into a stream
        MemoryStream oggstream = new MemoryStream(data);

        vorbis = new NVorbis.VorbisReader(oggstream, false);

        int samplecount = (int)(vorbis.SampleRate * vorbis.TotalTime.TotalSeconds);

        //  AudioClip audioClip = AudioClip.Create("clip", samplecount, vorbis.Channels, vorbis.SampleRate, false, true, OnAudioRead, OnAudioSetPosition);
        AudioClip audioClip = AudioClip.Create("ogg clip", samplecount, vorbis.Channels, vorbis.SampleRate, false, OnAudioRead);
        // Return the clip
        return audioClip;
    }
    static void OnAudioRead(float[] data)
    {
        var f = new float[data.Length];
        vorbis.ReadSamples(f, 0, data.Length);
        for (int i = 0; i < data.Length; i++)
        {
            data[i] = f[i];
        }
    }
    static void OnAudioSetPosition(int newPosition)
    {
        vorbis.DecodedTime = new TimeSpan(newPosition); //Only used to rewind the stream, we won't be seeking
    }
    public static AudioClip FromWavData(byte[] data)
    {
        WAV wav = new WAV(data);
        AudioClip audioClip = AudioClip.Create("wavClip", wav.SampleCount, 1, wav.Frequency, false);
        audioClip.SetData(wav.LeftChannel, 0);
        return audioClip;
    }
    public static AudioClip FromMp3Data(byte[] data)
    {
        // Load the data into a stream
        MemoryStream mp3stream = new MemoryStream(data);
        // Convert the data in the stream to WAV format
        Mp3FileReader mp3audio = new Mp3FileReader(mp3stream);
        WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(mp3audio);
        // Convert to WAV data
        WAV wav = new WAV(AudioMemStream(waveStream).ToArray());
        Debug.Log(wav);
        AudioClip audioClip = AudioClip.Create("mp3Clip", wav.SampleCount, 1, wav.Frequency, false);
        audioClip.SetData(wav.LeftChannel, 0);
        // Return the clip
        return audioClip;
    }

    private static MemoryStream AudioMemStream(WaveStream waveStream)
    {
        MemoryStream outputStream = new MemoryStream();
        using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
        {
            byte[] bytes = new byte[waveStream.Length];
            waveStream.Position = 0;
            waveStream.Read(bytes, 0, Convert.ToInt32(waveStream.Length));
            waveFileWriter.Write(bytes, 0, bytes.Length);
            waveFileWriter.Flush();
        }
        return outputStream;
    }
}

/* From http://answers.unity3d.com/questions/737002/wav-byte-to-audioclip.html */
public class WAV
{

    // convert two bytes to one float in the range -1 to 1
    static float bytesToFloat(byte firstByte, byte secondByte)
    {
        // convert two bytes to one short (little endian)
        short s = (short)((secondByte << 8) | firstByte);
        // convert to range from -1 to (just below) 1
        return s / 32768.0F;
    }

    static int bytesToInt(byte[] bytes, int offset = 0)
    {
        int value = 0;
        for (int i = 0; i < 4; i++)
        {
            value |= ((int)bytes[offset + i]) << (i * 8);
        }
        return value;
    }
    // properties
    public float[] LeftChannel { get; internal set; }
    public float[] RightChannel { get; internal set; }
    public int ChannelCount { get; internal set; }
    public int SampleCount { get; internal set; }
    public int Frequency { get; internal set; }

    public WAV(byte[] wav)
    {

        // Determine if mono or stereo
        ChannelCount = wav[22];     // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels

        // Get the frequency
        Frequency = bytesToInt(wav, 24);

        // Get past all the other sub chunks to get to the data subchunk:
        int pos = 12;   // First Subchunk ID from 12 to 16

        // Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal))
        while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97))
        {
            pos += 4;
            int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;
            pos += 4 + chunkSize;
        }
        pos += 8;

        // Pos is now positioned to start of actual sound data.
        SampleCount = (wav.Length - pos) / 2;     // 2 bytes per sample (16 bit sound mono)
        if (ChannelCount == 2) SampleCount /= 2;        // 4 bytes per sample (16 bit stereo)

        // Allocate memory (right will be null if only mono sound)
        LeftChannel = new float[SampleCount];
        if (ChannelCount == 2) RightChannel = new float[SampleCount];
        else RightChannel = null;

        // Write to double array/s:
        int i = 0;
        int maxInput = wav.Length - (RightChannel == null ? 1 : 3);
        // while (pos < wav.Length)
        while ((i < SampleCount) && (pos < maxInput))
        {
            LeftChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
            pos += 2;
            if (ChannelCount == 2)
            {
                RightChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
                pos += 2;
            }
            i++;
        }
    }

    public override string ToString()
    {
        return string.Format("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3}, Frequency={4}]", LeftChannel,
    RightChannel, ChannelCount, SampleCount, Frequency);
    }
}

再挂个AudioSource,简单粗暴读取文件,解码变为byte[]填充进AudioClip,播放即可

void PlayOGG()
{
    string path = Application.dataPath + "/../Audio/Music/a.ogg";
    byte[] data = File.ReadAllBytes(path);
    audioSource.clip = NAudioPlayer.FromOggData(data);
    audioSource.Play();
}
void PlayMP3()
{
    string path = Application.dataPath + "/../Audio/Music/a.mp3";
    byte[] data = File.ReadAllBytes(path);
    audioSource.clip = NAudioPlayer.FromMp3Data(data);
    audioSource.Play();
}
void PlayWAV()
{
    string path = Application.dataPath + "/../Audio/Music/a.wav";
    byte[] data = File.ReadAllBytes(path);
    audioSource.clip = NAudioPlayer.FromWavData(data);
    audioSource.Play();
}

 

转载于:https://www.cnblogs.com/kileyi/p/10792893.html

2018-02-04 07:30:51 weixin_39673686 阅读数 526

最近在做final year project,我有一个服务器,上面的文件下载下来之后会存放在c盘的默认路径里。然后我要把里面的音频文件读取出来,每个mp3文件做一个button ,用来控制播放。

//This script allows you to toggle music to play and stop.
//Assign an AudioSource to a GameObject and attach an Audio Clip in the Audio Source. Attach this script to the GameObject.

using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class MusicPlayer : MonoBehaviour
{
    public AudioSource Sound ;
    int playing = 1;
    int pause = 2;
    int stop = 3;
    public int state = 3;
    
    public void Setup(string Description) {
        StartCoroutine(wwwDownload(Description));
    }
    System.Collections.IEnumerator wwwDownload(string Description) {
        WWW www = new WWW("file://" + Path.Combine(Application.persistentDataPath, SceneTools.AreaNameDefault() + "//" + Description));
        yield return www;


        AudioClip clip = www.GetAudioClip();
        //clip = www.GetAudioClip(false,false,AudioType.MPEG);
        clip = www.GetAudioClip(false, false, AudioType.MPEG);
        clip.name = Description;
        GameObject prefeb_Sound = GameObject.Find("Audio Source");
        GameObject ob = GameObject.Instantiate<GameObject>(prefeb_Sound, new Vector3(0, 0, 0), Quaternion.identity);
        ob.name = "file:" + Description;
        ob.GetComponent<AudioSource>().clip = clip;
        Sound = ob.GetComponent<AudioSource>();
    }
    public void Play()
    {
        Sound.Play();
        state = playing;
    }
    public void PauseAudio() {
        Sound.Pause();
        state = pause;
    }
    public void StopAudio()
    {
        Sound.Stop();
        state = stop;
    }
    public void RestartAudio()
    {
        Sound.Stop();
        Sound.Play();
        state = playing;
    }

}
关键的一点是www 请求网上或本地资源,需要单独写一个函数,是
System.Collections.IEnumerator wwwDownload(string Description) 
这个函数。IEnumerator类型,作为多线程启动函数的参数。

在里面,我们首先处理www加载,其次是利用加载的文件做进一步编程,比如我就把clip 放在新生成的audiosource上面。然后利用

StartCoroutine(wwwDownload(Description));
开始一个新的线程来执行这个函数。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour {
    private MusicPlayer music;
    //spublic Button yourButton;
    public GameObject AudioCanvas = null;
    public GameObject buttonPrefeb;
    private GameObject newButton = null;
    private bool getName = false;
    private bool setUp = false;
    private String AudioName = "";
    int playing = 1;
    int pause = 2;
    int stop = 3;
    
    public void sendAudioName(String description) {
        AudioName = description;
        getName = true;
    }
    void Start()
    {
        if (this.transform.parent != null) { 
            Debug.Log(this.transform.parent.name);
            AudioCanvas = this.transform.parent.GetChild(this.transform.parent.childCount - 1 ).gameObject;
            newButton = Instantiate(buttonPrefeb) as GameObject;
            newButton.transform.SetParent(AudioCanvas.transform, false);
            music = (GetComponent("MusicPlayer") as MusicPlayer);//获取播放器对象
            if (getName) { 
                music.Setup(AudioName);
                setUp = true;
            }
            Button btn = newButton.GetComponent<Button>();
            //newButton.transform.position = new Vector3(0, 0, 0);
            Debug.Log(newButton.GetComponent<RectTransform>().localPosition);
            newButton.GetComponent<RectTransform>().localPosition = new Vector3(0, 0, 0);
            btn.onClick.AddListener(TaskOnClick);
            newButton.GetComponentInChildren<Text>().text = this.transform.parent.name + " Play >";
        }
    }
     void Update()
    {
        if (getName && !setUp)
        {
            music.Setup(AudioName);
            setUp = true; 

        }
    }
    void TaskOnClick()
    {

        // Debug.Log("AudioName  " + AudioName);
        // Debug.Log("Play"+music.Sound.clip.name);
        // Debug.Log("isPlaying" + music.Sound.isPlaying+music.Sound.isActiveAndEnabled);
        // GameObject musicOb = GameObject.Find("file:" + AudioName);
        //musicOb.GetComponent<AudioSource>().Play();
        // Debug.Log("musicOb" + musicOb.GetComponent<AudioSource>().clip.name + musicOb.GetComponent<AudioSource>().isActiveAndEnabled);
        //music.Play();
        Text textOnbutton = newButton.transform.GetChild(0).gameObject.GetComponent<Text>();
        if (music.Sound.isPlaying == false)
        {
            music.Play();
            if (music.state == playing)
                textOnbutton.text = this.transform.parent.name + "- Pause";

        }

        else
        {
            music.PauseAudio();
            if (music.state == pause)
                textOnbutton.text = this.transform.parent.name + "- Play";
        }
    }

    //void OnGUI()
    //{

    //    if (music.state == stop || music.state == pause)
    //    {
    //        if (GUI.Button(new Rect(10, 10, 100, 50), "PLAY"))
    //        {

    //            Debug.Log("Play!");
    //            music.Play();//调用播放器Play方法

    //        }
    //        if (music.state == pause)
    //            if (GUI.Button(new Rect(120, 10, 100, 50), "Stop"))
    //            {

    //                Debug.Log("Stop!");
    //                music.StopAudio();

    //            }

    //    }
    //    else if (music.state == playing) {
    //        if (GUI.Button(new Rect(10, 10, 100, 50), "PAUSE"))
    //        {

    //            Debug.Log("Pause!");
    //            music.PauseAudio();

    //        }
    //        if (GUI.Button(new Rect(120, 10, 100, 50), "Stop"))
    //        {

    //            Debug.Log("Stop!");
    //            music.StopAudio();

    //        }

    //    }


    //}

}
 music = (GetComponent("MusicPlayer") as MusicPlayer);//获取播放器对
我们首先要创建一个空物体,把两个脚本放上去,然后问题来了,两个脚本都是mono的,怎么才能传递参数呢。

关键就是利用getcomponent函数获取脚本,然后调用脚本的函数,貌似不可以直接修改脚本的属性,有兴趣的可以自己试试。

然后可以用ongui来设置屏幕上的gui按钮并判断是否按下按钮,也可以利用canvas新建一个新的画布再加上button,

btn.onClick.AddListener(TaskOnClick);
利用这行代码给button绑定一个函数,一般是控制音乐播放的。


大家看我的代码就好,如果有问题可以留言。

2016-06-15 11:07:04 linxinfa 阅读数 24322

Application.dataPath

Application.streamingAssetsPath

Application.persistentDataPath

Application.temporaryCachePath 

在个平台下的具体路径如下:

  Application.dataPath Application.streamingAssetsPath Application.persistentDataPath Application.temporaryCachePath 
iOS Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches
Android /data/app/xxx.xxx.xxx.apk jar:file:///data/app/xxx.xxx.xxx.apk/!/assets /data/data/xxx.xxx.xxx/files /data/data/xxx.xxx.xxx/cache
Windows /Assets /Assets/StreamingAssets C:/Users/xxxx/AppData/LocalLow/CompanyName/ProductName C:/Users/xxxx/AppData/Local/Temp/CompanyName/ProductName
Mac /Assets /Assets/StreamingAssets /Users/xxxx/Library/Caches/CompanyName/Product Name /var/folders/57/6b4_9w8113x2fsmzx_yhrhvh0000gn/T/CompanyName/Product Name
Windows Web Player file:///D:/MyGame/WebPlayer (即导包后保存的文件夹,html文件所在文件夹)      

  • Resources

Resources文件夹是一个只读的文件夹,通过Resources.Load()来读取对象。因为这个文件夹下的所有资源都可以运行时来加载,所以Resources文件夹下的所有东西都会被无条件的打到发布包中。建议这个文件夹下只放Prefab或者一些Object对象,因为Prefab会自动过滤掉对象上不需要的资源。举个例子我把模型文件还有贴图文件都放在了Resources文件夹下,但是我有两张贴图是没有在模型上用的,那么此时这两张没用的贴图也会被打包到发布包中。假如这里我用Prefab,那么Prefab会自动过滤到这两张不被用的贴图,这样发布包就会小一些了。 

  • StreamingAssets

StreamingAssets文件夹也是一个只读的文件夹,但是它和Resources有点区别,Resources文件夹下的资源会进行一次压缩,而且也会加密,不使用点特殊办法是拿不到原始资源的。但是StreamingAssets文件夹就下面的所有资源不会被加密,是原封不动的打包到发布包中,这样很容易就拿到里面的文件。所以StreamingAssets适合放一些二进制文件,而Resources更适合放一些GameObject和Object文件。 StreamingAssets 只能用过www类来读取!!

 

StreamingAssets在不同的平台上面 (Windows, iOS ,Android),该目录最终发布的位置不同,所以读取的方法也不同。

  windows iOS Android
IO读取路径 Application.StreamingAssetPath+"/myfile.txt" Application.StreamingAssetPath+"/myfile.txt" 不支持
WWW读取路径 "file://"+Application.StreamingAssetPath+"/myfile.txt" "file://"+Application.StreamingAssetPath+"/myfile.txt" Application.StreamingAssetPath+"/myfile.txt"

 

WWW是异步加载所以执行加载命令式不能直接执行读取解析操作,

要等待

WWW www = new WWW(filePath);

yield return www; // while (!www.isDone) {}

result = www.text;


Android之所以不支持C# IO流 方式读取StreamingAssets下的文件,是因为Android手机中,StreamingAssets下的文件都包含在压缩的.jar文件中(这基本上与标准的zip压缩文件的格式相同)。不能直接用读取文件的函数去读,而要用WWW方式。具体做法如下: 
1.把你要读取的文件放在Unity项目的Assets/StreamingAssets文件夹下面,没有这个文件夹的话自己建一个。 
2.读取的代码(假设名为"文件.txt") 

//用来存储读入的数据
byte[] bytes;       
//判断当前程序是否运行在安卓下                                                                                                   
if (Application.platform == RuntimePlatform.Android)                                            
{ 
    
    string fpath= "jar:file://" + Application.dataPath + "!/assets/" + "文件.txt"; 
    //等价于string fpath = Application.StreamingAssetPath+"/文件.txt"; 
    
    WWW www = new WWW(fpath);                                                                
    //WWW是异步读取,所以要用循环来等待 
    while(!www.isDone){}                                                                       
    //存到字节数组里 
    bytes= www.bytes;                                                                           
    

} 
else 
{ 
    //其他平台的读取代码 
}

------------------------------------------------------------------------------------------------------------------------------
补充:

各目录权限:

  • StreamingAssets文件夹(只读)
#if UNITY_EDITOR
string filepath = Application.dataPath +"/StreamingAssets"+"/my.xml";
#elif UNITY_IOS
 string filepath = Application.dataPath +"/Raw"+"/my.xml";
#elif UNITY_ANDROID
 string filepath = "jar:file://" + Application.dataPath + "!/assets/"+"/my.xml;
#endif
  • Resources文件夹(只读)

可以使用Resources.Load("名字"); 把文件夹中的对象加载出来

  • Application.dataPath文件夹(只读)

可以使用Application.dataPath进行读操作

Application.dataPath: 只可读不可写,放置一些资源数据

  • Application.persistentDataPath文件夹(读写)

IOS与android平台都可以使用这个目录下进行读写操作,可以存放各种配置文件进行修改之类的。

在PC上的地址是:C:\Users\用户名 \AppData\LocalLow\DefaultCompany\test


总结:

一. 在项目根目录中创建Resources文件夹来保存文件。
可以使用Resources.Load("文件名字,注:不包括文件后缀名");把文件夹中的对象加载出来。
注:此方可实现对文件实施“增删查改”等操作,但打包后不可以更改了

二. 直接放在项目根路径下来保存文件
在直接使用Application.dataPath来读取文件进行操作。
注:移动端是没有访问权限的。

三. 在项目根目录中创建StreamingAssets文件夹来保存文件。
1.可使用Application.dataPath来读取文件进行操作。

#if UNITY_EDITOR
string filepath = Application.dataPath +"/StreamingAssets"+"/my.xml";
#elif UNITY_IPHONE
 string filepath = Application.dataPath +"/Raw"+"/my.xml";
#elif UNITY_ANDROID
 string filepath = "jar:file://" + Application.dataPath + "!/assets/"+"/my.xml;
#endif

 

2.直接使用Application.streamingAssetsPath来读取文件进行操作。
注:此方法在pc/Mac电脑中可实现对文件实施“增删查改”等操作,但在移动端只支持读取操作。

四. 使用Application.persistentDataPath来操作文件
该文件存在手机沙盒中,因为不能直接存放文件,
1.通过服务器直接下载保存到该位置,也可以通过Md5码比对下载更新新的资源
2.没有服务器的,只有间接通过文件流的方式从本地读取并写入Application.persistentDataPath文件下,然后再通过Application.persistentDataPath来读取操作。
注:在Pc/Mac电脑 以及Android跟Ipad、ipone都可对文件进行任意操作,另外在IOS上该目录下的东西可以被iCloud自动备份

 

 

 

 

 

 

2019-03-05 20:12:32 Czhenya 阅读数 1302

dataPath :返回程序的数据文件所在的文件夹的路径(只读)。返回路径为相对路径,一般是相对于程序安装目录的位置。不同游戏平台的数据文件保存路径不同。

StreamingAssetsPath: 此属性用于返回数据流的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径。(只读)

PersistentDataPath:返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。对应同一平台,在不同程序中调用此属性时,其返回值是相同的,但是在不同的运行平台下,其返回值会不一样。

temporaryCachePath:此属性用于返回一个临时数据的缓冲目录(只读)。对于同一平台,在不同程序中调用此属性时,其返回值是相同的,但是在不同的运行平台下,其返回值是不一样的。

persistentDataPathtemporaryCachePath的返回值一般是程序所在平台的固定位置,适合程序在运行过程中产生的数据文件。


网图
(网图)

参考链接:http://tieba.baidu.com/p/3309230088

PC:

Application.dataPath : /Assets

Application.streamingAssetsPath : /Assets/StreamingAssets

Application.persistentDataPath : C:/Users/xxxx/AppData/LocalLow/CompanyName/ProductName

Application.temporaryCachePath : C:/Users/xxxx/AppData/Local/Temp/CompanyName/ProductName


Android:

Application.dataPath : /data/app/xxx.xxx.xxx.apk

Application.streamingAssetsPath : jar:file:///data/app/xxx.xxx.xxx.apk/!/assets

Application.persistentDataPath : /data/data/xxx.xxx.xxx/files

Application.temporaryCachePath : /data/data/xxx.xxx.xxx/cache


IOS:

Application.dataPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data

Application.streamingAssetsPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw

Application.persistentDataPath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents

Application.temporaryCachePath : Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches


Mac:

Application.dataPath : /Assets

Application.streamingAssetsPath : /Assets/StreamingAssets

Application.persistentDataPath : /Users/xxxx/Library/Caches/CompanyName/Product Name

Application.temporaryCachePath : /var/folders/57/6b4_9w8113x2fsmzx_yhrhvh0000gn/T/CompanyName/Product Name

C#获取U盘序列号

阅读数 46

没有更多推荐了,返回首页