I am working on an IOS App which I create with Unity in C# (Unity 2018.2.5f1). Now I'm trying to upload an image to Firebase Storage to get familiar with it. Unfortunately this doesn't work.
I assume there is a problem with the path to the local file. I get the following error in XCode when running the app.
Firebase.Storage.Storage.StorageException: There is no object at the desired reference.
The file swift.jpg definitively exists on the iPhone.
Your help is very welcome.
using UnityEngine;
using Firebase.Storage;
using System.Threading.Tasks;
public class Upload : MonoBehaviour {
FirebaseStorage storage;
StorageReference storage_ref;
// Use this for initialization
void Start () {
storage = FirebaseStorage.DefaultInstance;
storage_ref = storage.GetReferenceFromUrl("gs://[My Storage URL]");
// File located on disk
string local_file = Application.persistentDataPath + "/" + "swift.jpg";
// Create a reference to the file you want to upload
StorageReference image_ref = storage_ref.Child("images/swift.jpeg");
// Upload the file to the path
image_ref.PutFileAsync(local_file)
.ContinueWith((Task<StorageMetadata> task) => {
if (task.IsFaulted || task.IsCanceled) {
Debug.Log(task.Exception.ToString());
// Uh-oh, an error occurred!
}
else {
// Metadata contains file metadata such as size, content-type, and download URL.
// StorageMetadata metadata = task.Result;
// string download_url = metadata.DownloadUrl.ToString();
// Debug.Log("Finished uploading...");
// Debug.Log("download url = " + download_url);
}
});
}
}
Try
string local_file = "file:///" + Application.persistentDataPath + "/" + "swift.jpg";
Or
string local_file = "file://" + Application.persistentDataPath + "/" + "swift.jpg";
Or
string local_file = "file:\\" + Application.persistentDataPath + "/" + "swift.jpg";
Hope one of these will work.
Related
I want to have some of my files in my assets folder to be copied to the android device. How do you do it?
I have tried several ways, like opening the files via debugging, it works in the PC. But when I have transferred it to the android device, it doesn't work or either copy it whatnot.
public void OpenPDF(string filename) //this opens the file I have in my pc. Via debugging in Unity.
{
TextAsset pdfTem = Resources.Load("PDFs/" + filename, typeof(TextAsset)) as TextAsset;
System.IO.File.WriteAllBytes(Application.persistentDataPath + "/" + filename + ".pdf", pdfTem.bytes);
Application.OpenURL(Application.persistentDataPath + "/" + filename + ".pdf");
}
public void openPDFfromSD()
{
Application.OpenURL("/mnt/sdcard/openme.pdf"); //this doesn't open the PDF file I have in my sd card.
}
public void legitOpen(string nameOfFile) //this opens the file I have in my pc. Via debugging in Unity.
{
string realPath = Application.persistentDataPath + "/" + nameOfFile + ".pdf";
if (!System.IO.File.Exists(realPath))
{
if (!System.IO.Directory.Exists(Application.persistentDataPath + "/PDFs/"))
{
System.IO.Directory.CreateDirectory(Application.persistentDataPath + "/PDFs/");
}
WWW reader = new WWW(Application.streamingAssetsPath + "/PDFs/" + realPath);
while (!reader.isDone) { }
System.IO.File.WriteAllBytes(realPath, reader.bytes);
}
Application.OpenURL(realPath);
}
In general you shouldn't use string concatenation directly to build system paths.
Rather always use Path.Combine which automatically uses the correct path separator (/ or \) according to your target platform.
Also later in new WWW you have added both the leading Application.streamingAssetsPath and Application.persistentDataPath already in realPath.
public void OpenPDF(string filename)
{
TextAsset pdfTem = Resources.Load("PDFs/" + filename, typeof(TextAsset)) as TextAsset;
var filePath = Path.Combine(Application.persistentDataPath, filename + ".pdf";
System.IO.File.WriteAllBytes(filePath), pdfTem.bytes);
Application.OpenURL(filePath);
}
public void legitOpen(string nameOfFile)
{
string realPath = Path.Combine(Application.persistentDataPath, nameOfFile + ".pdf");
if (!System.IO.File.Exists(realPath))
{
if (!System.IO.Directory.Exists(Path.Combine(Application.persistentDataPath, "PDFs"))
{
System.IO.Directory.CreateDirectory(Path.Combine(Application.persistentDataPath, "PDFs"));
}
WWW reader = new WWW(Path.Combine(Application.streamingAssetsPath, "PDFs", nameOfFile + ".pdf");
while (!reader.isDone) { }
System.IO.File.WriteAllBytes(realPath, reader.bytes);
}
Application.OpenURL(realPath);
}
Btw if you want to prevent your app from completely freezing until the loading is done I would recommend to use a Coroutine and UnityWebRequest.Get like
public void legitOpen(string nameOfFile)
{
StartCoroutine(legitOpenRoutine(nameOfFile));
}
private IEnumerator legitOpenRoutine(string nameOfFile)
{
string realPath = Path.Combine(Application.persistentDataPath, nameOfFile + ".pdf");
if (!System.IO.File.Exists(realPath))
{
if (!System.IO.Directory.Exists(Path.Combine(Application.persistentDataPath, "PDFs"))
{
System.IO.Directory.CreateDirectory(Path.Combine(Application.persistentDataPath, "PDFs"));
}
using (var reader = new UnityWebRequest.Get(Path.Combine(Application.streamingAssetsPath, "PDFs", nameOfFile + ".pdf"))
{
yield return reader.SendWebRequest();
if (webRequest.isNetworkError)
{
Debug.Log(pages[page] + ": Error: " + webRequest.error);
return;
}
System.IO.File.WriteAllBytes(realPath, reader.bytes);
}
}
Application.OpenURL(realPath);
}
Or even completely use an async method using CopyToAsync
public void legitOpen(string nameOfFile)
{
legitOpenAsync(nameOfFile);
}
private async void legitOpenAsync(string nameOfFile)
{
var realPath = Path.Combine(Application.persistentDataPath, nameOfFile + ".pdf");
var pdfPath = Path.Combine(Application.persistentDataPath, "PDFs");
if (!System.IO.File.Exists(realPath))
{
if (!System.IO.Directory.Exists(pdfPath)
{
System.IO.Directory.CreateDirectory(pdfPath);
}
using(var sourceFile = File.Open(Path.Combine(Application.streamingAssetsPath, "PDFs", nameOfFile + ".pdf"), FileMode.Open, FileAccess.Read, FileShare.Read)
{
using(var targetFile = File.Open(realPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write))
{
await sourceFile.CopyToAsync(targetFile);
}
}
}
Application.OpenURL(realPath);
}
However
note that Application.OpenURL:
Android: Due security changes in Android 7.0 (More information), Application.OpenURL can no longer be used for opening local app files, you need to use FileProvider which allows you to share files with other applications.
and
iOS: Application.OpenURL cannot be used for opening local files.
Therefore this won't work at all
public void openPDFfromSD()
{
Application.OpenURL("/mnt/sdcard/openme.pdf");
}
I thought that should be simple, yet I can't figure it out.
I keep getting the error: System.IO.DirectoryNotFoundException: Could not find a part of the path "/storage/emulated/0/Pictures/Screenshots/name.jpg".
The code:
string root = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).Path;
File myDir = new File(root + "/Screenshots");
myDir.Mkdirs();
string timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").Format(new Date());
string fname = CommunicationHandler.GetNickname() + "|" + timeStamp + ".jpg";
File file = new File(myDir, fname);
if (file.Exists())
file.Delete();
try
{
using (System.IO.Stream outStream = System.IO.File.Create(file.Path))
{
finalBitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, outStream);
outStream.Flush();
outStream.Close();
}
}
catch (Exception e)
{
Toast.MakeText(Activity, e.ToString(), ToastLength.Long).Show();
}
Also, I can't access manually to /storage/emulated/0..
Why can't I manage to save the bitmap to my phone gallery? What's the problem in the code above?
If you want to create a new directory, you can use System.IO.Directory.CreateDirectory(root); to create it.
//create a directory called MyCamera
string root = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDcim).ToString() + "/MyCamera/";
//create the Directory
System.IO.Directory.CreateDirectory(root);
As taken from here:
MediaScannerConnection.scanFile(this, new String[]{file.toString()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
}
Also, note that you could just add an image to the gallery via a simple line:
MediaStore.Images.Media.insertImage(applicationContext.getContentResolver(), IMAGE ,"nameofimage" , "description");
I put some png files into /Assets/StreamingAssets, what i want to do is load a image's texture from that floder.
here is my c# code below:
string path = "file://" + Application.streamingAssetsPath + "/sunny.png";
private IEnumerator GetMatByWWW(string url)
{
WWW www = new WWW(url);
yield return www;
RawImage rawImage = gameObject.GetComponent<RawImage>();
rawImage.texture = www.texture;
}
On OSX, the code working perfect. But i need to make it working on IOS. So i remove the prefix of "file://" and the path is :
string path = Application.streamingAssetsPath + "/sunny.png";
It just showed a red question-mark after build and run at my iPhone. And i also tried
string path = "file:/" + Application.streamingAssetsPath + "/sunny.png";
Who can tell me how to do it correctly?
string ab_path = Application.streamingAssetsPath + "/" + "bundlename";
AssetBundle ab = AssetBundle.LoadFromFile(ab_path);
if(ab == null)
{
Debug.Log("ab is null");
}
Gameobject prefab = ab.LoadAsset<GameObject>("prefab_name");
Gameobject go = GameObject.Instantiate(prefab);
please check this link.
https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromFile.html
I have a website where photographers can upload photos. The site is being hosted on an shared azure web app and The photos and thumbnails of the photos are uploaded to Azure Blob storage and a record is written to the db. Photographers can upload potentially up to 700mb of photos at a time.
My problem
I had a synchronous method for the upload that A) took ages to run and B) failed with the "There is not enough space on disk" error message. I'm guessing this is because the temp folder for a Azure shared web app is restricted to 200mb.
I tried to implement a Asynchronous method to help speed up the upload but it completes the first photo successfully (ie blobs and db records exist) and then It appears to just hang. This is my first attempt at writing an asynchronous method.
I also don't know how to fix the temp folder size issue.
My calling method
public static async Task<Tuple<bool, string>> UploadAsync(HttpPostedFileBase[] photos, Bookings booking, string photoType, ApplicationUser user)
{
// For each file to be uploaded
foreach (HttpPostedFileBase file in photos)
{
try
{
await UploadPhotoFromFileAsync(file, user, booking.BookingsId, photoType);
}
catch (Exception ex)
{
// Not Implemented
}
}
return new Tuple<bool, string>(true, "Photos uploaded successfully");
}
My Photo Upload method
public static Task UploadPhotoFromFileAsync(HttpPostedFileBase file, ApplicationUser user, int bookingId, string photoType)
{
return Task.Run(() =>
{
using (ApplicationDbContext dbt = new ApplicationDbContext())
{
Bookings booking = dbt.Bookings.Find(bookingId);
// Craete a new record in the UserFiles table
Photos photo = new Photos();
photo.BookingsId = booking.BookingsId;
photo.PhotoType = photoType;
photo.FileName = Path.GetFileName(file.FileName);
string confirmedDate = string.Empty;
if (booking.ConfirmedDate.HasValue)
{
DateTime actualConfirmedDate = booking.ConfirmedDate.Value;
confirmedDate = actualConfirmedDate.Year.ToString() + actualConfirmedDate.Month.ToString() + actualConfirmedDate.Day.ToString();
}
string blobName = string.Empty;
string blobThumbName = string.Empty;
if (photoType == "SamplePhoto")
{
// Get the count of the sample photos in the gallery
List<Photos> samplePhotos = dbt.Photos.Where(m => m.BookingsId == booking.BookingsId && m.PhotoType == "SamplePhoto").ToList();
blobName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (samplePhotos.Count).ToString() + "_sample" + Path.GetExtension(file.FileName);
blobThumbName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (samplePhotos.Count).ToString() + "_sample_thumb" + Path.GetExtension(file.FileName);
}
else
{
// Get the count of the sample photos in the gallery
List<Photos> photos = dbt.Photos.Where(m => m.BookingsId == booking.BookingsId && m.PhotoType == "GalleryPhoto").ToList();
blobName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (photos.Count).ToString() + Path.GetExtension(file.FileName);
blobThumbName = "TS_" + booking.location.Location.Replace(" ", "") + "_" + booking.BookingsId.ToString() + "_" + confirmedDate + "_" + (photos.Count).ToString() + "_thumb" + Path.GetExtension(file.FileName);
}
// Create the Thumbnail image.
CloudBlobContainer thumbnailBlobContainer = _blobStorageService.GetCloudBlobContainer("thumbnails");
if (CreateThumbnailImageFromHttpPostedFileBase(file, blobThumbName, photo))
{
photo.ThumbnailBlobName = blobThumbName;
photo.ThumbnailBlobUrl = thumbnailBlobContainer.Uri + "/" + blobThumbName;
}
CloudBlobContainer blobContainer = _blobStorageService.GetCloudBlobContainer("photos");
photo.BlobName = blobName;
photo.BlobUrl = blobContainer.Uri + "/" + blobName;
photo.DateCreated = DateTime.Now;
photo.CreatedBy = user.Id;
dbt.Photos.Add(photo);
dbt.SaveChanges();
booking.Photos.Add(photo);
dbt.SaveChanges();
//Upload to Azure Blob Storage
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(blobName);
blob.UploadFromStream(file.InputStream);
}
});
}
The Azure Storage library includes Async-methods and you should take advantage of those. And instead of wrapping your controller method with Task.Run, you can use ASP.NET MVC's built-in async-capabilities.
So, first, make the controller's method async:
public async Task<ContentResult> UploadPhotoFromFileAsync...
Then remove all the Task.Runs.
Lastly, call Azure Storage Library's async-methods:
var blob = blobContainer.GetBlockBlobReference(blobName);
await blob.UploadFromStreamAsync(file.InputStream);
The problem was actually being caused by the request length set in the Web.Config. It wasn't high enough to allow for the size of the photos being uploaded. I simply added the following code to the Web.Config.
<system.web>
<httpRuntime targetFramework="4.5" maxRequestLength="1048576" executionTimeout="900" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
</system.webServer>
Alright so I've managed to read/write files programatically in C# in Xamarin Studio. And it's working on my device.
However, when I output the exact path that the file is being written to, to the console, that path doesn't even exist anywhere in the entire phone!!!!
How is that?
using System;
using System.IO;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace ToolbarSample
{
[Activity(Label = "ToolbarSample", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
string content = "Jason rules";
string filename = "file.txt";
var documents = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.button);
TextView viewer = FindViewById<TextView>(Resource.Id.textView1);
if (File.Exists(documents + #"/" + filename))
{
string newContent = File.ReadAllText(documents + #"/" + filename);
if (viewer != null)
{
viewer.Text = newContent;
Console.WriteLine("File exists in: " + documents + #"/" + filename);
}
}
if (button != null)
{
button.Click += delegate
{
button.Enabled = false;
if (!Directory.Exists(documents))
{
viewer.Text = "Directory not found: " + documents;
}
else
{
Console.WriteLine("Directory exists.");
File.WriteAllText(documents + #"/" + filename, content);
if (!File.Exists(documents + #"/" + filename))
{
viewer.Text = "File not found: " + documents + #"/" + filename;
}
else
{
string newContent = File.ReadAllText(documents + #"/" + filename);
if (viewer != null)
{
viewer.Text = newContent;
Console.WriteLine("File exists in: " + documents + #"/" + filename);
}
}
}
};
}
}
}
}
The following gets outputted to the console upon successful read from internal sdcard:
Directory exists. File exists in:
/data/data/ToolbarSample.ToolbarSample/files/file.txt
But using (many different) file managers - all with root access - and hidden files being shown - I cannot navigate to that path because it does not exist. I even did a whole phone search for "file.txt" and not a single result showed up. Yet I am able to read that file whenever I open my app and click the button.
The file at the location you have specified does exist. You cannot access that location from your PC via USB and File Explorer, but you can access the location (and the file) if you use a good File Manager app like Root Explorer.
If you really want your users to be able to access these saved files, I'd suggest that you save these files to a better location so that the user can easily transfer files from their phone to the computer via USB.
It quite simple both Read/Write data from File .
public String ReadFileData()
{
var path = global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
var filename = Path.Combine(path.ToString(), "loginSystem.txt");
String line;
objData = new List<UsersData>();
// Read the file and display it line by line.
StreamReader file = new StreamReader(filename);
while ((line = file.ReadLine()) != null)
{
string[] words = line.Split(',');
if (words.Length != 1)
objData.Add(new UsersData(words[0], words[1], words[2]));
}
file.Close();
return String.Empty;
}
Save data into file
private string SaveDataToSd(String FirstName, String Address, String Password)
{
var path = global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
var filename = Path.Combine(path.ToString(), "loginSystem.txt");
String contents = FirstName + "," + Password + "," + Address;
try
{
using (StreamWriter data_file = new StreamWriter(filename, true))
{
data_file.WriteLine(contents);
}
return contents;
}
catch (Exception ex)
{
RunOnUiThread(() =>
{
var builder = new AlertDialog.Builder(this);
builder.SetMessage(ex.InnerException + "Saving file went wrong");
builder.SetTitle("Unable to save file");
builder.Show();
});
return String.Empty;
}
}