C# (xamarin project) not able to find path to the file - c#

I have this problem when I'm trying to read JSON file (or any file): It's not able to find that file. I try everything, even the absolute path (error almost same - DirectoryNotFound)
This is structure of mine code:
And this is code:
private void LoadJson()
{
using (var r = new StreamReader("quizQuestions.json"))
{
string json = r.ReadToEnd();
items = JsonConvert.DeserializeObject<List<Questions>>(json);
}
}
I I even try to use Directory.GetCurrentDirectory() but it's returning : / -> only this character. I don't know where is a mistake or if I forgot to set something. I try to find answers everywhere but I was not able to find anything with this.

Make sure the Build Action of the file is set as Content or as an Asset and give this a try.
private void LoadJson()
{
AssetManager assets = this.Assets;
using (var r = new StreamReader(assets.Open ("quizQuestions.json")))
{
string json = r.ReadToEnd();
items = JsonConvert.DeserializeObject<List<Questions>>(json);
}
}

You can configure the file as Embedded Resource and then access it like this:
public static Stream GetEmbeddedResourceStream(Assembly assembly, string resourceFileName)
{
var resourceNames = assembly.GetManifestResourceNames();
var resourcePaths = resourceNames
.Where(x => x.EndsWith(resourceFileName, StringComparison.CurrentCultureIgnoreCase)).ToArray();
if (resourcePaths.Any() && resourcePaths.Count() == 1)
{
return assembly.GetManifestResourceStream(resourcePaths.Single());
}
return null; // or throw Exception
}
private void LoadJson()
{
Assembly assembly = GetAssemblyContainingTheJson();
using (var r = GetEmbeddedResourceStream(assembly, "quizQuestions.json"))
{
string json = r.ReadToEnd();
items = JsonConvert.DeserializeObject<List<Questions>>(json);
}
}

Related

How to pass xml file inside of code instead of a folder path?

I'am trying to not create a file, and pass xml document straight to a SkiaSharp method Load. I mean, is there the way to imitate a path? So here is the code:
public IActionResult svgToPng(string itemId, string mode = "
{
var svgSrc = new XmlDocument();
svgSrc.LoadXml(/*Some xml code*/);
string svgSaveAs = "save file path";
var quality = 100;
var svg = new SkiaSharp.Extended.Svg.SKSvg();
var pict = svg.Load(svgSrc); // HERE, it needs to be a path, not XmlDocument, but i want to pass straight
var dimen = new SkiaSharp.SKSizeI
(
(int) Math.Ceiling(pict.CullRect.Width),
(int) Math.Ceiling(pict.CullRect.Height)
);
var matrix = SKMatrix.MakeScale(1, 1);
var img = SKImage.FromPicture(pict, dimen, matrix);
// Convert to PNG
var skdata = img.Encode(SkiaSharp.SKEncodedImageFormat.Png, quality);
using(var stream = System.IO.File.OpenWrite(svgSaveAs))
{
skdata.SaveTo(stream);
}
ViewData["Content"] = "PNG file was created out of SVG.";
return View();
}
The Load method seems to be this:
public SKPicture Load(
using (var stream = File.OpenRead(filename))
{
return Load(stream);
}
}
look at the code of that library :
https://github.com/mono/SkiaSharp.Extended/blob/master/SkiaSharp.Extended.Svg/source/SkiaSharp.Extended.Svg.Shared/SKSvg.cs
Look at the Load method, it has multiple implementations :
public SKPicture Load(string filename)
{
using (var stream = File.OpenRead(filename))
{
return Load(stream);
}
}
public SKPicture Load(Stream stream)
{
using (var reader = XmlReader.Create(stream, xmlReaderSettings, CreateSvgXmlContext()))
{
return Load(reader);
}
}
public SKPicture Load(XmlReader reader)
{
return Load(XDocument.Load(reader));
}
You will need to pick one of them and use it. Now, nothing stops you from getting the code and adding one extra Load for an XML string for example, but since this is a library you do not control, I'd stick to what you are given.
You could use the XmlReader version, that's probably the closest one to what you want.

(C#) How to GET a download url to a certain path?

So let's say I have a download url that when you GET it, it downloads a file.
Now, this file is not a txt or anything, it has no extension.
How would I code a GET request to the URL, but make it download to a certain path?
EDIT: Also, how would I convert it to a TXT and read from the txt afterwards?
NOTE: It's a get request site that instantly downloads the file, not a file on a site you can open in your browser
EDIT 2: It actually returns xml, not the file, sorry
just using a browser downloads it.
What is the real content of that file?
You can try to configure the content-type as "application/octet-stream".
It asks the server for byte content.
If the content is regular text already, you can simply add ".txt" to the file name and you can read it whenever you want.
You do it like this it shouldn't matter if your link has a clear ending like the one I have used. Or if you are really serious about making the GET part explicit use RestSharp. Look now you can even change the file extensions from within the code not that it would matter the least bit. I tossed in some Linq2Xml since you mentioned your file was xml and I thought you possible needed to do something with it.
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Xml.Linq;
using System.Linq;
using RestSharp;
namespace Get2File
{
internal class Program
{
private const string FallbackUrl = #"https://gist.github.com/Rusk85/8d189cd35295cfbd272d8c2121110e38/raw/4885d9ba37528faab50d9307f76800e2e1121ea2/example-xml-with-embedded-html.xml";
private string _downloadedContent = null;
private const string FileNameWithoutExtension = "File";
private static void Main(string[] args)
{
var p = new Program();
p.Get2FileWithRestSharp(fileExtensions:".xml");
p.UseLinq2XmlOnFile();
}
private void Get2File(string altUrl = null, string fileExtensions = ".txt")
{
var url = !string.IsNullOrEmpty(altUrl)
? altUrl
: FallbackUrl;
var client = new HttpClient();
var content = client.GetStringAsync(url).Result;
_downloadedContent = content;
var outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{FileNameWithoutExtension}{fileExtensions}");
File.WriteAllText(outputPath, content);
}
private void Get2FileWithRestSharp(string altUrl = null, string fileExtensions = ".txt")
{
var url = !string.IsNullOrEmpty(altUrl)
? altUrl
: FallbackUrl;
var urlAsUri = new Uri(url);
var client = new RestClient(urlAsUri);
var request = new RestRequest(Method.GET);
var content = string.Empty;
var result = client.Execute(request);
content = result.Content;
_downloadedContent = content;
var output = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{FileNameWithoutExtension}{fileExtensions}");
File.WriteAllText(output, content);
}
private void UseLinq2XmlOnFile()
{
XElement xElement = XElement.Parse(_downloadedContent);
var elements = xElement.Elements();
var StringElement = elements.FirstOrDefault(e => e.Name == "String");
var tranlateXAttribute = StringElement.Attributes().FirstOrDefault(attr => attr.Name == "translate");
Debug.WriteLine(tranlateXAttribute.Value);
}
}
}

Append (n) to file names (not using system.io.file) to ensure unique names

I have a class that holds the name of a file, and the data of a file:
public class FileMeta
{
public string FileName { get; set; }
public byte[] FileData { get; set; }
}
I have a method that populates a collection of this class through an async download operation (Files are not coming from a local file system):
async Task<List<FileMeta>> ReturnFileData(IEnumerable<string> urls)
{
using (var client = new HttpClient())
{
var results = await Task.WhenAll(urls.Select(async url => new
{
FileName = Path.GetFileName(url),
FileData = await client.GetByteArrayAsync(url),
}));
return results.Select(result =>
new FileMeta
{
FileName = result.FileName,
FileData = result.FileData
}).ToList();
}
}
I am going to feed this List<FileMeta> into a ZipFile creator, and the ZipFile like all File containers needs unique file names.
Readability is important, and I would like to be able to do the following:
file.txt => file.txt
file.txt => file(1).txt
file.txt => file(2).txt
There are a number of examples on how to do this within the file system, but not with a simple object collection. (Using System.IO.File.Exists for example)
What's the best way to loop through this collection of objects and return a unique set of file names?
How far I've gotten
private List<FileMeta> EnsureUniqueFileNames(IEnumerable<FileMeta> fileMetas)
{
var returnList = new List<FileMeta>();
foreach (var file in fileMetas)
{
while (DoesFileNameExist(file.FileName, returnList))
{
//Append (n) in sequence until match is not found?
}
}
return returnList;
}
private bool DoesFileNameExist(string fileName, IEnumerable<FileMeta> fileMeta)
{
var fileNames = fileMeta.Select(file => file.FileName).ToList();
return fileNames.Contains(fileName);
}
You can try the following to increment the filenames:
private List<FileMeta> EnsureUniqueFileNames(IEnumerable<FileMeta> fileMetas)
{
var returnedList = new List<FileMeta>();
foreach (var file in fileMetas)
{
int count = 0;
string originalFileName = file.FileName;
while (returnedList.Any(fileMeta => fileMeta.FileName.Equals(file.FileName,
StringComparison.OrdinalIgnoreCase))
{
string fileNameOnly = Path.GetFileNameWithoutExtension(originalFileName);
string extension = Path.GetExtension(file.FileName);
file.FileName = string.Format("{0}({1}){2}", fileNameOnly, count, extension);
count++;
}
returnList.Add(file);
}
return returnList;
}
As a side note, in your ReturnFileData, you're generating two lists, one of anonymous type and one of your actual FileMeta type. You can reduce the creation of the intermediate list. Actually, you don't need to await inside the method at all:
private Task<FileMeta[]> ReturnFileDataAsync(IEnumerable<string> urls)
{
var client = new HttpClient();
return Task.WhenAll(urls.Select(async url => new FileMeta
{
FileName = Path.GetFileName(url),
FileData = await client.GetByteArrayAsync(url),
}));
}
I made the return type a FileMeta[] instead of a List<FileMeta>, as it is a fixed sized returning anyway, and reduces the need to call ToList on the returned array. I also added the Async postfix, to follow the TAP guidelines.

C# - Cannot getting a string from ResourceManager (from satellite assembly)

I'm developing a localisable application. In my "local" resource file, I've the language used by default (english) and if possible, I load the user's preference and culture and load strings translated in is language.
So what I've done :
private static CultureInfo _culture = CultureInfo.CurrentUICulture;
private static ResourceManager _manager;
private static void ToNeutralCulture()
{
while (!_culture.IsNeutralCulture)
{
_culture = _culture.Parent;
}
}
private static void LoadCulture()
{
ResourceManager manager = Properties.Resources.ResourceManager;
try
{
ToNeutralCulture();
string assembly = Assembly.GetCallingAssembly().GetName().CodeBase;
string assemblyDir = Path.GetDirectoryName(assembly);
string assemblyName = Path.GetFileNameWithoutExtension(assembly);
string resourceFileName = string.Format(CultureInfo.InvariantCulture,
#"{0}\{1}_{2}.dll",
assemblyDir,
assemblyName,
_culture.Name.ToUpper());
FileInfo resourceFile = new FileInfo(resourceFileName);
if (resourceFile.Exists)
{
Assembly resourceAssembly = Assembly.LoadFrom(resourceFile.FullName);
string[] manifests = resourceAssembly.GetManifestResourceNames();
if (manifests.Length == 1)
{
manager = new ResourceManager(manifests[0], resourceAssembly);
}
using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
{
IDictionaryEnumerator dict = reader.GetEnumerator();
while (dict.MoveNext())
{
string key = dict.Key as string;
object val = dict.Value;
//string mVal = manager.GetString(key);
}
}
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,
"Fail to loading culture {0}",
(_culture == null) ? "--" : _culture.EnglishName));
}
_manager = manager;
}
Assembly is correctly loaded and the enumerator will display me all resources present in the resource file, well, works fine except :
string mVal = manager.GetString(key);
When I uncommented this line, I've an System.Resources.MissingManifestResourceException, can someone tell me why?
Thanks !
[EDIT]
Project "MyApp"
namespace MyApp
{
Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
string[] manifests = resourceAssembly.GetManifestResourceNames();
if (manifests.Length == 1)
{
manager = new ResourceManager(manifests[0], resourceAssembly);
}
// Throws the exception
manager.GetString("PleaseCallIT", null);
// Works
using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
{
IDictionaryEnumerator dict = reader.GetEnumerator();
while (dict.MoveNext())
{
string key = dict.key as string; // PleaseCallIT
object val = dict.value; // Please call IT.
}
}
}
Project "MyApp_FR" (Resources.Designer.cs auto-generated file)
namespace MyApp.Properties {
// ...
internal static string PleaseCallIT {
get {
return ResourceManager.GetString("PleaseCallIT", resourceCulture);
}
}
}
I don't understand...
I found why, hope this will help someone that is in the same case.
So, I looked in MyApp_FR.dll the code generated to use the Resource file, it is :
new global::System.Resources.ResourceManager("MyApp_FR.Properties.Resources", typeof(Resources).Assembly);
but when retrieving the manifest file names, I got :
"MyApp_FR.Properties.Resources.resources"
Seems to be there is a .resource to much in this room... By removing it, I can use my ResourceManager normally, all works fine...
Final code :
Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
string[] manifests = resourceAssembly.GetManifestResourceNames();
if (manifests.Length == 1)
{
string manifest = manifests[0].Replace(".resources", string.Empty);
manager = new ResourceManager(manifest, resourceAssembly);
}
// Works !
manager.GetString("PleaseCallIT", null);
From Microsoft Support:
This problem occurs if you use a localized resource that exists in a satellite assembly that you created by using a .resources file that has an inappropriate file name. This problem typically occurs if you manually create a satellite assembly:
Try this KB:
http://support.microsoft.com/kb/839861
An alternate approach, put in the following as test code:
string[] resources =
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
In debugging, check the contents of resources to see if it matches what you are loading with ResourceManager.
Especially note, if you get something like 'MyAssembly..Resources.resources', then you will need to explicitly add 'Resources' to the ResourceManager constructor:
private static readonly ResourceManager stringTable =
new ResourceManager("MyAssembly.Resources", Assembly.GetExecutingAssembly());

C#: Reading the content of a file, which is embedded in a resource file

How can I read a text file, which is embedded in a resx file with the help of the ResourceManager class?
Whats wrong with the following snippet?
ResourceManager resman = new ResourceManager("Mynamespace.RESXFileName", Assembly.GetExecutingAssembly());
Stream stream = resman2.GetStream("ResourceName");
stream is alway = null!
using (var resourceStream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName))
{
if (resourceStream != null)
{
using (var textStreamReader = new StreamReader(resourceStream))
{
text = textStreamReader.ReadToEnd();
}
}
else
{
throw (new MissingManifestResourceException(resourceName));
}
}
The resource name is determined by namespace and filename. Say file MyTxt.txt exists in the root of the project, which has default namespace MyNs then the resource name will be: MyNs.MyTxt.txt
EDIT
I should learn to read the question. I haven't tested but this should give you what you want:
static object GetResxObject(string resxPathName, string resourceKey)
{
using (var resxReader = new ResXResourceReader(resxPathName))
{
return resxReader
.Cast<DictionaryEntry>()
.Single(d => string.Equals(d.Key,
resourceKey))
.Value;
}
}
...
var myString=(string)GetResxObject(#"path\to\resx.resx","myStringKey");
<ResourceNamespace>.ResourceManager.GetString(<textresourcename>);

Categories