читать файл из ресурсов


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

Я использую этот код, пытаясь прочитать файл из активов. Я попробовал два способа сделать это. Во-первых, при использовании Fileя получил FileNotFoundException, при использовании AssetManager getAssets()метода не распознается. Здесь есть какое-то решение?

Ответы:


225

Вот что я делаю в упражнении для буферизованного чтения: расширение / изменение в соответствии с вашими потребностями

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

РЕДАКТИРОВАТЬ: Мой ответ, возможно, бесполезен, если ваш вопрос о том, как сделать это вне деятельности. Если ваш вопрос заключается в том, как просто прочитать файл из ресурса, то ответ выше.

ОБНОВЛЕНИЕ :

Чтобы открыть файл с указанием типа, просто добавьте тип в вызов InputStreamReader следующим образом.

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

РЕДАКТИРОВАТЬ

Как говорит @Stan в комментарии, код, который я даю, не суммирует строки. mLineзаменяется каждый проход. Вот почему я написал //process line. Я предполагаю, что файл содержит какие-то данные (например, список контактов), и каждая строка должна обрабатываться отдельно.

Если вы просто хотите загрузить файл без какой-либо обработки, вам нужно будет подводить итоги mLineна каждом проходе, используя StringBuilder()и добавляя каждый проход.

ДРУГОЕ РЕДАКТИРОВАНИЕ

Согласно комментарию @Vincent я добавил finallyблок.

Также обратите внимание, что в Java 7 и выше вы можете использовать try-with-resourcesдля использования AutoCloseableиCloseable более поздних версиях возможности недавней Java.

КОНТЕКСТ

В комментарии @LunarWatcher указывает, что getAssets()находится classв context. Таким образом, если вы вызываете его вне, activityвам нужно обратиться к нему и передать экземпляр контекста в действие.

ContextInstance.getAssets();

Это объясняется в ответе @Maneesh. Так что, если это полезно для вас, проголосуйте за его ответ, потому что именно он указал на это.


2
@Stan, затем напишите об этом в комментариях и позвольте автору решить, хотят ли они обновить его. Изменения предназначены для улучшения ясности, а не для изменения смысла. Изменения кода всегда должны публиковаться как комментарии в первую очередь.
KyleMit

2
Ваш код не гарантирует своевременного закрытия потока и освобождения ресурса. Я рекомендую вам использовать finally {reader.close();}.
Винсент Кантин

2
Я думаю, что полезно указать, что приведенный выше код показывает ошибку в ADT - "reader.close ();" Строка должна быть помещена в другой блок try-catch. Проверьте эту тему: stackoverflow.com/questions/8981589/… :)
JakeP

1
getAssets - это класс в Context, поэтому для использования вне активности должен быть сделан вызов Context. Так что вне деятельности, это будет что-то вродеcontext.getAssets(.....)
Zoe

1
Согласно вашему обновлению (спасибо за добавление этого, кстати), наличие контекста в статических полях является утечкой памяти. Это следует использовать с осторожностью и правильно очищать. В противном случае вы получите утечку памяти, которая может оказать большое влияние на приложение.
Зоя

65
getAssets()

работает только в Activity в любом другом классе, который вы должны использовать Contextдля него.

Сделать конструктор для класса Utils передачей ссылки на активность (безобразно) или контекста приложения в качестве параметра для него. Используя это, используйте getAsset () в вашем классе Utils.


1
Он работает со всем, что является подклассом Context, из которых Activity является одним из многих.
Джереми Логан

Только что отметил, я написал Context.
user370305

@ user370305 знаете, как я могу преобразовать InputStream в FileInputStream?
hotHead

@ user370305 как это безобразно?
Севастян Саванюк

Передача объектов пользовательского интерфейса без учета последствий, как правило, является плохой практикой. Если вы не будете осторожны, вы можете вызвать утечки памяти или попытаться использовать мертвые контексты. Хорошо прочитал по теме: android.jlelse.eu/memory-leak-patterns-in-android-4741a7fcb570
milosmns

49

Лучше поздно, чем никогда.

У меня были трудности с чтением файлов построчно при некоторых обстоятельствах. Приведенный ниже метод является лучшим, который я нашел, и я рекомендую его.

Использование: String yourData = LoadData("YourDataFile.txt");

Где предполагается, что YourDataFile.txt находится в активах /

 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;

 }

Моя возвращаемая строка: android.content.res.AssetManager$AssetInputStream@4195dfa0 ..
Болдияр Пол

то же самое здесь, res.AssetManager $ AssetInputStream @ .... какая-то конкретная причина, почему он возвращает это?
Bigs

Вы дважды выделяете память - сначала для буфера, а затем для строки. Не работает для больших файлов.
JaakL

1
идеальный способ выделить размер буфера stream.available().
Касим Рангвала

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

Вы могли бы подумать, что если вы закроете BufferedReader, то он также должен автоматически закрыть InputStreanReader и InputStream. Потому что это то, что вы не создаете ручку для тех, например input = new BufferedReader(new InputStreamReader(fIn));.
Транс

3
Я бы предложил создать отдельные блоки try / catch для закрытия всех ваших ресурсов в конце; вместо того, чтобы объединять их все в одно - поскольку это может оставить другие ресурсы незакрытыми, если предыдущая попытка закрыть другой ресурс вызывает исключение
Рис

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

8

однострочное решение для котлина:

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

7

getAssets() Метод будет работать, когда вы вызываете внутри класса Activity.

Если вы вызываете этот метод в классе, отличном от Activity, вам нужно вызывать этот метод из Context, который передается из класса Activity. Ниже приведена строка, по которой вы можете получить доступ к методу.

ContextInstance.getAssets();

ContextInstance может быть передано как класс активности.


5

Чтение и запись файлов всегда были многословны и подвержены ошибкам. Избегайте этих ответов и просто используйте 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
Вы знаете, почему это выглядит более эстетично и коротко? Ну, потому что вы пропустили, по крайней мере, половину кода здесь. Пропущенные части: 1) IOExceptionблок try / catch 2) Закрытие потоков в случае возникновения исключения 3) Этот код читает одну строку, а не весь файл. С точки зрения производительности, эта библиотека, безусловно, является в своем роде, без сомнения. Теперь, скажите мне, я все еще должен избегать "этих ответов" и использовать Okio только для чтения файлов? Ответ НЕТ, если он уже не является частью вашего приложения.
Фарид

Обновил мой ответ.
Сакет

4

Вот метод для чтения файла в ресурсах:

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

Это хороший ответ, но это плохой подход к использованию конкатенации строк. Попробуйте вместо этого использовать StringBuilder. StringBuilder contentBuilder = new StringBuilder (); while ((line = reader.readLine ())! = null) {builder.append ("\ n"). append (line); } И в конце вы можете создать новый объект String следующим образом: content = contentBuilder.toString ();
Barterio

4

Вы можете загрузить контент из файла. Считайте, что файл присутствует в папке активов.

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

Теперь вы можете получить контент, вызвав функцию следующим образом

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

Учитывая, что data.json хранится в Application \ app \ src \ main \ assets \ data.json


3

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

Кроме того, вы можете создать отдельный класс, который делает всю работу

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

На мой взгляд, лучше создать интерфейс, но это не обязательно

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

2

Если вы используете какой-либо другой класс, кроме Activity, вы можете сделать, как,

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

2

Используя Kotlin, вы можете сделать следующее, чтобы прочитать файл из ресурсов в 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

Может быть, уже слишком поздно, но ради других, которые ищут персиковые ответы:

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 + "";

    }

Ссылка теперь возвращаетсяFile no longer available That file has now been permanently removed and cannot be recovered
gregn3

1

Класс Scanner может упростить это.

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

Вы можете объединить эти 2 строки sb.append (scanner.nextLine ()); sb.append ( '\ п'); в sb.appendln (scanner.nextLine ());
Мойтаба

0

@HpTerm ответить на версию 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
}

В настоящее время это будет предшествовать нулю в строке. Необходимые изменения: var mLine:Stringдолжен быть var mLine:String? var data: String?должен быть var data = ""возвращаемый тип должен бытьString
fupduck

0

Вот способ , чтобы получить InputStreamдля файла в assetsпапке без Context, Activity, Fragmentили Application. Как вы получаете данные из этогоInputStream зависит от вас. Есть много предложений для этого в других ответах здесь.

Котлин

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

Ява

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

Все ставки отключены, если кастом ClassLoaderнаходится в игре.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.