lire le fichier à partir des actifs

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

J'utilise ce code pour essayer de lire un fichier à partir d'actifs. J'ai essayé deux façons de le faire. Premièrement, lors de l'utilisation que Filej'ai reçue FileNotFoundException, lorsque l'utilisation de la AssetManager getAssets()méthode n'est pas reconnue. Y a-t-il une solution ici?

poisson40
la source

Réponses:

225

Voici ce que je fais dans une activité de lecture tamponnée étendre / modifier pour répondre à vos besoins

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: Ma réponse est peut-être inutile si votre question est de savoir comment le faire en dehors d'une activité. Si votre question est simplement de savoir comment lire un fichier à partir d'un actif, la réponse est ci-dessus.

MISE À JOUR :

Pour ouvrir un fichier spécifiant le type, ajoutez simplement le type dans l'appel InputStreamReader comme suit.

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

ÉDITER

Comme le dit @Stan dans le commentaire, le code que je donne ne résume pas les lignes. mLineest remplacé à chaque passage. C'est pourquoi j'ai écrit //process line. Je suppose que le fichier contient une sorte de données (c'est-à-dire une liste de contacts) et que chaque ligne doit être traitée séparément.

Dans le cas où vous souhaitez simplement charger le fichier sans aucun traitement, vous devrez résumer mLineà chaque passe en utilisant StringBuilder()et en ajoutant chaque passe.

UNE AUTRE MODIFICATION

D'après le commentaire de @Vincent, j'ai ajouté le finallybloc.

Notez également que dans Java 7 et supérieur, vous pouvez utiliser try-with-resourcespour utiliser les fonctionnalités AutoCloseableet Closeablede Java récent.

LE CONTEXTE

Dans un commentaire, @LunarWatcher souligne qu'il getAssets()s'agit d'un classin context. Donc, si vous l'appelez en dehors d'un, activityvous devez y faire référence et transmettre l'instance de contexte à l'activité.

ContextInstance.getAssets();

Ceci est expliqué dans la réponse de @Maneesh. Donc, si cela vous est utile, augmentez sa réponse, car c'est lui qui l'a souligné.

HpTerm
la source
2
@Stan, puis écrivez à ce sujet dans les commentaires et laissez l'auteur décider s'il souhaite le mettre à jour. Les modifications visent à améliorer la clarté et non à changer le sens. Les révisions de code doivent toujours être publiées en premier comme commentaires.
KyleMit
2
Votre code ne garantit pas la fermeture du flux et la libération de la ressource en temps opportun. Je vous recommande d'utiliser finally {reader.close();}.
Vincent Cantin
2
Je pense qu'il est utile de souligner que le code ci-dessus montre une erreur dans ADT - le "reader.close ();" La ligne doit être placée dans un autre bloc try-catch. Vérifiez ce fil: stackoverflow.com/questions/8981589/… :)
JakeP
1
getAssets est une classe dans Context, donc pour une utilisation en dehors des activités, un appel à Context doit être effectué. Donc en dehors d'une activité, ce sera quelque chose commecontext.getAssets(.....)
Zoe
1
Selon votre mise à jour (merci d'avoir ajouté ce btw), avoir du contexte dans des champs statiques est une fuite de mémoire. Ceci doit être utilisé avec précaution et correctement nettoyé. Sinon, vous vous retrouvez avec une fuite de mémoire qui peut avoir un impact important sur l'application.
Zoe
65
getAssets()

Cela ne fonctionne que dans Activity dans toute autre classe que vous devez utiliser Contextpour cela.

Faites en sorte qu'un constructeur pour la classe Utils transmette la référence de l'activité (manière laide) ou du contexte de l'application en tant que paramètre. En utilisant cela, utilisez getAsset () dans votre classe Utils.

user370305
la source
1
Cela fonctionne sur tout ce qui est une sous-classe de Context, dont Activity est l'une des nombreuses.
Jeremy Logan
Je viens de noter que j'ai écrit Context.
user370305
@ user370305 savez-vous comment je peux convertir InputStream en FileInputStream?
hotHead
@ user370305 en quoi c'est moche?
Sevastyan Savanyuk
Faire passer des objets de l'interface utilisateur sans tenir compte des conséquences est généralement une mauvaise pratique. Si vous ne faites pas attention, vous pouvez provoquer des fuites de mémoire ou tenter d'utiliser des contextes morts. Bonne lecture sur le sujet: android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570
milosmns
49

Mieux vaut tard que jamais.

J'ai eu des difficultés à lire les fichiers ligne par ligne dans certaines circonstances. La méthode ci-dessous est la meilleure que j'ai trouvée, jusqu'à présent, et je la recommande.

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

YourDataFile.txt est supposé résider dans les actifs /

 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
la source
Ma chaîne de retour est android.content.res.AssetManager$AssetInputStream@4195dfa0 ..
Boldijar Paul
même ici, res.AssetManager $ AssetInputStream @ .... une raison particulière pour laquelle il renvoie ceci?
Bigs
Vous double-allouez de la mémoire - d'abord pour le tampon, puis pour la chaîne. Ne fonctionne pas pour les fichiers plus volumineux.
JaakL
1
moyen idéal d'allouer la taille au tampon 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
la source
Vous pourriez penser que si vous fermez BufferedReader, il devrait également fermer automatiquement InputStreanReader et InputStream. Parce que ce que vous ne créez pas de poignée pour ceux-ci, par exemple input = new BufferedReader(new InputStreamReader(fIn));.
trans
3
Je suggérerais de créer des blocs try / catch séparés pour fermer toutes vos ressources à la fin; plutôt que de les regrouper tous en un seul - car cela peut laisser d'autres ressources non fermées si une tentative préalable de fermer une autre ressource lève une exception.
Reece
9
AssetManager assetManager = getAssets();
InputStream inputStream = null;
try {
    inputStream = assetManager.open("helloworld.txt");
}
catch (IOException e){
    Log.e("message: ",e.getMessage());
}
Siva Charan
la source
8

solution en une ligne pour kotlin:

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

getAssets() fonctionnera lorsque vous appelez dans la classe Activity.

Si vous appelez cette méthode dans une classe non-Activity, vous devez appeler cette méthode à partir du contexte qui est passé de la classe Activity. Voici donc la ligne par laquelle vous pouvez accéder à la méthode.

ContextInstance.getAssets();

ContextInstance peut être passé comme ceci de la classe d'activité.

Maneesh
la source
5

La lecture et l'écriture de fichiers ont toujours été verbeuses et sujettes aux erreurs. Évitez ces réponses et utilisez simplement Okio à la place:

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
la source
1
Savez-vous pourquoi cela a l'air plus esthétique et court? Eh bien, parce que vous avez omis, au moins, la moitié du code ici. Parties omises: 1) IOExceptionle bloc try / catch de 2) Fermeture des flux en cas d'exception 3) Ce code lit une seule ligne, pas le fichier entier. En termes de performances, cette bibliothèque est définitivement unique en son genre, sans aucun doute à ce sujet. Maintenant, dites-moi devrais-je toujours éviter "ces réponses" et implémenter Okio juste pour lire des fichiers? La réponse est NON, sauf si cela fait déjà partie de votre application.
Farid
Mis à jour ma réponse.
Saket
4

Voici une méthode pour lire un fichier dans les actifs:

/**
 * 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
la source
C'est une bonne réponse, mais c'est une mauvaise approche d'utiliser la concaténation de chaînes. Pensez à utiliser StringBuilder à la place. StringBuilder contentBuilder = nouveau StringBuilder (); while ((line = reader.readLine ())! = null) {builder.append ("\ n"). append (line); } Et à la fin, vous pouvez créer un nouvel objet String par ceci: content = contentBuilder.toString ();
Barterio
4

Vous pouvez charger le contenu du fichier. Considérez que le fichier est présent dans le dossier des ressources.

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

Vous pouvez maintenant obtenir le contenu en appelant la fonction comme suit

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

Considérant que data.json est stocké dans Application \ app \ src \ main \ assets \ data.json

Siddarth Kanted
la source
3

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

En outre, vous pouvez créer une classe distincte qui fait tout le travail

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

À mon avis, il vaut mieux créer une interface, mais ce n'est pas nécessaire

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

Si vous utilisez une autre classe autre que Activité, vous voudrez peut-être faire comme,

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

En utilisant Kotlin, vous pouvez effectuer les opérations suivantes pour lire un fichier à partir d'actifs dans 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
la source
2

C'est peut-être trop tard, mais pour le bien des autres qui recherchent les réponses pêche:

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
la source
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
la source
Le lien revient maintenantFile no longer available That file has now been permanently removed and cannot be recovered
gregn3
1

La classe Scanner peut simplifier cela.

        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
la source
Vous pouvez fusionner ces 2 lignes sb.append (scanner.nextLine ()); sb.append ('\ n'); à sb.appendln (scanner.nextLine ());
Mojtaba le
0

@HpTerm répond à la version 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
la source
Actuellement, cela ajoutera null à la chaîne. Modifications nécessaires: var mLine:Stringdevrait être var mLine:String? var data: String?devrait être le var data = ""type de retour devrait êtreString
fupduck
0

Voici un moyen d'obtenir un InputStreampour un fichier dans le assetsdossier sans Context, Activity, Fragmentou Application. Comment obtenez-vous les données à partir de celaInputStream dépend de vous. Il y a beaucoup de suggestions à ce sujet dans d'autres réponses ici.

Kotlin

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

Java

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

Tous les paris sont ouverts si une coutume ClassLoaderest en jeu.

Bartonstanley
la source