[英]How to read a text file from “assets” directory as a string?
I have a file in my assets folder... how do I read it? 我的资产文件夹中有一个文件...如何阅读?
Now I'm trying: 现在我正在尝试:
public static String readFileAsString(String filePath)
throws java.io.IOException{
StringBuffer fileData = new StringBuffer(1000);
BufferedReader reader = new BufferedReader(
new FileReader(filePath));
char[] buf = new char[1024];
int numRead=0;
while((numRead=reader.read(buf)) != -1){
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
reader.close();
return fileData.toString();
}
But it cast a null pointer exception... 但它抛出一个空指针异常......
the file is called "origin" and it is in folder assets 该文件名为“origin”,它位于文件夹资产中
I tried to cast it with: 我试着把它投射:
readFileAsString("file:///android_asset/origin");
and 和
readFileAsString("asset/origin");``
but both failed... any advice? 但都失败了......有什么建议吗?
BufferedReader's readLine() method returns a null when the end of the file is reached, so you'll need to watch for it and avoid trying to append it to your string. 当达到文件末尾时,BufferedReader的readLine()方法返回null,因此您需要注意它并避免尝试将其附加到字符串中。
The following code should be easy enough: 以下代码应该很简单:
public static String readFileAsString(String filePath) throws java.io.IOException
{
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line, results = "";
while( ( line = reader.readLine() ) != null)
{
results += line;
}
reader.close();
return results;
}
Simple and to-the-point. 简单而重要。
public static String readFile( String filePath ) throws IOException
{
Reader reader = new FileReader( filePath );
StringBuilder sb = new StringBuilder();
char buffer[] = new char[16384]; // read 16k blocks
int len; // how much content was read?
while( ( len = reader.read( buffer ) ) > 0 ){
sb.append( buffer, 0, len );
}
reader.close();
return sb.toString();
}
It's very straight forward, very fast, and works well for unreasonable large textfiles (100+ MB) 它非常直接,非常快,适用于不合理的大型文本文件(100 + MB)
(Code at the end) (最后的代码)
Many times it won't matter, but this method is pretty fast and quite readable. 很多时候它并不重要,但这种方法非常快,而且非常易读。 In fact its an order of complexity faster than @Raceimation's answer -- O(n) instead of O(n^2).
事实上,它的复杂度比@ Raceimation的答案更快--O(n)而不是O(n ^ 2)。
I've tested six methods (from slow to fast): 我测试了六种方法(从慢到快):
Preallocating the buffer entirely is the fastest on very large files, but the method isn't very versatile because the total filesize must be known ahead of time. 完全预分配缓冲区对于非常大的文件是最快的,但是该方法不是非常通用,因为必须提前知道总文件大小。 Thats why i suggest using strBuilder with char[] buffers, its still simple and if needed easily changable to accept any input stream instead of just files.
这就是为什么我建议使用带有char []缓冲区的strBuilder,它仍然很简单,如果需要,可以轻松地接受任何输入流而不仅仅是文件。 Yet its certainly fast enough for all reasonable cases.
然而,它对于所有合理的案例来说肯定足够快
import java.io.*;
public class Test
{
static final int N = 5;
public final static void main( String args[] ) throws IOException{
test( "1k.txt", true );
test( "10k.txt", true );
// concat with += would take ages here, so we skip it
test( "100k.txt", false );
test( "2142k.txt", false );
test( "pruned-names.csv", false );
// ah, what the heck, why not try a binary file
test( "/Users/hansi/Downloads/xcode46graphicstools6938140a.dmg", false );
}
public static void test( String file, boolean includeConcat ) throws IOException{
System.out.println( "Reading " + file + " (~" + (new File(file).length()/1024) + "Kbytes)" );
strbuilderwithchars( file );
strbuilderwithchars( file );
strbuilderwithchars( file );
tick( "Warm up... " );
if( includeConcat ){
for( int i = 0; i < N; i++ )
concat( file );
tick( "> Concat with += " );
}
else{
tick( "> Concat with += **skipped** " );
}
for( int i = 0; i < N; i++ )
strbuilderguess( file );
tick( "> StringBuilder init with length " );
for( int i = 0; i < N; i++ )
strbuilder( file );
tick( "> StringBuilder with line buffer " );
for( int i = 0; i < N; i++ )
strbuilderwithchars( file );
tick( "> StringBuilder with char[] buffer" );
for( int i = 0; i < N; i++ )
strbufferwithchars( file );
tick( "> StringBuffer with char[] buffer " );
for( int i = 0; i < N; i++ )
singleBuffer( file );
tick( "> Allocate byte[filesize] " );
System.out.println();
}
public static long now = System.currentTimeMillis();
public static void tick( String message ){
long t = System.currentTimeMillis();
System.out.println( message + ": " + ( t - now )/N + " ms" );
now = t;
}
// StringBuilder with char[] buffer
// + works if filesize is unknown
// + pretty fast
public static String strbuilderwithchars( String filePath ) throws IOException
{
Reader reader = new FileReader( filePath );
StringBuilder sb = new StringBuilder();
char buffer[] = new char[16384]; // read 16k blocks
int len; // how much content was read?
while( ( len = reader.read( buffer ) ) > 0 ){
sb.append( buffer, 0, len );
}
reader.close();
return sb.toString();
}
// StringBuffer with char[] buffer
// + works if filesize is unknown
// + faster than stringbuilder on my computer
// - should be slower than stringbuilder, which confuses me
public static String strbufferwithchars( String filePath ) throws IOException
{
Reader reader = new FileReader( filePath );
StringBuffer sb = new StringBuffer();
char buffer[] = new char[16384]; // read 16k blocks
int len; // how much content was read?
while( ( len = reader.read( buffer ) ) > 0 ){
sb.append( buffer, 0, len );
}
reader.close();
return sb.toString();
}
// StringBuilder init with length
// + works if filesize is unknown
// - not faster than any of the other methods, but more complicated
public static String strbuilderguess(String filePath) throws IOException
{
File file = new File( filePath );
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
StringBuilder sb = new StringBuilder( (int)file.length() );
while( ( line = reader.readLine() ) != null)
{
sb.append( line );
}
reader.close();
return sb.toString();
}
// StringBuilder with line buffer
// + works if filesize is unknown
// + pretty fast
// - speed may (!) vary with line length
public static String strbuilder(String filePath) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line;
StringBuilder sb = new StringBuilder();
while( ( line = reader.readLine() ) != null)
{
sb.append( line );
}
reader.close();
return sb.toString();
}
// Concat with +=
// - slow
// - slow
// - really slow
public static String concat(String filePath) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line, results = "";
int i = 0;
while( ( line = reader.readLine() ) != null)
{
results += line;
i++;
}
reader.close();
return results;
}
// Allocate byte[filesize]
// + seems to be the fastest for large files
// - only works if filesize is known in advance, so less versatile for a not significant performance gain
// + shortest code
public static String singleBuffer(String filePath ) throws IOException{
FileInputStream in = new FileInputStream( filePath );
byte buffer[] = new byte[(int) new File( filePath).length()]; // buffer for the entire file
int len = in.read( buffer );
return new String( buffer, 0, len );
}
}
/**
*** RESULTS ***
Reading 1k.txt (~31Kbytes)
Warm up... : 0 ms
> Concat with += : 37 ms
> StringBuilder init with length : 0 ms
> StringBuilder with line buffer : 0 ms
> StringBuilder with char[] buffer: 0 ms
> StringBuffer with char[] buffer : 0 ms
> Allocate byte[filesize] : 1 ms
Reading 10k.txt (~313Kbytes)
Warm up... : 0 ms
> Concat with += : 708 ms
> StringBuilder init with length : 2 ms
> StringBuilder with line buffer : 2 ms
> StringBuilder with char[] buffer: 1 ms
> StringBuffer with char[] buffer : 1 ms
> Allocate byte[filesize] : 1 ms
Reading 100k.txt (~3136Kbytes)
Warm up... : 7 ms
> Concat with += **skipped** : 0 ms
> StringBuilder init with length : 19 ms
> StringBuilder with line buffer : 21 ms
> StringBuilder with char[] buffer: 9 ms
> StringBuffer with char[] buffer : 9 ms
> Allocate byte[filesize] : 8 ms
Reading 2142k.txt (~67204Kbytes)
Warm up... : 181 ms
> Concat with += **skipped** : 0 ms
> StringBuilder init with length : 367 ms
> StringBuilder with line buffer : 372 ms
> StringBuilder with char[] buffer: 208 ms
> StringBuffer with char[] buffer : 202 ms
> Allocate byte[filesize] : 199 ms
Reading pruned-names.csv (~11200Kbytes)
Warm up... : 23 ms
> Concat with += **skipped** : 0 ms
> StringBuilder init with length : 54 ms
> StringBuilder with line buffer : 57 ms
> StringBuilder with char[] buffer: 32 ms
> StringBuffer with char[] buffer : 31 ms
> Allocate byte[filesize] : 32 ms
Reading /Users/hansi/Downloads/xcode46graphicstools6938140a.dmg (~123429Kbytes)
Warm up... : 1665 ms
> Concat with += **skipped** : 0 ms
> StringBuilder init with length : 2899 ms
> StringBuilder with line buffer : 2978 ms
> StringBuilder with char[] buffer: 2702 ms
> StringBuffer with char[] buffer : 2684 ms
> Allocate byte[filesize] : 1567 ms
**/
Ps. PS。 You might have noticed that StringBuffer is slightly faster than StringBuilder.
您可能已经注意到StringBuffer比StringBuilder稍快。 This is a bit nonsense because the classes are the same, except StringBuilder is not synchronized.
这有点无稽之谈,因为类是相同的,除了StringBuilder不同步。 If anyone can (or) can't reproduce this... I'm most curious :)
如果有人可以(或)不能重现这个......我最好奇:)
You can open an input stream using AssetsManager
. 您可以使用
AssetsManager
打开输入流。
InputStream input = getAssets().open("origin");
Reader reader = new InputStreamReader(input, "UTF-8");
getAssets()
is a method of the Context
class. getAssets()
是Context
类的一个方法。
Also note that you shouldn't recreate a buffer of characters ( buf = new char[1024]
, the last line of your cycle). 另请注意,您不应重新创建字符缓冲区(
buf = new char[1024]
,循环的最后一行)。
You should try org.appache.commons.io.IOUtils.toString(InputStream is)
to get file content as string. 您应该尝试使用
org.appache.commons.io.IOUtils.toString(InputStream is)
将文件内容作为字符串。 There you can pass InputStream
object which you will get from 在那里你可以传递你将从中获得的
InputStream
对象
getAssets().open("xml2json.txt")
in your Activity
. 在你的
Activity
。
To get String
use this: 要获取
String
使用:
String xml = IOUtils.toString((getAssets().open("xml2json.txt")));
I wrote a function that does the same thing as yours. 我写了一个与你的功能相同的功能。 I wrote it a while back but I believe it still works correctly.
我写了一段时间,但我相信它仍然可以正常工作。
public static final String grabAsSingleString(File fileToUse)
throws FileNotFoundException {
BufferedReader theReader = null;
String returnString = null;
try {
theReader = new BufferedReader(new FileReader(fileToUse));
char[] charArray = null;
if(fileToUse.length() > Integer.MAX_VALUE) {
// TODO implement handling of large files.
System.out.println("The file is larger than int max = " +
Integer.MAX_VALUE);
} else {
charArray = new char[(int)fileToUse.length()];
// Read the information into the buffer.
theReader.read(charArray, 0, (int)fileToUse.length());
returnString = new String(charArray);
}
} catch (FileNotFoundException ex) {
throw ex;
} catch(IOException ex) {
ex.printStackTrace();
} finally {
try {
theReader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
return returnString;
}
Now you can use this function if you wish, but when you're passing in the file either through a file object or a string, make sure you either give the full path of the file such as "C:\\Program Files\\test.dat" OR you pass in the relative link from your working directory. 现在您可以根据需要使用此功能,但是当您通过文件对象或字符串传递文件时,请确保提供文件的完整路径,例如“C:\\ Program Files \\ test”。 dat“或者您传入工作目录中的相对链接。 Your working directory is commonly the directory you launch the application from (unless you change it).
您的工作目录通常是您启动应用程序的目录(除非您更改它)。 So if the file was in a folder called data, you would pass in "./data/test.dat"
因此,如果文件位于名为data的文件夹中,您将传入“./data/test.dat”
Yes, I know this is working with android so the Windows URI isn't applicable, but you should get my point. 是的,我知道这是在使用android,所以Windows URI不适用,但你应该明白我的观点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.