首先,我看到了一个现有问题 ( JCIFS: file retrieval is too slow to be usable ),但它是针对 Java 的,而不是 Android,而且建议的答案都没有用。
我在 Android Studio 2.3 中为 Android SDK 25 (7.1.1) 创建了一个默认项目,将库与 compile 'jcifs:jcifs:1.3.17'
链接起来,并输入了以下简单测试代码。结果在代码下方。
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jcifs.Config.setProperty("jcifs.util.loglevel", "3");
//jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "false");
//jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");
try
{
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", ID, PASSWORD);
final SmbFile smb = new SmbFile("smb://192.168.XX.XX/Share/FileName", auth);
Thread t = new Thread(new Runnable()
{
@Override
public void run()
{
Log.d(TAG, "Test Start");
for(int i = 1000; i<10000; i+=1000)
measure(i);
Log.d(TAG, "Test End");
}
private void measure(int bufferSize)
{
Log.d(TAG, "=====Buffer: " + bufferSize + "============");
try
{
byte[] buffer = new byte[bufferSize];
int read = 0;
InputStream str = smb.getInputStream();
long start = System.nanoTime();
while(read < 1000000)
read += str.read(buffer);
long end = System.nanoTime();
str.close();
float time = (float) ((end - start) / 1000000000d);
float speed = (float) read / 1048576 / time;
Log.d(TAG, "Time:" + time + ", size =" + read);
Log.d(TAG, "Speed = " + speed + "MB/s");
}
catch(IOException exc)
{
exc.printStackTrace();
}
}
});
t.start();
}
catch(Exception exc)
{
Log.d(TAG, exc.toString());
}
}
结果
Test Start
=====Buffer: 1000============
Time:2.210785, size =1000000
Speed = 0.43137363MB/s
=====Buffer: 2000============
Time:1.4158936, size =1000000
Speed = 0.6735495MB/s
=====Buffer: 3000============
Time:1.0556641, size =1002000
Speed = 0.9051948MB/s
=====Buffer: 4000============
Time:0.7543335, size =1000000
Speed = 1.2642609MB/s
=====Buffer: 5000============
Time:3.6557617, size =1000000
Speed = 0.26086885MB/s
=====Buffer: 6000============
Time:3.292389, size =1002000
Speed = 0.2902396MB/s
=====Buffer: 7000============
Time:2.9179688, size =1001000
Speed = 0.32715496MB/s
=====Buffer: 8000============
Time:2.462616, size =1000000
Speed = 0.38726068MB/s
=====Buffer: 9000============
Time:3.9379272, size =1008000
Speed = 0.24411413MB/s
Test End
读取速度约为0.2MB/s ~ 1.2MB/s。设备连接150Mbps Wi-Fi,理论上可以达到10MB/s以上。 SMB 服务器也不慢。当我将文件复制到笔记本电脑时,读取速度约为 30MB/s。
为什么这么慢?我应该检查什么?如果缓冲区大小为 4000,为什么读取速度大约提高 5 倍(1.2MB/s)?
顺便说一句,我已经测试过使用其他商业应用程序复制相同的文件。 File Commander、Asus File Manager 显示出类似的低速,ES File Explorer 显示大约 2MB/s,而 Solid Explorer 显示大约 5MB/s。因为我很确定它们都使用 JCIFS(尽管它的版本可能略有不同),所以必须有一种方法可以像 Solid Explorer 那样达到至少 5MB/s。
最佳答案
在Windows电脑上使用WireShark(网络分析工具)后,我发现无论我设置什么缓冲区大小,读取SMB命令总是给Windows电脑4286字节。似乎 SmbFileInputStream.java
正在使用服务器的最大缓冲区大小。
但是当我看到来自 Soild Explorer 的数据包时,它是 32768 字节。因此,我反编译了 Solid Explorer 的 APK(它当然是经过混淆处理的),并在其中看到了 SmbFileInputStream.java
文件(该文件属于 JCIFS)。似乎 Solid Explorer 的开发人员修改了该文件,并设置了更大的 readSize
。所以,我尝试了类似的事情。然后我用上面的相同代码实现了 5MB/s。
由于 JCIFS 附带 LGPL,Solid Explorer 在不公开源代码的情况下使用修改后的 JCIFS 违反了 JCIFS 的许可。但是,哦,好吧,似乎很多 Android 应用程序开发人员都忽略了他们使用的库的许可。他们甚至没有正确地归功于他们使用的开源库。
关于android - 性能:Android JCIFS 文件读取速度慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43109872/