5
respostas

Java.IO.FileInputStream(file) - Como encontrar o Arquivo?

Bom dia. Meu código.

Page.xaml

<StackLayout>
        <Button x:Name="btnCamera" Command="{Binding CaptureImageFileCommand,Mode=OneWay}" Text="Camera"></Button>
        <Button x:Name="btnFiles" Command="{Binding OpenFileStorageCommand,Mode=OneWay}" Text="Files"></Button>
</StackLayout>

ViewModel.cs

public ICommand OpenFileStorageCommand { get; }
      public ICommand CaptureImageFileCommand { get; }


      OpenFileStorageCommand = new Command(ExecuteOpenFileStorageCommand);
      CaptureImageFileCommand = new Command(ExecuteCaptureImageFileCommand);

    //Métodos - não tem implementação pois vou fazer outra coisa com os bytes, mas está funcionando(camera)
    //estou usando a mesma interface ICamera no dependency.
     private void ExecuteOpenFileStorageCommand()
        {
            DependencyService.Get<ICamera>().CapturarMedia("FileStorage");
            MessagingCenter.Subscribe<byte[]>(this, "FileStorage",
                (bytes) =>
                {

                });
        }
        private void ExecuteCaptureImageFileCommand()
        {            
            DependencyService.Get<ICamera>().CapturarMedia("CameraImagem");
            MessagingCenter.Subscribe<byte[]>(this, "CameraImagem",
                (bytes) =>
                {

                });
        }

Activity.cs

 public void CapturarMedia(string media)
        {
            switch (media)
            {
                case "CameraImagem":
                    CameraImagem();
                    break;
                case "CameraVideo":
                    CameraVideo();
                    break;
                case "FileStorage":
                    FileStorage();
                    break;

            }
        }
private void CameraImagem()
        {
            Intent intent = new Intent(MediaStore.ActionImageCapture);

            File diretorio = new File(
                Android.OS.Environment.GetExternalStoragePublicDirectory(
                Android.OS.Environment.DirectoryPictures), "Imagens");

            if (!diretorio.Exists())
                diretorio.Mkdirs();

            arquivoImagem = new File(diretorio,
                System.DateTime.Now.Ticks.ToString() + ".jpg");

            intent.PutExtra(MediaStore.ExtraOutput,
                Android.Net.Uri.FromFile(arquivoImagem));

            var activity = Forms.Context as Activity;
            activity.StartActivityForResult(intent, 1);
        }

private void FileStorage()
        {
            Intent intent = new Intent(MediaStore.ExtraMediaAlbum);
            intent.SetType("*/*");
            intent.SetAction(Intent.ActionGetContent);

            var activity = Forms.Context as Activity;
            activity.StartActivityForResult(Intent.CreateChooser(intent, "Select File"), 2);
        }

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);

            if (resultCode == Result.Ok && requestCode == 1)
            {
                byte[] bytes;
                using (var stream = new Java.IO.FileInputStream(arquivoImagem))
                {
                    bytes = new byte[arquivoImagem.Length()];
                    stream.Read(bytes);
                }
                //string formmattedPic = Convert.ToBase64String(bytes);

                MessagingCenter.Send<byte[]>(bytes, "CameraImagem");
            }
            else if ((requestCode == 2) && (resultCode == Result.Ok) && (data != null))
            {
//O problema esta na leitura do caminho do arquivo
//que está na variável data, o Java.IO.FileInputStream(file)
//não encontra o arquivo
                string file = data.Data.ToString();
                byte[] bytes;
//Aqui neste ponto ocorre a exceção
                using (var stream = new Java.IO.FileInputStream(file))
                {
                    bytes = new byte[arquivoImagem.Length()];
                    stream.Read(bytes);
                }

                MessagingCenter.Send<byte[]>(bytes, "FileStorage");
            }
        }

O problema está na leitura do caminho do arquivo que está na variável data (em requestCode == 2), o Java.IO.FileInputStream(file) não encontra o arquivo... Existe outra forma de capturar o arquivo? Ou esta metodologia poderá ser ajustada? Se alguém souber e puder dar uma luz, agradeço!

5 respostas

Olá, Jefferson

No curso, fizemos esse procedimento de um jeito um pouco diferente.

Primeiro, definimos um arquivo MainActivity.cs, com as anotações devidas

using Android.Content;
using Xamarin.Forms;
using Android.Graphics;
using System.Collections.Generic;
using TestDrive2.Droid;

[assembly: Xamarin.Forms.Dependency(typeof(MainActivity))]
namespace TestDrive.Droid
{
    ...
}

Definimos uma variável estática na própria classe MainActivity.cs:

static Java.IO.File arquivoImagem;

No método TirarFoto, essa variável estática recebeu o valor do arquivo, do tipo Java.IO.File, que foi fornecido pelo método PegarArquivoImagem:

        public void TirarFoto()
        {
            Intent intent = new Intent(MediaStore.ActionImageCapture);

            arquivoImagem = PegarArquivoImagem();

            intent.PutExtra(MediaStore.ExtraOutput,
                Android.Net.Uri.FromFile(arquivoImagem));

            var activity = Forms.Context as Activity;
            activity.StartActivityForResult(intent, 0);
        }

        private static Java.IO.File PegarArquivoImagem()
        {
            Java.IO.File arquivoImagem;
            Java.IO.File diretorio = new Java.IO.File(
Android.OS.Environment.GetExternalStoragePublicDirectory(
Android.OS.Environment.DirectoryPictures), "Imagens");

            if (!diretorio.Exists())
                diretorio.Mkdirs();

            arquivoImagem =
                new Java.IO.File(diretorio, "MinhaFoto.jpg");
            return arquivoImagem;
        }

O método OnActivityResult é chamado quando a Activity finalmente retorna um valor. Então nesse método utilizamos o valor da variável estática arquivoImagem que foi previamente armazenada:

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);

            if (resultCode == Result.Ok)
            {
                byte[] bytes;
                using (var stream = new Java.IO.FileInputStream(arquivoImagem))
                {
                    bytes = new byte[arquivoImagem.Length()];
                    stream.Read(bytes);
                }
                MessagingCenter.Send<byte[]>(bytes, "FotoTirada");
            }
        }

Então acho que você pode tentar adaptar o seu código de acordo com o que fizemos em aula (Note que não utilizamos o valor da variável data, como no seu código).

Então... a variável data está lá porque não tem como saber de onde será selecionado o arquivo do celular... O usuário poderá selecionar um arquivo de qualquer lugar visto que o comando que utilizo é "ExtraMediaAlbum"... ele abre todos as categorias de armazenagem. Quando é disparado o evento OnActivityResult, a variável data vem carregada com o caminho do arquivo somente. É aqui o problema... Eu tento localizar o arquivo e utilizando "FileInputStream" pois ele permite passar o caminho. Nesse momento estoura a exception "File not found".

Eu imagino o seguinte... como eu estou no emulador... possivelmente o arquivo não exista mesmo... diferente da foto da câmera que vc definiu um local para gravar a imagem"arquivoImagem" no momento da captura. Talvez eu teria que emular com o celular par que eu possa ter um ambiente onde exista o arquivo. Vc tem mais experiência.... qual a sua visão?

string file = data.Data.ToString();
using (var stream = new Java.IO.FileInputStream(file))
                {
                    bytes = new byte[arquivoImagem.Length()];
                    stream.Read(bytes);
                }

Me ajuda ai... pois, parei por um tempo porque não consegui sair dessa fase...

A unica coisa que preciso é: Como capturar o arquivo que o usuário selecionou... só isso. Vlw

Então... O meu código só mudou um pouco com o intuito de aceitar foto ou arquivo existente. Note que coloquei um método para decidir qual botão o usuário clicou... se foi tirar foto ou escolher um arquivo.

 public void CapturarMedia(string media)
        {
            switch (media)
            {
                case "CameraImagem":
                    CameraImagem();
                    break;
                case "CameraVideo":
                    CameraVideo();
                    break;
                case "FileStorage":
                    FileStorage();
                    break;

            }
        }

Se foi foto, executa "CameraImagem" exatamente como vc ensinou. Se for escolha de arquivo executa "FileStorage" com uma leve diferença: acesso ao album "ExtraMediaAlbum" , qualquer arquivo "SetType("/");" , devolve a URI "intent.SetAction(Intent.ActionGetContent);" , abre o album com titulo Select Files e um parametro para que eu possa sabre se foi câmera ou álbum, no caso eu usei 2 para álbum e 1 para câmera... isso é opcional.... "Intent.CreateChooser(intent, "Select File"), 2);"

Então, até aqui não tem erro no codificação pois funciona direitinho... apenas não encontra o arquivo retornado na variável data que veio com a URI do local do arquivo. Se vc tiver uma luz... vlw

private void FileStorage()
        {
            Intent intent = new Intent(MediaStore.ExtraMediaAlbum);
            intent.SetType("*/*");
            intent.SetAction(Intent.ActionGetContent);

            var activity = Forms.Context as Activity;
            activity.StartActivityForResult(Intent.CreateChooser(intent, "Select File"), 2);
        }