将文件写入名称递增的路径

时间:2017-05-16 09:05:51

标签: c# file unity3d

Unity3D脚本中,我有以下内容,只是将文件(图像)写入路径:

var path = Application.persistentDataPath + "/ocr.jpg";
FileOperations.Create(blah, path);

当然在其他地方的static实用程序中,我已经实现了这个辅助函数,如下所示:

public static void Create(byte[] bytes, string path)
{
    var file = File.Open(path, FileMode.Create);

    using ( var binary = new BinaryWriter(file) )
    {
        binary.Write(bytes);
        file.Close();
    }
}

我意识到我的实现只会创建一个文件;即覆盖具有相同名称(ocr.jpg)的现有文件,因此我编写了以下代码:

public static void Create(byte[] bytes, string path)
{
    if ( !File.Exists(path) )
    {
        var file = File.Open(path, FileMode.Create);

        using ( var binary = new BinaryWriter(file) )
        {
            binary.Write(bytes);
            file.Close();
        }
    }
    else
    {                                                       
        int counter = 1;
        path = Application.persistentDataPath + "/ocr" + "_" + counter + ".jpg";

        var file = File.Open(path, FileMode.Create);

        using ( var binary = new BinaryWriter(file) )
        {
            binary.Write(bytes);
            file.Close();
        }
    }
}

然后,我意识到每次运行应用时,counter都会重新设置为1,所以现在我的ocr_1.jpg被覆盖了!

(没关系,这个半解决方案已经很丑陋,因为它带来了一些特定于Unity的东西。我希望不要在我的帮助器实用程序类中包含using UnityEngine。)

接下来,我尝试以递归方式执行此操作,如下所示:

public static void Create(byte[] bytes, string path)
{
    if ( !File.Exists(path) )
    {
        var file = File.Open(path, FileMode.Create);

        using ( var binary = new BinaryWriter(file) )
        {
            binary.Write(bytes);
            file.Close();
        }
    }
    else
    {                                                       
        int counter = 1;
        path = Application.persistentDataPath + "/ocr" + "_" + counter + ".jpg";

        Create(bytes, path);
    }
}

但是我收到了StackOverFlow错误消息。我不明白为什么,因为检查应该继续,直到没有相同名称的文件等...

有人可以帮助我了解我做错了什么,以及如何实现我的目标,即根据需要多次运行应用并按顺序创建图像:ocr.jpgocr_1.jpgocr_2.jpgocr_3.jpg等等......

另外,如果我发现如何以我的实用程序类不必包含与统一相关的东西的方式来做这件事,那将会很棒。即只有using System.IO

3 个答案:

答案 0 :(得分:2)

In case you pass in a path that already exists and

path = Application.persistentDataPath + "/ocr" + "_" + counter + ".jpg";

also exists, you keep on calling Create method without incrementing counter, hence stack overflow. Consider passing counter value to the recursive create method, and updating it in every iteration, until it hits a filename that doesn't exist.

答案 1 :(得分:2)

您获得StackOverflow的原因是填充方法Call Stack。在您的代码中,counter变量是方法的局部变量,永远不会递增。因此,每次对Create方法进行递归调用时,都会进行相同的调用(参数方式)。

作为高级解决方案,您应该做两件事:

  • 在整个递归调用中跟踪counter的值
  • 确保在每次递归调用Create
  • 时递增计数器的值

您可以通过将counter变量作为全局变量(有时不是一个好主意)或将其作为Create方法参数的一部分来跟踪document.body.style.zoom = 2.0;变量的状态。

答案 2 :(得分:1)

  

我希望不在我的帮助程序实用程序中包含using UnityEngine   类

你不必。您可以使用包含其命名空间的完全限定名称:

UnityEngine.Application.persistentDataPath

很少有人知道:

1 。在读取或写入文件时始终捕获异常。

2 。不要这样做:Application.persistentDataPath + "/ocr" + "_" + counter + ".jpg";

将文件名与“+”连接起来不是一个好主意,因为可跨平台移植。请使用Path.Combine

以下是我将如何实现这一点:

使用PlayerPrefs.SetInt保存计数器。每次要保存图像时,使用PlayerPrefs.GetInt读取计数器,然后使用File.WriteAllBytes保存图像。如果保存成功,请递增计数器,然后使用PlayerPrefs.SetInt保存。

大致如下:

public static void Create(byte[] dataToSave)
{
    //Load old counter
    int counter = PlayerPrefs.GetInt("_counter_", 0);

    //Concatenate file name
    string tempPath = Path.Combine(UnityEngine.Application.persistentDataPath, "ocr");
    tempPath = Path.Combine(tempPath, "_");
    tempPath = Path.Combine(tempPath, counter.ToString() + ".jpg");

    //Create Directory if it does not exist
    if (!Directory.Exists(Path.GetDirectoryName(tempPath)))
    {
        Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
    }
    //Debug.Log(path);

    try
    {
        File.WriteAllBytes(tempPath, dataToSave);
        Debug.Log("Saved Data to: " + tempPath.Replace("/", "\\"));

        //Increment Counter
        counter++;

        //Save current Counter
        PlayerPrefs.SetInt("_counter_", counter);
        PlayerPrefs.Save();
    }
    catch (Exception e)
    {
        Debug.LogWarning("Failed To PlayerInfo Data to: " + tempPath.Replace("/", "\\"));
        Debug.LogWarning("Error: " + e.Message);
    }
}