Datei aus Assets lesen

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

Ich verwende diesen Code, um eine Datei aus Assets zu lesen. Ich habe zwei Möglichkeiten ausprobiert, dies zu tun. Erstens, wenn die Verwendung, die Fileich erhalten habe FileNotFoundException, wenn die Verwendung der AssetManager getAssets()Methode nicht erkannt wird. Gibt es hier eine Lösung?

fish40
quelle

Antworten:

225

Hier ist, was ich in einer Aktivität zum gepufferten Lesen mache, erweitern / modifizieren, um es Ihren Bedürfnissen anzupassen

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: Meine Antwort ist vielleicht nutzlos, wenn Ihre Frage lautet, wie es außerhalb einer Aktivität gemacht werden soll. Wenn Ihre Frage einfach ist, wie man eine Datei aus einem Asset liest, ist die Antwort oben.

AKTUALISIEREN :

Um eine Datei mit dem Typ zu öffnen, fügen Sie den Typ einfach wie folgt in den InputStreamReader-Aufruf ein.

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

BEARBEITEN

Wie @Stan im Kommentar sagt, summiert der Code, den ich gebe, keine Zeilen. mLinewird bei jedem Durchgang ersetzt. Deshalb habe ich geschrieben//process line . Ich gehe davon aus, dass die Datei irgendeine Art von Daten enthält (dh eine Kontaktliste) und jede Zeile separat verarbeitet werden sollte.

Wenn Sie die Datei einfach ohne jegliche Verarbeitung laden möchten, müssen Sie sie mLinebei jedem Durchgang mit jedem Durchgang zusammenfassen StringBuilder()und anhängen.

Noch eine Bearbeitung

Nach dem Kommentar von @Vincent habe ich das hinzugefügt finally Block .

Beachten Sie auch, dass Sie in Java 7 und höher try-with-resourcesdie Funktionen AutoCloseableund CloseableFunktionen des aktuellen Java verwenden können.

KONTEXT

In einem Kommentar weist @LunarWatcher darauf hin, dass getAssets()es sich um ein classIn handelt context. Wenn Sie es also außerhalb von a aufrufen, activitymüssen Sie darauf verweisen und die Kontextinstanz an die Aktivität übergeben.

ContextInstance.getAssets();

Dies wird in der Antwort von @Maneesh erklärt. Wenn dies für Sie nützlich ist, stimmen Sie seiner Antwort zu, denn das ist er, der darauf hingewiesen hat.

HpTerm
quelle
2
@Stan, dann schreibe darüber in die Kommentare und lass den Autor entscheiden, ob er es aktualisieren möchte. Änderungen dienen der Verbesserung der Klarheit und nicht der Änderung der Bedeutung. Code-Revisionen sollten immer zuerst als Kommentare veröffentlicht werden.
KyleMit
2
Ihr Code garantiert nicht, dass der Stream geschlossen und die Ressource rechtzeitig freigegeben wird. Ich empfehle Ihnen zu verwenden finally {reader.close();}.
Vincent Cantin
2
Ich denke, es ist nützlich darauf hinzuweisen, dass der obige Code einen Fehler in ADT anzeigt - "reader.close ();" Die Zeile muss in einen anderen Try-Catch-Block eingefügt werden. Überprüfen Sie diesen Thread: stackoverflow.com/questions/8981589/… :)
JakeP
1
getAssets ist eine Klasse im Kontext, daher muss für die Verwendung außerhalb der Aktivität ein Aufruf des Kontexts erfolgen. Außerhalb einer Aktivität wird es also so etwas wiecontext.getAssets(.....)
Zoe sein
1
Gemäß Ihrem Update (danke, dass Sie das übrigens hinzugefügt haben) ist der Kontext in statischen Feldern ein Speicherverlust. Dies sollte mit Vorsicht verwendet und ordnungsgemäß gereinigt werden. Andernfalls kommt es zu einem Speicherverlust, der große Auswirkungen auf die App haben kann.
Zoe
65
getAssets()

funktioniert nur in Aktivität in einer anderen Klasse, die Sie dafür verwenden müssen Context.

Mach ein Konstruktor für die Utils- Klasse als Referenz für die Aktivität (hässlicher Weg) oder den Kontext der Anwendung als Parameter. Verwenden Sie dazu getAsset () in Ihrer Utils-Klasse.

user370305
quelle
1
Es funktioniert für alles, was eine Unterklasse des Kontexts ist, von denen Aktivität eine von vielen ist.
Jeremy Logan
Ich habe gerade bemerkt, dass ich geschrieben habe Context.
user370305
@ user370305 wissen Sie, wie ich InputStream in FileInputStream konvertieren kann?
hotHead
@ user370305 inwiefern ist das hässlich?
Sevastyan Savanyuk
Das Weitergeben von UI-Objekten ohne Berücksichtigung der Konsequenzen ist im Allgemeinen eine schlechte Praxis. Wenn Sie nicht vorsichtig sind, können Sie Speicherlecks verursachen oder versuchen, tote Kontexte zu verwenden. Gute Lektüre zum Thema: android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570
milosmns
49

Besser spät als nie.

Unter bestimmten Umständen hatte ich Schwierigkeiten, Dateien Zeile für Zeile zu lesen. Die folgende Methode ist die beste, die ich bisher gefunden habe, und ich empfehle sie.

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

Wo angenommen wird, dass sich YourDataFile.txt in Assets befindet /

 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
quelle
Meine Rückgabezeichenfolge ist android.content.res.AssetManager$AssetInputStream@4195dfa0 ..
Boldijar Paul
das gleiche hier, res.AssetManager $ AssetInputStream @ .... einen bestimmten Grund, warum es dies zurückgibt?
Bigs
Sie weisen Speicher doppelt zu - zuerst für den Puffer und dann für den String. Funktioniert nicht für größere Dateien.
JaakL
1
perfekte Möglichkeit, dem Puffer Größe zuzuweisen 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
quelle
Sie würden denken, wenn Sie den BufferedReader schließen, müssten auch der InputStreanReader und der InputStream automatisch geschlossen werden. Denn was es ist, erstellen Sie kein Handle für diese, z input = new BufferedReader(new InputStreamReader(fIn));.
Trans
3
Ich würde vorschlagen, separate Try / Catch-Blöcke zu erstellen, um am Ende alle Ihre Ressourcen zu schließen. anstatt sie alle zu einer zusammenzufassen, da andere Ressourcen möglicherweise nicht geschlossen werden, wenn ein vorheriger Versuch, eine andere Ressource zu schließen, eine Ausnahme auslöst.
Reece
9
AssetManager assetManager = getAssets();
InputStream inputStream = null;
try {
    inputStream = assetManager.open("helloworld.txt");
}
catch (IOException e){
    Log.e("message: ",e.getMessage());
}
Siva Charan
quelle
8

Einzeilige Lösung für Kotlin:

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

getAssets() Die Methode funktioniert, wenn Sie innerhalb der Activity-Klasse aufrufen.

Wenn Sie diese Methode in einer Nicht-Aktivitätsklasse aufrufen, müssen Sie diese Methode aus dem Kontext aufrufen, der von der Aktivitätsklasse übergeben wird. Unten sehen Sie die Zeile, in der Sie auf die Methode zugreifen können.

ContextInstance.getAssets();

ContextInstance kann als dies der Aktivitätsklasse übergeben werden.

Maneesh
quelle
5

Das Lesen und Schreiben von Dateien war schon immer ausführlich und fehleranfällig. Vermeiden Sie diese Antworten und verwenden Sie stattdessen einfach 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
quelle
1
Wissen Sie, warum dies ästhetischer und kurzer aussieht? Nun, weil Sie hier mindestens die Hälfte des Codes weggelassen haben. Ausgelassene Teile: 1) IOExceptionTry / Catch-Block 2) Schließen von Streams, falls eine Ausnahme ausgelöst wird 3) Dieser Code liest eine einzelne Zeile, nicht die gesamte Datei. In Bezug auf die Leistung ist diese Bibliothek definitiv einzigartig, daran besteht kein Zweifel. Sagen Sie mir jetzt, sollte ich "diese Antworten" trotzdem vermeiden und Okio nur zum Lesen von Dateien implementieren? Die Antwort lautet NEIN, es sei denn, es ist bereits Teil Ihrer App.
Farid
Meine Antwort wurde aktualisiert.
Saket
4

Hier ist eine Methode zum Lesen einer Datei in Assets:

/**
 * 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
quelle
Dies ist eine gute Antwort, aber es ist ein schlechter Ansatz, die String-Verkettung zu verwenden. Verwenden Sie stattdessen StringBuilder. StringBuilder contentBuilder = new StringBuilder (); while ((line = reader.readLine ())! = null) {builder.append ("\ n"). append (line); } Und am Ende können Sie ein neues String-Objekt erstellen: content = contentBuilder.toString ();
Barterio
4

Sie können den Inhalt aus der Datei laden. Angenommen, die Datei befindet sich im Asset-Ordner.

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

Jetzt können Sie den Inhalt abrufen, indem Sie die Funktion wie folgt aufrufen

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

Berücksichtigen Sie, dass die Datei data.json unter Application \ app \ src \ main \ assets \ data.json gespeichert ist

Siddarth Kanted
quelle
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)));
        }
    }

Sie können auch eine separate Klasse erstellen, die die gesamte Arbeit erledigt

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

Meiner Meinung nach ist es besser, eine Schnittstelle zu erstellen, aber es ist nicht notwendig

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

Wenn Sie eine andere Klasse als Aktivität verwenden, möchten Sie möglicherweise Folgendes tun:

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

Mit Kotlin können Sie Folgendes tun, um eine Datei aus Assets in Android zu lesen:

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
quelle
2

Es ist vielleicht zu spät, aber für andere, die nach pfirsichfarbenen Antworten suchen:

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
quelle
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
quelle
Der Link kehrt jetzt zurückFile no longer available That file has now been permanently removed and cannot be recovered
gregn3
1

Die Scannerklasse kann dies vereinfachen.

        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
quelle
Sie können diese 2 Zeilen zusammenführen sb.append (scanner.nextLine ()); sb.append ('\ n'); an sb.appendln (scanner.nextLine ());
Mojtaba
0

@ HPTerm Antwort Kotlin Version:

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
quelle
Derzeit wird der Zeichenfolge null vorangestellt. Erforderliche Änderungen: var mLine:Stringsollte sein var mLine:String? var data: String?sollte sein var data = ""Rückgabetyp sollte seinString
fupduck
0

Hier ist ein Weg , eine bekommen InputStreamfür eine Datei im assetsOrdner ohne Context, Activity, Fragmentoder Application. Wie Sie die Daten daraus erhaltenInputStream liegt bei Ihnen. Es gibt viele Vorschläge dafür in anderen Antworten hier.

Kotlin

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

Java

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

Alle Wetten sind ungültig, wenn ein Brauch ClassLoaderim Spiel ist.

Bartonstanley
quelle