I am trying to save an image selected with FileOpenPicker. I am lunching this event when an image is selected
async void photoChooserTask_Completed(object sender, PhotoResult e)
{
// get the file stream and file name
Stream photoStream = e.ChosenPhoto;
string fileName = Path.GetFileName(e.OriginalFileName);
// persist data into isolated storage
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream current = await file.OpenStreamForWriteAsync())
{
await photoStream.CopyToAsync(current);
}
}
But this code which will give me the lenght of the saved file return 0
var properties = await file.GetBasicPropertiesAsync();
i = properties.Size;
Have I done something wrong in saving the image?
You may need to flush the stream.
If that does not work, add a breakpoint and check the two streams' lengths after the copy. Are they equal? They should be. Anything suspicious on those two stream objects?
Edit
On the image you posted, I can see that you use the SetSource method of a BitmapImage with the same Stream that you copy. Once you do that, the Stream's Position will be at the end, as it was just read by that call.
CopyToAsync copies everything after the current Position of the Stream you call it on. Since the position is at the end, because it was just read, the CopyToAsync does not copy anthing.
All you need to do to fix your problem is set the stream's Position to 0.
Related
In my project, I have the player info being saved out to a JSON file. I am encrypting the information before I save it but if the player goes into the file and happens to delete one character of the file, when the game loads, because it depends upon that file, the game freezes up. I do have it so that a new player info is created if no file is detected, but if the file is there and they mess with it, is there any way of detecting that and correcting it before the game tries to load it. I am using JSONUtility built into Unity.
Use a try/catch when loading the JSON file
try
{
JsonUtility.FromJSON(...)
}
catch (FileNotFoundException e)
{
Print("The file was not found: '{e}'");
}
catch (DirectoryNotFoundException e)
{
Print("The directory was not found: '{e}'");
}
catch (IOException e)
{
Print("The file could not be opened: '{e}'");
}
However, this shouldn't be that important. If a player is trying to mess with the game files and you are worried about the program crashing, you shouldn't because that player shouldn't have been editing game files.
I think using both hashing and try/catch checking would be the better solution
You can just try to open the file then compare its hash with the hash you saved in the last game session:
private void LoadSave()
{
try
{
JsonUtility.FromJson("filename", ...);
string oldHash = PlayerPrefs.GetString("importantSaveFileHash");
string newHash = CalculateMd5("filename");
if (oldHash == null || oldHash == newHash)
{
//recalculate hash every time you change the save file
//you can also encrypt this hash for better security
PlayerPrefs.SetString("importantSaveFileHash", newHash);
//RESULT: Save file is cool!
}
else
{
//RESULT: Save file was modified!
}
}
catch (Exception e)
{
//RESULT: broken file
}
}
private static string CalculateMd5(string filename)
{
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(filename))
{
var hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
Btw you can just use PlayerPrefs to store all the game state (I know that sometimes its important to have visible and readable save file) - choose what you need)
UPD: its not good to store game state in PlayerPrefs - use any another way instead (read comments)
I am using Below Code to save image but it save image after filesavepicker save image but I want to save image direct into local folder without using
filesavepicker,Please suggest me any Solution for this, thanks in Advance.
webcam private async Task SavePhoto(IRandomAccessStream mediaStream)
{
FileSavePicker photoSavePicker = new FileSavePicker();
photoSavePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
var mediaFile = await photoSavePicker.PickSaveFileAsync();
await SaveStreamToFileAsync(mediaStream, mediaFile);
}
I want to save this stream data in image format direct to local folder without using filesavepicker.
Create the StorageFile inside the app's LocalData. Then pass this StorageFile to your function.
StorageFolder dirLocal = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile mediaFile = await dirLocal.CreateFileAsync("mediaFile.abc");
SaveStreamToFileAsync(mediaStream, mediaFile);
When using the secondaryTitle in c++, I have to enter a URI that points to the logo. The URI fails if I try to point it to any file outside of the app's package. What I tried to is have the user select the file using a filepicker
void App3::MainPage::FindLogo(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
FileOpenPicker^ openPicker = ref new FileOpenPicker();
openPicker->ViewMode = PickerViewMode::Thumbnail;
openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
openPicker->FileTypeFilter->Append(".jpg");
openPicker->FileTypeFilter->Append(".jpeg");
openPicker->FileTypeFilter->Append(".png");
create_task(openPicker->PickSingleFileAsync()).then([this](Windows::Storage::StorageFile^ file)
{
if (file)
{
StorageFolder^ folder;
auto ur = ref new Uri("ms-appx:///Assets//");
String^ s = Windows::ApplicationModel::Package::Current->InstalledLocation->Path;
create_task(StorageFolder::GetFolderFromPathAsync(s)).then([=](StorageFolder^ folder){
create_task(file->CopyAsync(folder, file->Name, NameCollisionOption::ReplaceExisting)).then([this, file](task<StorageFile^> task)
{
logoFile = ref new Uri("ms-appdata:///local//App3//Assets//StoreLogo.scale-100.png");
});
});
}
});
}
then copy that file and save it in the app directory. It still fails when using a uri to point to the new copy.
void App3::MainPage::kk(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
text = url->Text->ToString();
ids = id->Text->ToString();
auto test = ref new Windows::UI::StartScreen::SecondaryTile(ids, "hi", text, logoFile, Windows::UI::StartScreen::TileSize::Square150x150); // Breaks right here
// error: logofile is 0x05fcc1d0
num++;
test->RequestCreateAsync();
//auto uri = ref new Windows::Foundation::Uri("http://www.google.com");
//concurrency::task<bool> launchUriOperation(Windows::System::Launcher::LaunchUriAsync(uri));
}
UPDATED
create_task(openPicker->PickSingleFileAsync()).then([this](Windows::Storage::StorageFile^ file)
{
if (file)
{
StorageFolder^ folder = ApplicationData::Current->LocalFolder;
create_task(file->CopyAsync(folder, file->Name, NameCollisionOption::ReplaceExisting)).then([this, file](task<StorageFile^> task)
{
String^ path = "ms-appdata:///local/" + file->Name;
logoFile = ref new Uri(path);
});
}
});
You're attempting to copy the picked file into the app package location (InstalledLocation), rather than into an app data folder. The package location is read-only, so CopyAsync should be failing. Use StorageFolder^ localFolder = ApplicationData::Current->LocalFolder; instead.
Also, you do need the /// in ms-appdata:///local because it's a shorthand to omit the package id, but you need only a single / elsewhere in the URI.
Finally, be aware that tile images must be 200KB or smaller and 1024x1024 or smaller, or they won't appear at all. If you're using photographic images, use a JPEG compression; vector images compress best with PNG. For more on dealing with this, see Chapter 16 of my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, specifically "Basic Tile Updates" starting on page 887 and the sidebar on page 899. The content is applicable to apps written in all languages, and it's a free book so there's no risk.
i have a question. If there is a possibility at windows phone 8 at visual studio to create button event to read text file? i know about streamReader and if i declare wchich exacly file i want to read, but if i want to choose from list of files wchich i want to display. i did research on the Internet but i didint find an answer. I know i can use isolatedStorage to read music, video, image but not text files, on the app i created few files with text in it and i want users to have posibility to display one from this file, whichever they want to see. So, can you tell me how to do this?
You can use IsolatedStorage to read any file type you wish. You must of been using something like a Launcher that filters out the file type based on the Chooser.
You can open a file like this:
private async Task<string> ReadTextFile(string file_name)
{
// return buffer
string file_content = "";
// Get the local folder
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
if (local != null)
{
// Get the file
StorageFile file;
try
{
file = await local.GetFileAsync(file_name);
}
catch (Exception ex)
{
// no file, return empty
return file_content;
}
// Get the stream
System.IO.Stream file_stream = await file.OpenStreamForReadAsync();
// Read the data
using (StreamReader streamReader = new StreamReader(file_stream))
{
file_content = streamReader.ReadToEnd(); // read the full text file
streamReader.Close();
}
// Close the stream
file_stream.Close();
}
// return
return file_content;
}
If you want to get the PackageLocation (files that you added into the project like assets and images) then replace the LocalFolder with
Windows.ApplicationModel.Package package = Windows.ApplicationModel.Package.Current;
Windows.Storage.StorageFolder installedLocation = package.InstalledLocation;
With Windows Phone 8.1, File Pickers are allowed, consisting the same functionality you are expecting, so probably you might want to upgrade your app to WP8.1.
Here's more info on this API : Working with File Pickers
There is Windows.Storage.FileIO.WriteBufferAsync method, but it's not supported on WP8. What's the right way to save a buffer to a storage file on a phone?
You have a couple options as to how you can proceed here. However, the extensions you'll need to make working with IBuffer objects easier are all located in the System.Runtime.InteropServices.WindowsRuntime namespace. You may also need the System.IO namespace for the OpenStreamForWriteAsync extension.
private async void SaveBuffer(Windows.Storage.Streams.IBuffer myBuffer)
{
Windows.Storage.StorageFile myFile = await Windows.Storage.StorageFile.GetFileFromPathAsync("...");
using (var writeStream = await myFile.OpenStreamForWriteAsync())
{
// Option 1: Cast to stream and copy
myBuffer.AsStream().CopyTo(writeStream);
// Option 2: Cast to byte array and write
var content = myBuffer.ToArray();
writeStream.Write(content, 0, content.Length);
}
}
Ref:
IBuffer.AsStream Extension
IBuffer.ToArray Extension