ler arquivo de ativos


178
public class Utils {
    public static List<Message> getMessages() {
        //File file = new File("file:///android_asset/helloworld.txt");
        AssetManager assetManager = getAssets();
        InputStream ims = assetManager.open("helloworld.txt");    
     }
}

Estou usando esse código tentando ler um arquivo de ativos. Eu tentei duas maneiras de fazer isso. Primeiro, quando uso Fileque recebi FileNotFoundException, ao usar o AssetManager getAssets()método não é reconhecido. Existe alguma solução aqui?

Respostas:


225

Aqui está o que eu faço em uma atividade de leitura em buffer estender / modificar para atender às suas necessidades

BufferedReader reader = null;
try {
    reader = new BufferedReader(
        new InputStreamReader(getAssets().open("filename.txt")));

    // do reading, usually loop until end of file reading  
    String mLine;
    while ((mLine = reader.readLine()) != null) {
       //process line
       ...
    }
} catch (IOException e) {
    //log the exception
} finally {
    if (reader != null) {
         try {
             reader.close();
         } catch (IOException e) {
             //log the exception
         }
    }
}

Edição: Minha resposta talvez seja inútil se sua pergunta é sobre como fazê-lo fora de uma atividade. Se sua pergunta é simplesmente como ler um arquivo do ativo, a resposta está acima.

ATUALIZAÇÃO :

Para abrir um arquivo especificando o tipo, adicione o tipo na chamada InputStreamReader da seguinte maneira.

BufferedReader reader = null;
try {
    reader = new BufferedReader(
        new InputStreamReader(getAssets().open("filename.txt"), "UTF-8")); 

    // do reading, usually loop until end of file reading 
    String mLine;
    while ((mLine = reader.readLine()) != null) {
       //process line
       ...
    }
} catch (IOException e) {
    //log the exception
} finally {
    if (reader != null) {
         try {
             reader.close();
         } catch (IOException e) {
             //log the exception
         }
    }
}

EDITAR

Como o @Stan diz no comentário, o código que estou dando não está resumindo as linhas. mLineé substituído a cada passe. Por isso escrevi //process line. Presumo que o arquivo contenha algum tipo de dados (ou seja, uma lista de contatos) e cada linha deve ser processada separadamente.

Caso você queira simplesmente carregar o arquivo sem nenhum tipo de processamento, será necessário resumir mLinea cada passagem usando StringBuilder()e anexando cada passagem.

OUTRA EDIÇÃO

De acordo com o comentário do @Vincent, adicionei o finallybloco.

Observe também que no Java 7 e superior você pode usar try-with-resourcespara usar os recursos AutoCloseablee Closeabledo Java recente.

CONTEXTO

Em um comentário, @LunarWatcher aponta que getAssets()é um classin context. Portanto, se você chamá-lo fora de um, activityprecisará se referir a ele e passar a instância de contexto para a atividade.

ContextInstance.getAssets();

Isso é explicado na resposta de @Maneesh. Portanto, se isso é útil para você, responda a resposta dele porque foi ele quem apontou isso.


2
@ Stan, em seguida, escreva sobre isso nos comentários e deixe o autor decidir se eles gostariam de atualizá-lo. As edições são para melhorar a clareza, não alterando o significado. As revisões de código sempre devem ser postadas como comentários primeiro.
— precisa saber é o seguinte

2
Seu código não garante o fechamento do fluxo e a liberação do recurso em tempo hábil. Eu recomendo que você use finally {reader.close();}.
— precisa saber é o seguinte

2
Acho útil ressaltar que o código acima mostra um erro no ADT - o "reader.close ();" a linha precisa ser colocada em outro bloco try-catch. Verifique este tópico: stackoverflow.com/questions/8981589/... :)
— JakeP

1
getAssets é uma classe em contexto, portanto, para uso fora da atividade, é necessário fazer uma chamada para o contexto. Portanto, fora de uma atividade, será algo como:context.getAssets(.....)
— Zoe

1
Conforme sua atualização (obrigado por adicionar essa btw), ter contexto em campos estáticos é um vazamento de memória. Isso deve ser usado com cuidado e limpo adequadamente. Caso contrário, você terá um vazamento de memória que poderá ter um grande impacto no aplicativo.
— Zoe

65
getAssets()

só funciona em Activity em outra classe que você precise usar Contextpara isso.

Faça um construtor para a classe Utils passar referência de atividade (maneira feia) ou contexto de aplicação como um parâmetro para ele. Usando isso, use getAsset () na sua classe Utils.


1
Funciona em qualquer coisa que seja uma subclasse de Contexto, da qual Activity é uma dentre muitas.
— Jeremy Logan

Acabei de notar que escrevi Context.
— user370305

@ user370305 você sabe, como posso converter InputStream em FileInputStream?
— hotHead 18/05

@ user370305 de que maneira isso é feio?
— Sevastyan Savanyuk

Passar objetos da interface do usuário sem considerar as consequências geralmente é uma prática ruim. Se você não tomar cuidado, poderá causar vazamento de memória ou tentar usar contextos mortos. Boa leitura sobre o tema: android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570
— milosmns

49

Antes tarde do que nunca.

Tive dificuldades em ler arquivos linha por linha em algumas circunstâncias. O método abaixo é o melhor que encontrei até agora e recomendo.

Uso: String yourData = LoadData("YourDataFile.txt");

Onde YourDataFile.txt supõe residir em ativos /

 public String LoadData(String inFile) {
        String tContents = "";

    try {
        InputStream stream = getAssets().open(inFile);

        int size = stream.available();
        byte[] buffer = new byte[size];
        stream.read(buffer);
        stream.close();
        tContents = new String(buffer);
    } catch (IOException e) {
        // Handle exceptions here
    }

    return tContents;

 }

Meu String de retorno é android.content.res.AssetManager$AssetInputStream@4195dfa0 ..
— Boldijar Paul

mesmo aqui, res.AssetManager $ AssetInputStream @ .... alguma razão específica para retornar isso?
— Bigs

Você aloca duas vezes a memória - primeiro para o buffer e depois para a String. Não funciona para arquivos maiores.
— JaakL

1
maneira perfeita de alocar tamanho para buffer stream.available().
— Kasim Rangwala

39
public String ReadFromfile(String fileName, Context context) {
    StringBuilder returnString = new StringBuilder();
    InputStream fIn = null;
    InputStreamReader isr = null;
    BufferedReader input = null;
    try {
        fIn = context.getResources().getAssets()
                .open(fileName, Context.MODE_WORLD_READABLE);
        isr = new InputStreamReader(fIn);
        input = new BufferedReader(isr);
        String line = "";
        while ((line = input.readLine()) != null) {
            returnString.append(line);
        }
    } catch (Exception e) {
        e.getMessage();
    } finally {
        try {
            if (isr != null)
                isr.close();
            if (fIn != null)
                fIn.close();
            if (input != null)
                input.close();
        } catch (Exception e2) {
            e2.getMessage();
        }
    }
    return returnString.toString();
}

Você pensaria que, se você fechar o BufferedReader, teria que fechar automaticamente o InputStreanReader e o InputStream também. Porque o que você não cria um identificador para aqueles, por exemplo input = new BufferedReader(new InputStreamReader(fIn));.
— trans

3
Eu sugeriria a criação de blocos try / catch separados para fechar todos os seus recursos no final; em vez de agrupá-los todos em um - pois pode deixar outros recursos não fechados se uma tentativa anterior de fechar outro recurso gerar uma exceção.
— Reece

9
AssetManager assetManager = getAssets();
InputStream inputStream = null;
try {
    inputStream = assetManager.open("helloworld.txt");
}
catch (IOException e){
    Log.e("message: ",e.getMessage());
}

8

solução de uma linha para kotlin:

fun readFileText(fileName: String): String {
    return assets.open(fileName).bufferedReader().use { it.readText() }
}

7

getAssets() O método funcionará quando você estiver chamando dentro da classe Activity.

Se você chamar esse método na classe não Activity, precisará chamar esse método do Contexto, que é passado da classe Activity. Então abaixo está a linha pela qual você pode acessar o método

ContextInstance.getAssets();

ContextInstance pode ser passado como este da classe Activity.


5

Os arquivos de leitura e gravação sempre foram detalhados e propensos a erros. Evite essas respostas e use Okio :

public void readLines(File file) throws IOException {
  try (BufferedSource source = Okio.buffer(Okio.source(file))) {
    for (String line; (line = source.readUtf8Line()) != null; ) {
      if (line.contains("square")) {
        System.out.println(line);
      }
    }
  }
}

1
Você sabe por que isso parece mais estético e curto? Bem, porque você omitiu, pelo menos, metade do código aqui. Peças omitidas: 1) IOExceptionbloco de tentativa / captura 2) Fechamento de fluxos em caso de exceção 3) Este código lê uma única linha, não o arquivo inteiro. Em termos de desempenho, essa biblioteca é definitivamente única, sem dúvida. Agora, diga-me que ainda devo evitar "essas respostas" e implementar o Okio apenas para ler arquivos? A resposta é NÃO, a menos que já faça parte do seu aplicativo.
— Farid

Atualizei minha resposta.
— Saket

4

Aqui está um método para ler um arquivo nos ativos:

/**
 * Reads the text of an asset. Should not be run on the UI thread.
 * 
 * @param mgr
 *            The {@link AssetManager} obtained via {@link Context#getAssets()}
 * @param path
 *            The path to the asset.
 * @return The plain text of the asset
 */
public static String readAsset(AssetManager mgr, String path) {
    String contents = "";
    InputStream is = null;
    BufferedReader reader = null;
    try {
        is = mgr.open(path);
        reader = new BufferedReader(new InputStreamReader(is));
        contents = reader.readLine();
        String line = null;
        while ((line = reader.readLine()) != null) {
            contents += '\n' + line;
        }
    } catch (final Exception e) {
        e.printStackTrace();
    } finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException ignored) {
            }
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException ignored) {
            }
        }
    }
    return contents;
}

Essa é uma boa resposta, mas é uma abordagem ruim usar a concatenação de String. Considere usar StringBuilder. StringBuilder contentBuilder = novo StringBuilder (); while ((line = reader.readLine ())! = null) {builder.append ("\ n"). append (linha); } E no final, você pode criar um novo objeto String com isso: content = contentBuilder.toString ();
— Barterio

4

Você pode carregar o conteúdo do arquivo. Considere que o arquivo está presente na pasta de ativos.

public static InputStream loadInputStreamFromAssetFile(Context context, String fileName){
    AssetManager am = context.getAssets();
    try {
        InputStream is = am.open(fileName);
        return is;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

public static String loadContentFromFile(Context context, String path){
    String content = null;
    try {
        InputStream is = loadInputStreamFromAssetFile(context, path);
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();
        content = new String(buffer, "UTF-8");
    } catch (IOException ex) {
        ex.printStackTrace();
        return null;
    }
    return content;
}

Agora você pode obter o conteúdo chamando a função da seguinte maneira

String json= FileUtil.loadContentFromFile(context, "data.json");

Considerando que o data.json está armazenado em Application \ app \ src \ main \ assets \ data.json


3

Em MainActivity.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tvView = (TextView) findViewById(R.id.tvView);

        AssetsReader assetsReader = new AssetsReader(this);
        if(assetsReader.getTxtFile(your_file_title)) != null)
        {
            tvView.setText(assetsReader.getTxtFile(your_file_title)));
        }
    }

Além disso, você pode criar uma classe separada que faz todo o trabalho

public class AssetsReader implements Readable{

    private static final String TAG = "AssetsReader";


    private AssetManager mAssetManager;
    private Activity mActivity;

    public AssetsReader(Activity activity) {
        this.mActivity = activity;
        mAssetManager = mActivity.getAssets();
    }

    @Override
    public String getTxtFile(String fileName)
    {
        BufferedReader reader = null;
        InputStream inputStream = null;
        StringBuilder builder = new StringBuilder();

        try{
            inputStream = mAssetManager.open(fileName);
            reader = new BufferedReader(new InputStreamReader(inputStream));

            String line;

            while((line = reader.readLine()) != null)
            {
                Log.i(TAG, line);
                builder.append(line);
                builder.append("\n");
            }
        } catch (IOException ioe){
            ioe.printStackTrace();
        } finally {

            if(inputStream != null)
            {
                try {
                    inputStream.close();
                } catch (IOException ioe){
                    ioe.printStackTrace();
                }
            }

            if(reader != null)
            {
                try {
                    reader.close();
                } catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
            }
        }
        Log.i(TAG, "builder.toString(): " + builder.toString());
        return builder.toString();
    }
}

Na minha opinião, é melhor criar uma interface, mas não é necessário

public interface Readable {
    /**
     * Reads txt file from assets
     * @param fileName
     * @return string
     */
    String getTxtFile(String fileName);
}

2

Se você usa outra classe que não seja Activity, pode fazer o seguinte,

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( YourApplication.getInstance().getAssets().open("text.txt"), "UTF-8"));

2

Usando o Kotlin, você pode fazer o seguinte para ler um arquivo de ativos no Android:

try {
    val inputStream:InputStream = assets.open("helloworld.txt")
    val inputString = inputStream.bufferedReader().use{it.readText()}
    Log.d(TAG,inputString)
} catch (e:Exception){
    Log.d(TAG, e.toString())
}

2

Talvez seja tarde demais, mas para o bem de outras pessoas que procuram as respostas peachy:

public static String loadAssetFile(Context context, String fileName) {
    try {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(context.getAssets().open(fileName)));
        StringBuilder out= new StringBuilder();
        String eachline = bufferedReader.readLine();
        while (eachline != null) {
            out.append(eachline);
            eachline = bufferedReader.readLine();
        }
        return out.toString();
    } catch (IOException e) {
        Log.e("Load Asset File",e.toString());
    }
    return null;
}

1

cityfile.txt

   public void getCityStateFromLocal() {
        AssetManager am = getAssets();
        InputStream inputStream = null;
        try {
            inputStream = am.open("city_state.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        ObjectMapper mapper = new ObjectMapper();
        Map<String, String[]> map = new HashMap<String, String[]>();
        try {
            map = mapper.readValue(getStringFromInputStream(inputStream), new TypeReference<Map<String, String[]>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        ConstantValues.arrayListStateName.clear();
        ConstantValues.arrayListCityByState.clear();
        if (map.size() > 0)
        {
            for (Map.Entry<String, String[]> e : map.entrySet()) {
                CityByState cityByState = new CityByState();
                String key = e.getKey();
                String[] value = e.getValue();
                ArrayList<String> s = new ArrayList<String>(Arrays.asList(value));
                ConstantValues.arrayListStateName.add(key);
                s.add(0,"Select City");
                cityByState.addValue(s);
                ConstantValues.arrayListCityByState.add(cityByState);
            }
        }
        ConstantValues.arrayListStateName.add(0,"Select States");
    }
 // Convert InputStream to String
    public String getStringFromInputStream(InputStream is) {
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        String line;
        try {
            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb + "";

    }

O link agora retornaFile no longer available That file has now been permanently removed and cannot be recovered
— gregn3 5/04

1

A classe Scanner pode simplificar isso.

        StringBuilder sb=new StringBuilder();
        Scanner scanner=null;
        try {
            scanner=new Scanner(getAssets().open("text.txt"));
            while(scanner.hasNextLine()){
                sb.append(scanner.nextLine());
                sb.append('\n');
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(scanner!=null){try{scanner.close();}catch (Exception e){}}
        }
        mTextView.setText(sb.toString());

Você pode mesclar essas duas linhas sb.append (scanner.nextLine ()); sb.append ('\ n'); para sb.appendln (scanner.nextLine ());
— Mojtaba 6/04

0

@HpTerm responde à versão do Kotlin:

private fun getDataFromAssets(): String? {

    var bufferedReader: BufferedReader? = null
    var data: String? = null

    try {
        bufferedReader = BufferedReader(
            InputStreamReader(
                activity?.assets?.open("Your_FILE.html"),     
                "UTF-8"
            )
        )                  //use assets? directly if in activity

       var mLine:String = bufferedReader?.readLine()
        while (mLine != null) {
            data+= mLine
            mLine=bufferedReader.readLine()
        }

    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        try {
            bufferedReader?.close()
        } catch (e: Exception) {
           e.printStackTrace()
        }
    }
    return data
}

Atualmente, isso incluirá nulo na sequência. Mudanças necessárias: var mLine:Stringdeve ser var mLine:String? var data: String?deve ser var data = ""tipo de retorno deve serString
— fupduck

0

Aqui está uma maneira de obter um InputStreampara um arquivo na assetspasta sem um Context, Activity, Fragmentou Application. A decisão de como você obtém os dados InputStreamdepende disso . Há muitas sugestões para isso em outras respostas aqui.

Kotlin

val inputStream = ClassLoader::class.java.classLoader?.getResourceAsStream("assets/your_file.ext")

Java

InputStream inputStream = ClassLoader.class.getClassLoader().getResourceAsStream("assets/your_file.ext");

Todas as apostas estão desativadas se um costume ClassLoaderestiver em jogo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.