Windows Phone 8 IsolatedStorageFileStream - c#

I'm making a WP8.1 Silverlight app, it's basically done, but I have one big problem.
public void CheckAndCopyDBToIsoStore(params bool[] list)
{
// Obtain a reference to the application's isolated storage
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
//Only copy db file over if it does not already exist
if (!iso.FileExists("TankolasKonyveloDB.sdf") || (list.Length == 1 && list[0] == true))
{
using (Stream input = Application.GetResourceStream(new Uri("TankolasKonyveloDB.sdf",
UriKind.Relative)).Stream)
{
using (IsolatedStorageFileStream output = iso.CreateFile("TankolasKonyveloDB.sdf"))
{
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the file from the install folder to isolated storage.
while ((bytesRead = input.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
output.Write(readBuffer, 0, bytesRead);
}
output.Close();
output.Dispose();
iso.Dispose();
}
}
}
}
I have this method in App.xaml.cs, it is called once in the constructor on application start without parameters and it copies the empty database to the isostore if it's not already there. It's working well. The next thing I'd like to do is, that if I click a button I call this method again with a bool argument with a value of true. When I do this, I want to copy the empty database again over the existing in runtime.
At the line
IsolatedStorageFileStream output = iso.CreateFile("TankolasKonyveloDB.sdf")
I get an exception:
Operation not permitted on IsolatedStorageFileStream
I googled it and the answers were I must close and dispose the connection and everything, but the problem is still there. Instead of iso.CreateFile I tried OpenFile with FileMode.OpenOrCreate, Create and CreateNew... None of them worked.
So the thing is, I want to copy the .sdf file to the isostore if it doesn't already exist and I don't want to copy it again on every startup, unless I express that by clicking that button.
If somebody has a solution to this or an idea, please help me!

Related

Unzip .zip file from Assets folder to Internal Storage (Xamarin.Android)

So the question is pretty simple. I'm using Xamarin.Android and I have a zip file in the Assets folder named "MyZipFile.zip", which I want extracted to the following path: System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
It sounds simple enough, but I cannot figure out how to read the Asset into memory through the AssetManager and then unzip it at the targeted location.
Is there a simple way to do this?
The Android Java framework includes a Java.Util.Zip package, so without adding any additional app libraries, I directly use it instead of using C# framework code, thus no bloat that linking can not remove.
So basically you are creating an asset stream and feeding that to a ZipInputStream and iterating over each ZipEntry in that zip stream to either create directories or files to your destination path.
UnZipAssets
public void UnZipAssets(string assetName, string destPath)
{
byte[] buffer = new byte[1024];
int byteCount;
var destPathDir = new Java.IO.File(destPath);
destPathDir.Mkdirs();
using (var assetStream = Assets.Open(assetName, Android.Content.Res.Access.Streaming))
using (var zipStream = new ZipInputStream(assetStream))
{
ZipEntry zipEntry;
while ((zipEntry = zipStream.NextEntry) != null)
{
if (zipEntry.IsDirectory)
{
var zipDir = new Java.IO.File(Path.Combine(destPath, zipEntry.Name));
zipDir.Mkdirs();
continue;
}
// Note: This is deleting existing entries(!!!) for debug purposes only...
#if DEBUG
if (File.Exists(Path.Combine(destPath, zipEntry.Name)))
File.Delete(Path.Combine(destPath, zipEntry.Name));
#endif
using (var fileStream = new FileStream(Path.Combine(destPath, zipEntry.Name), FileMode.CreateNew))
{
while ((byteCount = zipStream.Read(buffer)) != -1)
{
fileStream.Write(buffer, 0, byteCount);
}
}
Log.Debug("UnZipAssets", zipEntry.Name);
zipEntry.Dispose();
}
}
}
Usage:
UnZipAssets("gameModLevels.zip", Path.Combine(Application.Context.CacheDir.AbsolutePath, "assets"));
Note: Even through the asset/zip steam is fast, depending upon number/size of the zip entries and the speed of the flash the entry is being written to, this should be done on a background thread as not to block UI thread and cause an ANR

C# Getting Runtime error : The process cannot access the file because it is being used by another process

Here is my code:
enter image description here
using System.IO;
namespace Randoms
{
public class Program
{
public static void Main()
{
byte[] buffer = new byte[10240]; // buffer size
string path = #"C:\Users\RAHUL\Desktop\file.txt";
using (FileStream source = new FileStream(path, FileMode.Open, FileAccess.Read))
{
long fileLength = source.Length;
using (FileStream dest = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
{
long totalBytes = 0;
int currentBlockSize = 0;
while ((currentBlockSize = source.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytes += currentBlockSize;
double percentage = (double)totalBytes * 100.0 / fileLength;
dest.Write(buffer, 0, currentBlockSize);
}
}
}
}
}
}
Please check the image which shows the error which I am getting.I have tried to change the FileAccess multiple times but not getting any luck.
This post explains how to both read and write to a file using a single stream:
How to both read and write a file in C#
Consider you may have the file still open from a previous erroneous run. Use a tool like Sysinternals Process Monitor or Unlocker to verify it isn't open by another instance.
How to use Process Monitor:
http://www.manuelmeyer.net/2013/09/tooltips-unlocking-files-with-sysinternals-process-monitor/
Both source and dest are referencing the same file. In the first instance (source) you open it exclusively (ie not shared).
In the second instance (dest) you now want to create the file which you opened in the first instance, but allow it to be shared.
Since the source is already open an in use you cannot write over the top of it using dest.
I think what you may be really want is to have the path parameter for the dest to be different to path parameter for the source, since you are essentially trying to re-write the same data into the same file at the same location right now.

Image loss quality after upload via HttpPostedFile.SaveAs(imgPath)

I'm working in a project that doesn't use much of the .net framework and instead work with Request.Form posts.
The code that was being used to save the images (this work, but loss quality) is this one:
files[0].SaveAs(HttpContext.Current.Server.MapPath("../uploads/") + filename);
So I tried to change to this, but now it doesn't even save the image. (the uploadStream.Read(buffer, 0, buffer.Length) comes with the value of 0.
string imagePath = HttpContext.Current.Server.MapPath("../uploads/") + filename;
using (BinaryReader uploadStream = new BinaryReader(files[0].InputStream))
{
using (FileStream fileStream = new FileStream(imagePath, FileMode.Create))
{
byte[] buffer = new byte[32768];
int read;
while ((read = uploadStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, read);
}
}
}
I built this code basing myself on the question/answers of Image upload without loss of quality. I'm using .net 4.0 on the application.
Is there another way, or what I was doing is the right way and I just missed something? PS: I don't get any error and on the database, I save the correct information, but I don't get the file on the folder. The upload to that folder works, since it work with the SaveAs() method.
PS: I may be wrong, about SaveAs being the reason to loss of quality on the image, but the files[0] come right from the HttpFileCollection and the upload is only there.

Database file cannot be found

In my Windows Phone 8 C#/XAML .NET 4.5 project I'm using (with the help of LINQ-2-SQL) a local database (SQLite probably) created by another member of the team.
But when I run the application, it throws an exception:
The database file cannot be found. Check the path to the database. [ Data Source = C:\Data\Users\DefApps\AppData\{XXXXX-XXXXX-XXXXXX-XXXXX}\Local\database.sdf ]
The .sdf file with the database is in the project in /Database/database.sdf and the properties are set to Build action: Embedded resource & Copy to output directory: Copy always.
In the databaseContext.cs, which is a class used as context (not sure I'm naming it right, I'm new to linq-2-sql), the connection string is defined as:
Data Source=isostore:/database.sdf
Is this the right settings? What can I do to make it work?
You will have to move the database to isolated storage first. Heres how you could do it.
public static void MoveReferenceDatabase()
{
// Obtain the virtual store for the application.
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
// Create a stream for the file in the installation folder.
using (Stream input = Application.GetResourceStream(new Uri("DutchMe.sdf", UriKind.Relative)).Stream)
{
// Create a stream for the new file in the local folder.
using (IsolatedStorageFileStream output = iso.CreateFile("DutchMe.sdf"))
{
// Initialize the buffer.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the file from the installation folder to the local folder.
while ((bytesRead = input.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
output.Write(readBuffer, 0, bytesRead);
}
}
}
}
Else
set the connection string to Data Source=appdata:/database.sdf . I am not very sure about the second solution.

c# copy/move into locked file/stream

I need help in how to lock the file, copy it, modify copy, and save copy back to original file, while the original file remains locked.
Here is the current flow:
User opens the file, the application copies it into a temporary folder and locks the original file with the following line
_lockStream = new FileStream(Path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
Then when it comes to save the temp file back to the original file, currently I am using the following routine (destination = _lockStream, and source = temp file's stream):
public static void Copy(Stream source, Stream destination, int bufferSize)
{
int readed = 0;
byte[] buffer = new byte[bufferSize];
destination.SetLength(source.Length);
destination.Position = 0;
while ((readed = source.Read(buffer, 0, buffer.Length)) > 0)
{
destination.Write(buffer, 0, readed);
}
destination.Flush();
}
I would prefer to use File.Copy instead, but I don't know how to make it working with locked file, even if file is locked by the application.
And, what's worse, my method it's not safe, if application or system crashes in the middle, the original file is corrupted. I think that more correct approach would be copy to the same folder, and then move (or just simply move) but I don't know how to do it retaining lock on the original file.
So, now to make it safe I release file lock, and use File.Copy, then obtain lock again. It works, but for some milliseconds the file is unlocked and can be locked by other processes.
What is best way of doing such things?
In order to make your method safe you can use TransactionScope like this:
using(var scope = new TransactionScope())
{
Copy(source, destination, buffersize);
scope.Complete();
}

Categories