In Xamarin.iOS Share Extension, I'd like to store my selected files (like pdf, images, word etc.) in my NSUserDefaults and when the main application starts, I'll have access to the files stored in it.
Here is my file class :
public class MyClass {
public string FileName { get; set; }
public byte[] Content { get; set; }
}
So in LoadItem in DidSelectPost methods, I create by object by using byte[] of files. Then for saving datas in NSUserDefaults, I convert my object to JSON like this (by using Newtonsoft.Json library):
string jsonString = JsonConvert.SerializeObject(myFileObject);
and I set it to NSUserDefaults object like that:
NSUser.SetValueForKey(new NSString(myFileObject), new NSString("FileSharing" + count));
or
NSUser.SetValueForKey(new NSString(myFileObject), new NSString("FileSharing"+ count));
And after I'll synchronise my items : NSUser.Synchronize());
Everything goes well, but when the main application open, the new data is not here.
string toDesralize = nSUser.StringForKey("FileSharing0");
I've tried for many files, and I've found out that this issue works only for files with low height and it doesn't work for files like 14mb. How can i save files with high height in NSUserDefaults? Is there any other way for doing the same job ?
You can use file system to store and read data in Xamarin.iOS:
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var filename = Path.Combine(documents, "Write.txt");
//save text
File.WriteAllText(filename, "Write this text into a file");
//save bytes
File.WriteAllBytes(filename,yourBytes);
And the read methods:
var text = File.ReadAllText("TestData/ReadMe.txt");
Console.WriteLine(text);
var bytes = File.ReadAllBytes("path");
Related
I have a pdf that I download from the server and save it. Next I open the file from the file path within a UIWebView. This works the first time I launch the app. When I relaunch the app again, even thought the file path is the same, the document does not open. Also, the document does exist in the document folder of the app.
I am doing something like :-
SaveToFolder.cs
var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), fileName);
using (FileStream destinationStream = File.Create(filePath))
{
await documentStream.CopyToAsync(destinationStream);
}
File path after saving the document first time :-
/var/mobile/Containers/Data/Application/C3EA2325-81CA-4EC9-8C03-479ACF7EE330/Documents/Insufficiency.pdf
File Path on app relaunch
/var/mobile/Containers/Data/Application/C3EA2325-81CA-4EC9-8C03-479ACF7EE330/Documents/Insufficiency.pdf
Is there something Iam doing wrong?
I have created a file in iOS for reading & writing file. Please have a look in iOS
using System;
using Xamarin.Forms;
using FileReader.iOS;
using System.IO;
using FileReader;
using Foundation;
using System.Linq;
using System.Threading.Tasks;
[assembly: Dependency(typeof(SaveAndLoadiOS))]
namespace FileReader.iOS
{
public class SaveAndLoadiOS : LoadAndSave
{
public static string DocumentPath
{
get
{
var documentURL = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User).Last();
return documentURL.Path;
}
}
public string CreatePath(string fileName)
{
return Path.Combine(DocumentPath, fileName);
}
public async Task SaveTextAsync(string fileName, string text)
{
string path = CreatePath(fileName);
if (IsFileExits(fileName))
{
File.Delete(path);
}
using (StreamWriter sw = File.CreateText(path))
await sw.WriteAsync(text);
}
public async Task<string> LaodTextAsync(string fileName)
{
string path = CreatePath(fileName);
using (StreamReader sr = File.OpenText(path))
return await sr.ReadToEndAsync();
}
public bool IsFileExits(string fileName)
{
return File.Exists (CreatePath(fileName));
}
}
}
For reading from my .CS class (subclass of ContentPage), Below is the code
var tempFileService = DependencyService.Get<LoadAndSave>();
var itemFile = await tempFileService.LaodTextAsync(tempFile.StoredFileName);
var rootobject = JsonConvert.DeserializeObject<Rootobject>(itemFile);
Where LoadAndSave is an interface as below
using System;
using System.Threading.Tasks;
namespace FileReader
{
public interface LoadAndSave
{
Task SaveTextAsync(string fileName, string text);
Task<string> LaodTextAsync(string fileName);
bool IsFileExits(string fileName);
}
}
Hope it helps.
I ran into the same issue a while ago. You can refer Can't find saved file (in device) after restarting the app
According to the answer
You shouldn't store raw file paths for persistence (or if you do, know that the root can move on you). A better practice would be to only store the relative part of the path and always attach it to the current "root" path in question (particularly if you might be sharing data across devices as with iCloud).
Maybe your root is changing as well. You can change your approach and append the filename with the default path to your documents folder like so in Xamarin:-
var docsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
filePath = docsPath +"/" + "Insuffeciency.pdf";
Also, consider changing your Personal folder to MyDocuments folder while saving the file.
I am trying to use the Rotativa component to store (not to show) a copy of the invoice permanently on web server disk. Two questions:
Why I need to specify a controller action? ("Index", in this
case)
How do I write the FileContentResult on local disk without
displaying it?
Thanks.
Here is my code:
[HttpPost]
public ActionResult ValidationDone(FormCollection formCollection, int orderId, bool fromOrderDetails)
{
Order orderValidated = context.Orders.Single(no => no.orderID == orderId);
CommonUtils.SendInvoiceMail(orderValidated.customerID , orderValidated.orderID);
var filePath = Path.Combine(Server.MapPath("/Temp"), orderValidated.invoiceID + ".pdf");
var pdfResult = new ActionAsPdf("Index", new { name = orderValidated.invoiceID }) { FileName = filePath };
var binary = pdfResult.BuildPdf(ControllerContext);
FileContentResult fcr = File(binary, "application/pdf");
// how do I save 'fcr' on disk?
}
You do not need the FileContentResult to create a file. You've got the byte array which can be saved directly to the disk:
var binary = pdfResult.BuildPdf(ControllerContext);
System.IO.File.WriteAllBytes(#"c:\foobar.pdf", binary);
string FileName="YOUR FILE NAME";
//first give a name to file
string Path=Server.MapPath("YourPath in solution"+Filename+".Pdf")
//Give your path and file extention. both are required.
binary[]= YOUR DATA
//Describe your data to be save as file.
System.IO.File.WriteAllBytes(Path, binary);
Thats simple...
I have an bitmap in System.Drawing. I know it must be converted to a byte[] to be stored in my table.
My table field:
public class Task
public byte? TaskImage { get; set; }
I have this in line code so far:
MemoryStream ms = new MemoryStream();
mybmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
Task.TaskImage =
db.SaveChanges();
I've been referenced to this:
public static byte[] ImageToByteArray(Image image)
{
var memoryStream = new MemoryStream();
image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg); // consider format
return memoryStream.ToArray();
}
but can't figure out how to apply it. This attempt doesn't work.
Task.TaskImage = Image.FromStream(ms.ToArray())
Can someone provide the code to go from the System.Drawing to Task.TaskImage= in inline code, or how to reference the function ImageToByteArray(Image image) in my code? In my MVC project, where is the proper place to put this function ImageToByteArray(Image image) if used?
You're on the right track.
One mistake I see is that
public byte? TaskImage { get; set; }
Needs to be a byte array. That is only a single nullable byte. Change it to
public byte[] TaskImage { get; set; }
What is an image and how do we store it?
In it's simplest form, an image is just a series of bits that are organised in a particular way (like any virtual object stored on a computer).
Databases aren't very good at storing complex types of data; they typically store strings (varchar, for example), integers of various sizes, floating point numbers, boolean values (a bit) and so on. In order to store something complex like an image we have to split the image up in to bytes and give that to the database (they can handle bytes (groups of bits) easily). You seem to know all of this.
In order to save an image to the database we need to know what format it's in and we need to be able to read all the bytes of the image.
Streams (What is a stream?) are useful here. They allow us to read and write a sequence of bytes. .NET classes like Image may also be useful for loading information about an image.
Reading an image from a database
Suppose we have an image stored as a byte array in a database. Entity Framework loads the object for us as a Task object.
public class Task
{
public byte[] TaskImage { get; set; }
}
To load the image:
Task task;
var ms = new MemoryStream(task.TaskImage);
Image img = Image.FromStream(ms);
Or
Bitmap bmp = new Bitmap(ms);
Saving an image to a database
Task task = new Task();
MemoryStream ms = new MemoryStream();
Image img = Image.FromFile("...");
img.Save(ms, img.RawFormat);
ms.Position = 0;
task.TaskImage = new byte[ms.Length];
ms.Read(TaskImage, 0, (int)ms.Length);
dbContext.Tasks.Add(task);
dbContext.SaveChanges();
In my Grails project, I have a domain class that allows me to store some large files. It has the following structure:
class PatientMedicalArchive {
byte[] document1;
byte[] document2;
byte[] document3;
String descriptionDocument1;
String descriptionDocument2;
String descriptionDocument3;
static belongsTo = [patient:Patient, secUser:SecUser]
static constraints = {
descriptionDocument1(maxSize: 255)
descriptionDocument2(maxSize: 255)
descriptionDocument3(maxSize: 255)
}
static mapping = {
document1(sqlType: "longblob")
document2(sqlType: "longblob")
document3(sqlType: "longblob")
}
}
It allows me to store large files in database in correct way. The problem is that, when I need to edit one instance of this class, I need to fill the fields with the name of file uploaded. Is it possible? How can I do it?
I am uploading a file using the following code
[HttpPost]
public ActionResult ImportDeleteCourse(ImportFromExcel model)
{
var excelFile = model.ExcelFile;
if (ModelState.IsValid)
{
OrganisationServices services = new OrganisationServices();
string filePath = Path.Combine(HttpContext.Server.MapPath("../Uploads"),
Path.GetFileName(excelFile.FileName));
excelFile.SaveAs(filePath);
// ... snipped //
}
}
I do not really need to do store the uploaded excel file. Is there anyway I can process it without saving?
Note: The ImportFromExcel class is nothing but a model, which is basically:
public class ImportFromExcel
{
[Required(ErrorMessage = "Please select an Excel file to upload.")]
[DisplayName("Excel File")]
public HttpPostedFileWrapper ExcelFile { get; set; }
}
The most interesting part is that it wraps a HttpPostedFileWrapper.
Sure you can. As Patko suggested, the InputStream property can be used for another stream. For example I did this for an uploaded xml document to use with LINQ to XML:
XDocument XmlDoc = XDocument.Load(new StreamReader(viewmodel.FileUpload.InputStream))
Cheers,
Chris
The HttpPostedFileBase.InputStream property looks promising. You should be able to use that and save the data to whichever other stream you need to.