Check if a file exists in the project in WinRT

2020-02-12 02:37发布

问题:

I have a WinRT Metro project which displays images based on a selected item. However, some of the images selected will not exist. What I want to be able to do is trap the case where they don't exist and display an alternative.

Here is my code so far:

internal string GetMyImage(string imageDescription)
{
    string myImage = string.Format("Assets/MyImages/{0}.jpg", imageDescription.Replace(" ", ""));

    // Need to check here if the above asset actually exists

    return myImage;
}

Example calls:

GetMyImage("First Picture");
GetMyImage("Second Picture");

So Assets/MyImages/SecondPicture.jpg exists, but Assets/MyImages/FirstPicture.jpg does not.

At first I thought of using the WinRT equivalent of File.Exists(), but there doesn't appear to be one. Without having to go to the extent of trying to open the file and catching an error, can I simply check if either the file exists, or the file exists in the project?

回答1:

You could use GetFilesAsync from here to enumerate the existing files. This seems to make sense considering you have multiple files which might not exist.

Gets a list of all files in the current folder and its sub-folders. Files are filtered and sorted based on the specified CommonFileQuery.

var folder = await StorageFolder.GetFolderFromPathAsync("Assets/MyImages/");
var files = await folder.GetFilesAsync(CommonFileQuery.OrderByName);
var file = files.FirstOrDefault(x => x.Name == "fileName");
if (file != null)
{
    //do stuff
}

Edit:

As @Filip Skakun pointed out, the resource manager has a resource mapping on which you can call ContainsKey which has the benefit of checking for qualified resources as well (i.e. localized, scaled etc).

Edit 2:

Windows 8.1 introduced a new method for getting files and folders:

var result = await ApplicationData.Current.LocalFolder.TryGetItemAsync("fileName") as IStorageFile;
if (result != null)
    //file exists
else
    //file doesn't exist


回答2:

There's two ways you can handle it.

1) Catch the FileNotFoundException when trying to get the file:

 Windows.Storage.StorageFolder installedLocation = 
     Windows.ApplicationModel.Package.Current.InstalledLocation;
 try
 {
     // Don't forget to decorate your method or event with async when using await
     var file = await installedLocation.GetFileAsync(fileName);
     // Exception wasn't raised, therefore the file exists
     System.Diagnostics.Debug.WriteLine("We have the file!");
 }
 catch (System.IO.FileNotFoundException fileNotFoundEx)
 {
     System.Diagnostics.Debug.WriteLine("File doesn't exist. Use default.");
 }
 catch (Exception ex)
 {
     // Handle unknown error
 }

2) as mydogisbox recommends, using LINQ. Although the method I tested is slightly different:

 Windows.Storage.StorageFolder installedLocation =
     Windows.ApplicationModel.Package.Current.InstalledLocation;
 var files = await installedLocation.GetFilesAsync(CommonFileQuery.OrderByName);
 var file = files.FirstOrDefault(x => x.Name == fileName);
 if (file != null)
 {
    System.Diagnostics.Debug.WriteLine("We have the file!");
 }
 else
 {
    System.Diagnostics.Debug.WriteLine("No File. Use default.");
 }


回答3:

BitmapImage has an ImageFailed event that fires if the image can't be loaded. This would let you try to load the original image, and then react if it's not there.

Of course, this requires that you instantiate the BitmapImage yourself, rather than just build the Uri.



回答4:

Sample checking for resource availability for c++ /cx (tested with Windows Phone 8.1):

std::wstring resPath = L"Img/my.bmp";
std::wstring resKey = L"Files/" + resPath;
bool exists = Windows::ApplicationModel::Resources::Core::ResourceManager::Current->MainResourceMap->HasKey(ref new Platform::String(resKey.c_str()));