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?

fish40
fonte

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.

HpTerm
fonte
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.

user370305
fonte
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;

 }
Florin Mircea
fonte
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();
}
swathi
fonte
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());
}
Siva Charan
fonte
8

solução de uma linha para kotlin:

fun readFileText(fileName: String): String {
    return assets.open(fileName).bufferedReader().use { it.readText() }
}
Ted
fonte
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.

Maneesh
fonte
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);
      }
    }
  }
}
Saket
fonte
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;
}
Jared Rummler
fonte
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

Siddarth Kanted
fonte
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);
}
Volodymyr Shalashenko
fonte
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"));
Zhaolong Zhong
fonte
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())
}
Vamsi Tallapudi
fonte
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;
}
ucMedia
fonte
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 + "";

    }
tej shah
fonte
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());
Solomon P Byer
fonte
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
}
Manohar Reddy
fonte
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.

Bartonstanley
fonte