How to include file in Source Control and edit it later - c#

I'm creating a game using C# and trying to incorporate a CSV for parsing previous scores into a leaderboard and also writing to the file when a player finishes their game.
This is the data stored relating to a score
If this was a sole project I would store the csv in the bin > Debug folder and pass the file path to a StreamReader. Although, this is a group project using Azure Devops/TFS as source control so I'm not too sure what way is best to do this.
I have tried storing the CSV in the Resources of the project but I didn't realise this embeds the file in the project and only allows for reading from the file.
The CSV is currently read like:
var file = Properties.Resources.highscores;
char[] splitter = "\r\n".ToCharArray();
string[] scoresCsv = Properties.Resources.highscores.Split(splitter);
foreach (string score in scoresCsv)
{
if(!String.IsNullOrEmpty(score))
{
var values = score.Split(',');
highScores.Add(new HighScore(values[0], Convert.ToInt32(values[1]), Convert.ToDateTime(values[2])));
}
}
this.highScores = highScores.OrderByDescending(x => x.Score).ToList();

Select the "Team Explorer" window and go to "Source Control Explorer"
Here you will see a global view of the project.
You can add files to your project in any folder you wish outside of the actual source. If you want to you can add your bin folder into the source control and keep that file in the bin folder.
Where-ever you put the file you just need to know the location to it from your project and you are able to map to it and edit it in runtime.
Another option is to create a folder in the C:\ProgramData folder for your game and you can write the leaderboards directly into their C drive when they run the game. People would be able to modify the leaderboards but, obviously the game is for learning purposes of coding and usually you wouldn't store the leaderboards on the client side anyway it would be on a server.

This assumes that the high score data is not shared, and stores it locally. It doesn't require the file to be added to source control.
public class ScoreFileHandler
{
private static string appPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "YourAppName");
private static string scoreFileName = "highscores.txt";
private static string filePath = Path.Combine(appPath, scoreFileName);
public string ReadFile()
{
if (!Directory.Exists(appPath))
{
Directory.CreateDirectory(appPath);
}
if (File.Exists(filePath))
{
return File.ReadAllText(filePath);
}
return string.Empty; // TODO - caller needs to handle this
}
public void WriteFile(string csvScoreData)
{
if (!Directory.Exists(appPath))
{
Directory.CreateDirectory(appPath);
}
File.WriteAllText(filePath, csvScoreData);
}
}

Related

Run time/length info for all media files in a folder

If there are multiple media files in a folder like so:
MediaFiles(folder)
-> file1.mp4
-> file2.mp4
...
When we select all the files and
Right Click -> Properties
In the Properties windows on the Details Tab there is a Length field that shows the total runtime of the media files together like this:
Is it possible to get this info using C#?
As indicated in this link, with the help of the Microsoft.WindowsAPICodePack-Shell nuget package, you can get the total length as follows;
static void Main(string[] args)
{
DirectoryInfo dir = new DirectoryInfo(#"C:\to\your\path");
FileInfo[] files = dir.GetFiles("*.mp4");
var totalDuration = files.Sum(v => GetVideoDuration(v.FullName));
}
public static double GetVideoDuration(string filePath)
{
using (var shell = ShellObject.FromParsingName(filePath))
{
IShellProperty prop = shell.Properties.System.Media.Duration;
var t = (ulong)prop.ValueAsObject;
return TimeSpan.FromTicks((long)t).TotalMilliseconds;
}
}
You can use windows media object and load the file and then get its properties.
Read the folders file and loop through with each file and load them and read the property you want and may be store in DB.
Please refer from Microsoft site go here to check the more detail

full path as the filename

Maybe someone knows a simple solution to my problem.
I do not know the entry of the file so it's not a static value.
It can be changed through the BizTalk gui and there we have a URI through the receiveport. But I do not believe it's accessible that easy. What I want to do is write out the full path as the filename. It works well with the messageID where the file is given a specific filepath name. But the Path-Name where the file was dropped is not working that well.
I keep getting this error :
Message:
Object reference not set to an instance of an object.
the message resource is present but the message is not found in the string/message table
-Does not say me much
Below you can see a snip from my code
internal static string UpdateMacroPathProperty(IBaseMessage baseMessage, string macroPathProperty, string macroDefsFile)
{
if (macroName == "MessageID")
{
contextPropertyValue = baseMessage.MessageID.ToString();
}
else if (macroName == "SourceFileName")
{
contextPropertyValue = Directory.GetCurrentDirectory();
}
}
This is an specific created pipeline. Has anyone encountered this problem or can point me in the right way.
I know that BizTalk has a built in function for this, BizTalk Server: List of Macros as the %SourceFileName% but I'm trying to save this as logs in a specific map structure so that it does not get processed.
It's adapter dependent; some adapters will use the FILE adapter's namespace even though they're not the file adapter, but this is the kind of logic that I've used in the past for this:
string adapterType = (string)pInMsg.Context.Read("InboundTransportType",
"http://schemas.microsoft.com/BizTalk/2003/system-properties");
string filePath = null;
if (adapterType != null)
{
if (adapterType == "FILE")
{
filePath = (string)pInMsg.Context.Read("ReceivedFileName",
"http://schemas.microsoft.com/BizTalk/2003/file-properties");
}
else if (adapterType.Contians("SFTP") && !adapterType.Contains("nsoftware"))
// nsoftware uses the FTP schema
{
filePath = (string)pInMsg.Context.Read("ReceivedFileName",
"http://schemas.microsoft.com/BizTalk/2012/Adapter/sftp-properties");
}
else if (adapterType.Contains("FTP"))
{
filePath = (string)pInMsg.Context.Read("ReceivedFileName",
"http://schemas.microsoft.com/BizTalk/2003/ftp-properties");
}
}
And then you can just fall back to the MessageID if you can't get the file path from any of these.

How do I get the folder for the currently open file in c#

I am writing a wizard that pulls information from a database like file. This wizard doesn't get compiled, it just runs on command. I am not sure the correct term for that.
The issue is, I need to enter more information which will manipulate the database, and I want to store the values into a csv file that I use to manipulate the database.
So the question is: How do I get the folder for the currently open file in a c# application so that I can save a csv file to that folder?
edit: The path needs to be dynamic. Each database file is stored in a separate folder. I need the wizard to save to which ever folder I just opened the file from.
edit2 :
I am not opening the file programmatically. The file is being open by the user in the application. So, the user opens a file, and a bunch of database information is displayed. He then runs a wizard on that data where he can enter some coefficients, etc .. and that will change the information in the database file. I need to be able to store the coefficients he enters into the folder that contains the database file that he opened. I cannot access / change the application code, only the wizard code.
Thanks
Something like this?
var file = "C:\\Users\\Me\\Desktop\\Test.txt";
var fileLocation = file.Substring(0, file.LastIndexOf("\\"));
You can use this:
string path = Path.GetFullPath(Directory.GetCurrentDirectory()).TrimEnd(Path.DirectorySeparatorChar);
string directoryName = Path.GetFileName(path);
I found this solution in this thread
Get the (last part of) current directory name in C#
Try
//Or where ever the database returns the file is stored
var filename = "C:\\Temp\\File\\Test.txt";
var path = System.IO.Path.GetDirectoryName(filename);
Should return C:\Temp\File
Source : https://msdn.microsoft.com/en-us/library/system.io.path.getdirectoryname(v=vs.110).aspx
Try using DirectoryInfo to get information about any directory:
using System;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
if (di != null)
{
FileInfo[] subFiles = di.GetFiles();
if (subFiles.Length > 0)
{
Console.WriteLine("Files:");
foreach (FileInfo subFile in subFiles)
{
Console.WriteLine(" " + subFile.Name + " (" + subFile.Length + " bytes) " + "Directory name: "
+ di.Name + " Directory full name: " + di.FullName);
}
}
Console.ReadKey();
}
}
}
}

What need I do to get this code to work in a Portable Class Library?

I'm wondering if the Portable Class Library is even more restricted in functionality than the Compact Framework.
I'm trying to port a CF/Windows CE app (runs on a handheld device) to a Xamarin solution that will target Android, iOS, Windows Phone, and perhaps other things.
One of the problems I run into, though, is that this legacy code (which works under CF):
public static List<string> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
string dirName = startingDir;
// call it like so: GetXMLFiles("ABC", "\\"); <= I think the double-whack is what I need for Windows CE device...am I right?
var fileNames = new List<String>();
try
{
foreach (string f in Directory.GetFiles(dirName))
{
string extension = Path.GetExtension(f);
if (extension != null)
{
string ext = extension.ToUpper();
string fileNameOnly = Path.GetFileNameWithoutExtension(f);
if (fileNameOnly != null &&
((ext.Equals(EXTENSION, StringComparison.OrdinalIgnoreCase)) &&
(fileNameOnly.Contains(fileType))))
{
fileNames.Add(f);
}
}
}
foreach (string d in Directory.GetDirectories(dirName))
{
fileNames.AddRange(GetXMLFiles(fileType, d));
// from Brad Rem's answer here: http://stackoverflow.com/questions/22186198/why-is-this-function-returning-nothing-although-there-is-a-match/22186351?noredirect=1#22186351
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return fileNames;
}
...won't compile in the Xamarin/CPL solution. I get, "The name 'Directory' does not exist in the current context" and right-clicking that word does not afford a "resolve" option.
Is there a way to get PCL to recognize "Directory" or must I completely rewrite the code? If the latter, does anybody have any suggestions on what to do/use in its stead?
Relatedly, is there an URL that will show me what is [not] available in PCL and/or a site that will show how much of a provided block of code is "PCL-ready"?
UPDATE
The first image in this article is very illuminating. Later on, it specifically talks about "Directory" not being available in the PCL scenario.
UPDATE 2
I downloaded the PCLStorage package referenced by Daniel Plaisted below to allow me to access the file system within a PCL project.
Using the sample code at the start of the download page [http://pclstorage.codeplex.com/] as a starting point, I've gotten this far:
public async Task<List<string>> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.GetFolderAsync(startingDir, CreationCollisionOption.OpenIfExists); //CreateFolderAsync(startingDir, CreationCollisionOption.OpenIfExists);
List<string> fileNames = await folder.GetFilesAsync(EXTENSION);
return fileNames;
}
...but "EXTENSION" as the arg to GetFilesAsync() is not right. I get with this, "Argument 1: cannot convert from 'string' to 'System.Threading.CancellationToken'"
So what need I do to get all the *.XML files the folder?
UPDATE 3
This compiles, but I'm not at all sure it's the right way to do it, besides the fact that it simply gets all the files from the folder, rather than just those that match "*.XML":
public async Task<List<IFile>> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.GetFolderAsync(startingDir, System.Threading.CancellationToken.None);
IList<PCLStorage.IFile> fileNames = await folder.GetFilesAsync(System.Threading.CancellationToken.None);
return fileNames.ToList();
}
Since in a PCL I was unable to get a StreamWriter from a string (it required a stream), I created a simple interface to get some of the data from the platform implementation. You can also do this with DirectoryInfo and FileInfo.
https://github.com/sami1971/SimplyMobile/blob/master/Core/SimplyMobile.Text/IStreamLocator.cs
The implementation is really simple as well, only needs one single compiler flag for WP8:
https://github.com/sami1971/SimplyMobile/blob/master/WP8/SimplyMobile.Text.Platform/StreamLocator.cs
Recursively search for *.XML files:
private static void PrintDirectory(IStreamLocator locator, string dir)
{
foreach (var file in locator.GetFileNames(dir, "*.XML"))
{
System.Diagnostics.Debug.WriteLine(file);
}
foreach (var di in locator.GetFolderNames(dir, "*"))
{
PrintDirectory(locator, di);
}
}
Windows Phone applications do not use the file system of the operating
system and are restricted to using isolated storage to persist and
access files, so this namespace does not provide any additional
functionality.
http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.io%28v=vs.105%29.aspx
Xamarin has a scanner which will give you a rough idea of the portability of your code: http://scan.xamarin.com/
For some guidance on how to deal with non-portable APIs from PCLs, see my blog post: How to Make Portable Class Libraries Work for You
For file IO in particular, you can try my PCL Storage library.
Another option is to use Shim if all your platforms are supported by it.
API coverage for file operations isn't exhaustive, but it gets you a long way. As a bonus, it also gives you access to a bunch of other stuff.

%AllUsersProfile%(%PROGRAMDATA%) gives a repetitive file path

I have an application written in C#, and I am seeking to write some information to the hidden ProgramData in order to access the same connection string from both the application's front end and back end.
I am accessing the directory using path variables as follows:
private bool ProgramDataWriteFile(string contentToWrite)
{
try
{
string strProgramDataPath = "%PROGRAMDATA%";
string directoryPath = Environment.ExpandEnvironmentVariables(strProgramDataPath) + "\\MyApp\\";
string path = Environment.ExpandEnvironmentVariables(strProgramDataPath)+"\\MyApp\\ConnectionInfo.txt";
if (Directory.Exists(directoryPath))
{
System.IO.StreamWriter file = new System.IO.StreamWriter(path);
file.Write(contentToWrite);
file.Close();
}
else
{
Directory.CreateDirectory(directoryPath);
System.IO.StreamWriter file = new System.IO.StreamWriter(path);
file.Write(contentToWrite);
file.Close();
}
return true;
}
catch (Exception e)
{
}
return false;
}
This seems to work correctly. However, my question is, when I used this path variable: %AllUsersProfile%(%PROGRAMDATA%)
instead, it expanded into an illegal(and redundant) file path : C:\ProgramData(C:\ProgramData)\
However, I thought that the latter path variable was the correct full name. Was I just using it incorrectly? I need to ensure that this connection info will be accessible to all users, will just using %PROGRAMDATA% allow that? I am using Windows 7 in case that is relevant.
From here:
FOLDERID_ProgramData / System.Environment.SpecialFolder.CommonApplicationData
The user would never want to browse here in Explorer, and settings changed here should affect every user on the machine. The default location is %systemdrive%\ProgramData, which is a hidden folder, on an installation of Windows Vista. You'll want to create your directory and set the ACLs you need at install time.
So, just use %PROGRAMDATA%, or better still:
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)

Categories

Resources