Question

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();
}
Was it helpful?

Solution 2

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

OTHER TIPS

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);
        }
    }

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top