我需要文件中每行的大小(以字节为单位),因此我可以获得读取文件的百分比。我已经使用file.length()
获得了文件的大小,但是如何获得每行的大小?
答案 0 :(得分:6)
你需要知道编码 - 否则这是一个毫无意义的问题。例如,“foo”是UTF-16中的6个字节,但是ASCII中是3个字节。假设您一次只读一行(根据您的问题),您应该知道您正在使用哪种编码,因为您应该在开始阅读时指定它。
您可以调用String.getBytes(charset)
来获取特定字符串的编码表示。
不只需拨打String.getBytes()
,因为它将使用平台默认编码。
请注意,所有这些都是有点工作...你已经读取了字节,将它们解码为文本,然后你将它们重新编码为字节......
答案 1 :(得分:3)
您可能会使用以下内容来阅读文件
FileInputStream fis = new FileInputStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
/* process line */
/* report percentage */
}
您需要在开头指定编码。如果你不这样做,你应该在Android上获得UTF-8。这是默认值,但可以更改。我会假设没有设备这样做。
重复已经说明的其他答案:字符数并不总是与字节数相同。特别是UTF编码很棘手。目前有249,764个指定的Unicode字符,可能超过一百万(WP),UTF使用1到4个字节来编码所有这些字符。 UTF-32是最简单的情况,因为它总是使用4个字节。 UTF-8动态地执行此操作并使用1到4个字节。简单的ASCII字符仅使用1个字节。 (来源:UTF & BOM FAQ)
获取可以使用的字节数,例如line.getBytes("UTF-8").length()
。一个很大的缺点是效率非常低,因为它每次都会创建String内部数组的副本,然后抛出它。这是在Android | Performance Tips
由于以下原因,从文件读取的实际字节数也不是100%准确:
例如,UTF-16文本文件通常以特殊的2字节BOM(字节顺序标记)开头,以表示它们是否必须解释为小端或大端。当你只看你从读者那里得到的String
时,不会报告那两个(UTF-8:3,UTF-32:4)字节。所以你已经离开了一些字节。
将文件的每一行转换为UTF-16 String
将包含每行的BOM字节数。因此getBytes
会为每一行报告2个字节太多。
行结束字符不是结果行的一部分 - String
。更糟糕的是,你有不同的方式来表示一条线的结束。通常只有1个字符的Unix样式'\n'
或者是两个字符的Windows样式'\r''\n'
。 BufferedReader
只会跳过这些内容。在这里,您的计算缺少非常多的字节数。从Unix / UTF-8的1个字节到Windows / UTF-32的8个字节。
如果你有Unix / UTF-16,最后两个原因会相互否定,但这可能不是典型的情况。错误的影响还取决于行长度:如果每行总共只有4个字节的错误,那么总共只有10个字节,那么你的进度将是非常错误的(如果我的数学很好,你的进度将达到140%或者在最后一行之后为60%,具体取决于你的计算假定每行为-4或+4字节)
这意味着到目前为止,无论你做什么,你只能得到一个近似值。
如果您编写自己的特殊字节计数Reader
,则可能会获得实际的字节数,但这将是相当多的工作。
另一种方法是使用自定义InputStream
来计算从底层流中实际读取的字节数。这并不难做,也不关心编码。
最大的缺点是它不会与你读取的行线性增加,因为BufferedReader
将填充它的内部缓冲区并从那里读取行,然后从文件中读取下一个块,依此类推。如果缓冲区足够大,则您已经在第一行处于100%。但我认为你的文件足够大,或者你不想知道进展情况。
例如,这将是一种实现。它有效,但我无法保证它是完美的。如果流使用mark()
和reset()
,则无效。文件阅读不应该这样做。
static class CountingInputStream extends FilterInputStream {
private long bytesRead;
protected CountingInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int result = super.read();
if (result != -1) bytesRead += 1;
return result;
}
@Override
public int read(byte[] b) throws IOException {
int result = super.read(b);
if (result != -1) bytesRead += result;
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int result = super.read(b, off, len);
if (result != -1) bytesRead += result;
return result;
}
@Override
public long skip(long n) throws IOException {
long result = super.skip(n);
if (result != -1) bytesRead += result;
return result;
}
public long getBytesRead() {
return bytesRead;
}
}
使用以下代码
File file = new File("mytestfile.txt");
int linesRead = 0;
long progress = 0;
long fileLength = file.length();
String line;
CountingInputStream cis = new CountingInputStream(new FileInputStream(file));
BufferedReader br = new BufferedReader(new InputStreamReader(cis, "UTF-8"), 8192);
while ((line = br.readLine()) != null) {
long newProgress = cis.getBytesRead();
if (progress != newProgress) {
progress = newProgress;
int percent = (int) ((progress * 100) / fileLength);
System.out.println(String.format("At line: %4d, bytes: %6d = %3d%%", linesRead, progress, percent));
}
linesRead++;
}
System.out.println("Total lines: " + linesRead);
System.out.println("Total bytes: " + fileLength);
br.close();
我得到像
这样的输出At line: 0, bytes: 8192 = 5%
At line: 82, bytes: 16384 = 10%
At line: 178, bytes: 24576 = 15%
....
At line: 1621, bytes: 155648 = 97%
At line: 1687, bytes: 159805 = 100%
Total lines: 1756
Total bytes: 159805
或者在同一文件UTF-16编码的情况下
At line: 0, bytes: 24576 = 7%
At line: 82, bytes: 40960 = 12%
At line: 178, bytes: 57344 = 17%
.....
At line: 1529, bytes: 303104 = 94%
At line: 1621, bytes: 319488 = 99%
At line: 1687, bytes: 319612 = 100%
Total lines: 1756
Total bytes: 319612
而不是打印,您可以更新您的进度。
那么,最好的方法是什么?
String#length()
(并且可能为行结尾添加+1或+2)
String#length()
快速而简单,只要您知道自己拥有哪些文件就应该没有问题。String#getBytes()
,处理1行的时间越长,临时数组及其垃圾收集的影响越小。不准确应在可接受的范围内。如果进度>请确保不要崩溃100%或<最后100%。InputStreamReader
和BufferedReader
的组合,因为Reader已经对字符进行了操作。 Android's implementation可能有助于作为起点。答案 2 :(得分:3)
final String hello_str = "Hello World";
hello_str.getBytes().length is the "byte size", i.e. the number of bytes
答案 3 :(得分:0)
如果File是ASCII文件,那么你可以使用String.length(); 否则会变得更复杂。
答案 4 :(得分:0)
考虑一下名为hello_str
final String hello_str = "Hello World";
//Check Character length
hello_str.length() //output will be 11
// Check encoded sizes
final byte[] utf8Bytes = hello_str.getBytes("UTF-8");
utf8Bytes.length //output will be 11
final byte[] utf16Bytes= hello_str.getBytes("UTF-16");
utf16Bytes.length // output will be "24"
final byte[] utf32Bytes = hello_str.getBytes("UTF-32");
utf32Bytes.length // output will be "44"