Problem in overwriting Application.persistentDataPath - c#

I have a JSON file which contains data for my Localization in my game. The file is stored in Application.persistentDataPath . I read in the documentation that the file is not deleted or overwritten when updating the game. Currently I launch the app and the file is there but when I add more content and send an update to save again, it only has the original content.
But is there a way to update this file when I update the game?
What if in the future I want to add more content to this JSON file, I would have to delete it and upload it again?
Any way to update and overwrite it?
private static void Request(string file)
{
var loadingRequest = UnityWebRequest.Get(Path.Combine(Application.streamingAssetsPath, file));
loadingRequest.SendWebRequest();
while (!loadingRequest.isDone)
{
if (loadingRequest.isNetworkError || loadingRequest.isHttpError)
{
break;
}
}
if (loadingRequest.isNetworkError || loadingRequest.isHttpError)
{
// Some error happened.
}
else
{
File.WriteAllBytes(Path.Combine(Application.persistentDataPath, file), loadingRequest.downloadHandler.data);
}
}
// Loads key from "StreamingAssets/language_data.json" file.
public static string LoadJson(string key)
{
Request("data.json");
var jsonPath = Path.Combine(Application.persistentDataPath, jsonFileName);
using (StreamReader r = new StreamReader(jsonPath))
{
var N = JSON.Parse(r.ReadToEnd());
string result = N[GetLanguage()][key];
return result;
}
}

I think the issue is the following:
You are only creating a file named data.json NOT languages_data.json!
In Request (you pass in "data.json") you copy
Application.streamingAssetsPath, file
to
Application.persistentDataPath, file
where file = "data.json"
Then in LoadJson you are trying to load values from
Application.persistentDataPath, jsonFileName
where - as to your comments - jsonFileName = "languages_data.json"
=> It is a different path!
In the Editor/on your PC you probably still have an old languages_data.json in the persistent data from some time ago. Therefore there is no error but it is also never updated. Delete the persistent/languages_data.json on your PC and it will throw a FileNotFoundException.
To solve this make 100% sure the file names are the same everywhere. The simplest fix code wise would be to simply rather use
Request(jsonFileName);
and make sure that jsonFileName matches the name of your existing file in StreamingAssets.

Related

Store and read csv file from android and ios in Unity

I have a Unity project which I want to work for both android and ios. I also have a csv file which I want to read during runtime. I tried the following code:
string basePath = Path.Combine(Application.persistentDataPath, $"{fileName}.csv");
if (File.Exists(basePath))
{
string[] rows = File.ReadAllLines(basePath);
foreach (string item in rows)
{
Debug.Log(item);
}
}
However, I don't know where to put the csv file for it to find it on persistentDataPath. And if I find the correct place, will it be the same on android and ios or do I need to save the file on more locations or folders?
Or do you have any other suggestions on how to store and then load a cvs for different platforms?
If you just want to read a .csv file that you deploy with your game, you could just place it into the Resources folders inside your Assets.
You could read it like this:
TextAsset file = Resources.Load(fileName) as TextAsset;
string content = file.ToString();
Note: fileName must be specified here without file extension.
If you want to modify the .csv file or perhaps make it available in Application.persistentDataPath, you can simply copy it to that location first. For later changes you can then access the file in persistentDataPath.
Self-Contained Example
A self-contained example could look something like this:
using System.IO;
using UnityEngine;
public class CSVFileManager : MonoBehaviour
{
void Start()
{
var fileName = "example";
var csvFileName = $"{fileName}.csv";
string basePath = Path.Combine(Application.persistentDataPath, csvFileName);
Debug.Log($"basePath = >>{basePath}<<");
if (!File.Exists(basePath))
{
TextAsset file = Resources.Load(fileName) as TextAsset;
string content = file.ToString();
File.WriteAllText(basePath, content);
}
else
{
//... work with the current file in persistentDataPath
}
}
}
Test
I tested it briefly on Mac, but it should work equally well on Android and iOS:

Securing Temporary Files in C#

When working with an application on C# I am creating a few temporary files using the following logic:
Creating Temp File
private static string CreateTmpFile()
{
string fileName = string.Empty;
try
{
// Get the full name of the newly created Temporary file.
// Note that the GetTempFileName() method actually creates
// a 0-byte file and returns the name of the created file.
fileName = Path.GetTempFileName();
// Craete a FileInfo object to set the file's attributes
FileInfo fileInfo = new FileInfo(fileName);
// Set the Attribute property of this file to Temporary.
// Although this is not completely necessary, the .NET Framework is able
// to optimize the use of Temporary files by keeping them cached in memory.
fileInfo.Attributes = FileAttributes.Temporary;
Console.WriteLine("TEMP file created at: " + fileName);
}
catch (Exception ex)
{
Console.WriteLine("Unable to create TEMP file or set its attributes: " + ex.Message);
}
return fileName;
}
Writing to Temp File
private static void UpdateTmpFile(string tmpFile)
{
try
{
// Write to the temp file.
StreamWriter streamWriter = File.AppendText(tmpFile);
streamWriter.WriteLine("Hello from www.daveoncsharp.com!");
streamWriter.Flush();
streamWriter.Close();
Console.WriteLine("TEMP file updated.");
}
catch (Exception ex)
{
Console.WriteLine("Error writing to TEMP file: " + ex.Message);
}
}
I have also tried and followed some of the implementations found on this link for another question
and am using the following implementations in my code : Storing the file in the AppData Folder for using the ACL
However I have been asked to make sure that :
The temp files cannot be read by anyone(Not even the user) during application runtime,
And to make sure that they are deleted even when force closing the
application
For case 1: The temp files cannot be read by anyone(Not even the user) during application runtime,
How can I implement this for my application files? The temp files contain sensitive data which should not be readable even if the user themselves would like to read. Is there a way I can do that?
For case 2: To make sure that they are deleted even when force closing the
application
Here I would like to make sure than even with force close or a sudden restart the files are deleted.
If Force close: then delete the files before force close
If Restart: then delete the files on next startup
Are these doable?

StreamReader Could not find file (Because it is not being created)

I am trying to create a file for the further write to and read from.
I use Directory.CreateDirectory and File.Create but neither path nor file are being created.
On the Page which part I show here below I check if File exists, and if not, I create a File. On Second Page (that I dont show here) I add new lines to the file using StreamWrite. When saved, first Page comes to focus again and lists the content of the File(only one row in this study).
Here is my code for the part in question:
public async Task ReadFileAsync()
{
string directoryName = Path.GetDirectoryName(#"C:\Users\...\DataBase\");
Task.Run(async() => Directory.CreateDirectory(directoryName));
Task.Run(async() => File.Create(directoryName + "ProductsDatabase.txt"));
//code for reading from file
string path = (directoryName + "ProductsDatabase.txt");
using (StreamReader ProductsDatabaseRead = new StreamReader(File.OpenRead(path)))
{
ProductOneTextBlock.Text = ProductsDatabaseRead.ReadLine();
}
if (ProductOneTextBlock.Text == "")
{
ProductOneTextBlock.Text = "Nothing to show";
}
}
The file and folder are not being created.
I don't get any error.
I tried also different folders on the drive in case if there was READ ONLY folder in solution folder. No difference.
Anyone could help?
(I found many threads about this problem but here I cannot resolve it with none of the solutions.
Physical file is not being created.
When I attempt to write to it (from another page) I get error that the file could not be found(because it is not there indeed).
It seems that program loses itself somewhere between
Task.Run(async() => Directory.CreateDirectory(directoryName));
Task.Run(async() => File.Create(directoryName + "ProductsDatabase.txt"));
and:
using (StreamReader ProductsDatabaseRead = new StreamReader(File.OpenRead(path)))
{
ProductOneTextBlock.Text = ProductsDatabaseRead.ReadLine();
}
, as TextBlock is not being updated even if ProductsDatabaseRead is null.
If I put
ProductOneTextBlock.Text = "Nothing to show";
a the begining of the method, TextBlock gets updated.
SO, why the
using (StreamReader ProductsDatabaseRead = new StreamReader(File.OpenRead(path)))
does not work?
You're not waiting for Task.Run to complete. Your directory creation, file creation and attempt to open a "as you think newly created file" are out of order. That's why you're probably not able to open a file (it still does not exist at this point).
Task.Run returns a task that will be completed when the work is done. You need to wait for completion.
public void ReadFile()
{
string folderPath = #"C:\Users\patri\source\repos\DietMate\";
string fileName = "ProductsDatabase.txt";
string fullPath = Path.Combine(folderPath, fileName);
//insert code to check whether file exists.
// use Exists()
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
File.Create(fullPath);
}
//if yes, follow with code below
//insert code for reading from file
using (StreamReader ProductsDatabaseRead = new StreamReader(fullPath))
{
ProductTest.Text = ProductsDatabaseRead.ReadLine();
}
}

Removing ShellFile Properties

I ran into a problem this week regarding the Windows Shell Property System when applied to TIFF/TIF files. I'm using Microsoft.WindowsAPICodePack 1.1.0.0 to access the property system.
When adding properties, the file gets corrupted because it seems to get stored where the first IFD pointer would be expected. Now I'm not sure it simply inserts itself at the 5th byte, after the file header (0x49 0x49 0x2A 0x00), of if it overwrites any existing data. Additionally, when comparing the hexadecimal of the IDF entries headers, the bytes looks different. Now when I say corrupted, it is only when programmatically opening the file as a byte stream, not knowing if the file has a property system container added to it. It opens fine in Windows Image Preview, but not in the software my clients are using to view TIFF files.
Here's how I'm adding the properties (as an array of key=value strings).
public void SetFileTag(string fileName, string tagName, string tagValue)
{
try
{
using (var shellFile = ShellFile.FromFilePath(fileName))
{
var keywords = shellFile.Properties.System.Keywords.Value;
var keyValue = string.Concat(tagName, "=", tagValue);
var list = keywords == null ? new List<string>() : new List<string>(keywords);
if (list.Contains(keyValue))
{
return;
}
list.Add(keyValue);
using (var writer = shellFile.Properties.GetPropertyWriter())
{
writer.WriteProperty(shellFile.Properties.System.Keywords, list.ToArray(), true);
writer.Close();
}
}
}
finally
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
I looked in the code pack for anything available to entirely remove the properties, but I can't find any method to do so, I can only remove the keywords value. Anyone would have an idea on how to perform this? It doesn't have to be .NET code, it can very well be a command-line tool or win32 code.

Manipulating freshly uploaded file causes IOException

My Asp.net MVC app requires a file upload. In the course of the upload I'd like to manipulate the freshly uploaded file.
public ActionResult Edit(int id, FormCollection collection) {
Block block = userrep.GetBlock(id);
foreach (string tag in Request.Files) {
var file = Request.Files[tag] as HttpPostedFileBase;
if (file.ContentLength == 0)
continue;
string tempfile = Path.GetTempFileName()
file.SaveAs(tempfile);
// This doesn't seem to make any difference!!
// file.InputStream.Close();
if (FileIsSmallEnough(file)) {
// Will throw an exception!!
File.Move(tempfile, permanentfile);
} else {
GenerateResizedFile(tempfile, permanentfile);
// Will throw an exception!!
File.Delete(tempfile);
}
block.Image = permanentfile;
}
userrep.Save();
The problem with this snippet is that any attempt to manipulate the initially uploaded file generates an IOException("The process cannot access the file because it is being used by another process.") Of course I can bypass the problem by copying rather than moving uploaded file but I still can't delete it once I have a better alternative.
Any advice?
Duffy
As you have mentioned in your comments, you load an Image from file. The MSDN documentation states that the file remains locked until the image is disposed.
http://msdn.microsoft.com/en-us/library/stf701f5.aspx
To dispose your image, you can either call the Dispose method on the instance, or use the preferred mechanism of the using statement:
private bool FileIsSmallEnough()
{
using (Image i = Image.FromFile())
{
}
}
This should solve the problem.

Categories