leggere il file dagli asset


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");    
     }
}

Sto usando questo codice cercando di leggere un file dalle risorse. Ho provato due modi per farlo. In primo luogo, quando l'uso Fileho ricevuto FileNotFoundException, quando si utilizza il AssetManager getAssets()metodo non viene riconosciuto. C'è qualche soluzione qui?

Risposte:


225

Ecco cosa faccio in un'attività di lettura buffer estesa / modificata per soddisfare le tue esigenze

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
         }
    }
}

EDIT: la mia risposta è forse inutile se la tua domanda è su come farlo al di fuori di un'attività. Se la tua domanda è semplicemente come leggere un file dall'asset, la risposta è sopra.

AGGIORNAMENTO :

Per aprire un file specificando il tipo, è sufficiente aggiungere il tipo nella chiamata InputStreamReader come segue.

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
         }
    }
}

MODIFICARE

Come dice @Stan nel commento, il codice che sto dando non sta riassumendo le righe. mLineviene sostituito ad ogni passaggio. Ecco perché ho scritto //process line. Presumo che il file contenga una sorta di dati (cioè un elenco di contatti) e ogni riga dovrebbe essere elaborata separatamente.

Nel caso in cui desideri semplicemente caricare il file senza alcun tipo di elaborazione, dovrai riassumere mLinead ogni passaggio utilizzando StringBuilder()e accodando ogni passaggio.

UN ALTRO EDIT

Secondo il commento di @Vincent ho aggiunto il finallyblocco.

Si noti inoltre che in Java 7 e superiore è possibile utilizzare try-with-resourcesdi utilizzare la AutoCloseablee Closeablecaratteristiche di recente Java.

CONTESTO

In un commento @LunarWatcher sottolinea che getAssets()è un classin context. Quindi, se lo chiami al di fuori di un, activitydevi fare riferimento ad esso e passare l'istanza di contesto all'attività.

ContextInstance.getAssets();

Questo è spiegato nella risposta di @Maneesh. Quindi, se questo è utile per te, vota la sua risposta perché è lui che l'ha sottolineato.


2
@Stan, quindi scrivici nei commenti e lascia che l'autore decida se desidera aggiornarlo. Le modifiche servono a migliorare la chiarezza, non a cambiare significato. Le revisioni del codice devono sempre essere inserite prima come commenti.
KyleMit,

2
Il codice non garantisce la chiusura dello stream e la liberazione della risorsa in modo tempestivo. Ti consiglio di usare finally {reader.close();}.
Vincent Cantin,

2
Penso che sia utile sottolineare che il codice sopra mostra un errore in ADT - il "reader.close ();" la linea deve essere inserita in un altro blocco try-catch. Controllare questa discussione: stackoverflow.com/questions/8981589/... :)
JakeP

1
getAssets è una classe nel contesto, quindi per l'utilizzo al di fuori dell'attività è necessario effettuare una chiamata al contesto. Quindi al di fuori di un'attività, sarà qualcosa del generecontext.getAssets(.....)
Zoe,

1
Come per il tuo aggiornamento (grazie per averlo aggiunto), avere un contesto nei campi statici è una perdita di memoria. Questo dovrebbe essere usato con cautela ed essere adeguatamente pulito. Altrimenti si finisce con una perdita di memoria che può avere un grande impatto sull'app.
Zoe,

65
getAssets()

funziona solo in Attività in qualsiasi altra classe che devi usare Contextper essa.

Fai in modo che un costruttore per la classe Utils passi il riferimento all'attività (brutta strada) o al contesto dell'applicazione come parametro. Usando quell'uso getAsset () nella tua classe Utils.


1
Funziona su tutto ciò che è una sottoclasse di Context, di cui Activity è una delle tante.
Jeremy Logan,

Ho appena notato che ho scritto Context.
user370305,

@ user370305 sai, come posso convertire InputStream in FileInputStream?
hotHead,

@ user370305 in che modo è brutto?
Sevastyan Savanyuk,

Passare oggetti dell'interfaccia utente senza considerare le conseguenze è generalmente una cattiva pratica. Se non stai attento, puoi causare perdite di memoria o tentare di utilizzare contesti morti. Buona lettura sull'argomento: android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570
milosmns

49

Meglio tardi che mai.

Ho avuto difficoltà a leggere i file riga per riga in alcune circostanze. Il metodo di seguito è il migliore che ho trovato, finora, e lo consiglio.

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

Dove si presume che YourDataFile.txt risieda nelle risorse /

 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;

 }

La mia stringa di ritorno è android.content.res.AssetManager$AssetInputStream@4195dfa0 ..
Boldijar Paul,

lo stesso qui, res.AssetManager $ AssetInputStream @ .... qualche motivo particolare per cui lo sta restituendo?
Bigs,

Allocare due volte la memoria, prima per il buffer e poi per la stringa. Non funziona per file più grandi.
JaakL,

1
modo perfetto per allocare le dimensioni al 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();
}

Penseresti che se chiudi BufferedReader, allora dovrebbe chiudere automaticamente anche InputStreanReader e InputStream. Perché quello che non crei una maniglia per quelli, ad es input = new BufferedReader(new InputStreamReader(fIn));.
trans

3
Suggerirei di creare blocchi try / catch separati per chiudere tutte le risorse alla fine; piuttosto che raggrupparli tutti in uno, poiché potrebbe lasciare chiuse altre risorse se un precedente tentativo di chiudere un'altra risorsa genera un'eccezione.
Reece,

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

8

soluzione a una linea per kotlin:

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

7

getAssets() Il metodo funzionerà quando si chiama all'interno della classe Activity.

Se si chiama questo metodo in una classe non di attività, è necessario chiamare questo metodo dal contesto che viene passato dalla classe di attività. Quindi sotto è la linea da cui è possibile accedere al metodo.

ContextInstance.getAssets();

ContextInstance può essere passato come questo della classe Activity.


5

Leggere e scrivere file è sempre stato dettagliato e soggetto a errori. Evita queste risposte e usa invece 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
Sai perché questo sembra più estetico e corto? Bene, perché hai omesso, almeno, metà del codice qui. Parti omesse: 1) IOExceptionBlocco try / catch 2) Chiusura di flussi in caso di eccezione 3) Questo codice legge una riga singola, non l'intero file. Per quanto riguarda le prestazioni, questa libreria è sicuramente unica nel suo genere, non c'è dubbio. Ora, dimmi, dovrei ancora evitare "queste risposte" e implementare Okio solo per leggere i file? La risposta è NO, a meno che non sia già parte della tua app.
Farid,

Aggiornato la mia risposta.
Saket,

4

Ecco un metodo per leggere un file negli asset:

/**
 * 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;
}

Questa è una buona risposta, ma è un cattivo approccio usare la concatenazione di stringhe. Prendi invece in considerazione l'utilizzo di StringBuilder. StringBuilder contentBuilder = new StringBuilder (); while ((line = reader.readLine ())! = null) {builder.append ("\ n"). append (line); } E alla fine puoi creare un nuovo oggetto String in questo modo: content = contentBuilder.toString ();
Barterio,

4

È possibile caricare il contenuto dal file. Considera che il file è presente nella cartella delle risorse.

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;
}

Ora puoi ottenere il contenuto chiamando la funzione come segue

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

Considerando data.json è archiviato in Application \ app \ src \ main \ assets \ data.json


3

In 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)));
        }
    }

Inoltre, puoi creare una classe separata che fa tutto il lavoro

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();
    }
}

Secondo me è meglio creare un'interfaccia, ma non è necessario

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

2

Se usi altre classi diverse da Activity, ti consigliamo di fare like,

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

2

Utilizzando Kotlin, puoi fare quanto segue per leggere un file dalle risorse in 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

Forse è troppo tardi, ma per il bene degli altri che cercano le risposte 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 + "";

    }

Il link ora ritornaFile no longer available That file has now been permanently removed and cannot be recovered
gregn3 il

1

La classe Scanner può semplificare questo.

        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());

È possibile unire queste 2 righe sb.append (scanner.nextLine ()); sb.append ( '\ n'); a sb.appendln (scanner.nextLine ());
Mojtaba,

0

@HpTerm rispondi alla versione di 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
}

Attualmente ciò anteporrà null alla stringa. Modifiche necessarie: var mLine:Stringdovrebbe essere var mLine:String? var data: String?dovrebbe essere il var data = ""tipo di ritorno dovrebbe essereString
fupduck

0

Ecco un modo per ottenere un InputStreamper un file nella assetscartella senza un Context, Activity, Fragmento Application. Il modo in cui ottieni i dati InputStreamdipende da te. Ci sono molti suggerimenti per questo in altre risposte qui.

Kotlin

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

Giava

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

Tutte le scommesse sono disattivate se ClassLoaderè in gioco un'usanza .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.