性能:Android JCIFS文件读取速度很慢

时间:2017-03-30 06:12:58

标签: android performance optimization jcifs

首先,我看到了一个现有问题(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)

顺便说一句,我已经测试过与其他商业应用程序复制相同的文件。文件指挥官,华硕文件管理器显示相似的低速,ES文件资源管理器显示约2MB / s,Solid Explorer显示约5MB / s。由于我很确定所有这些都使用JCIFS(虽然它的版本可能略有不同),但必须有一种方法可以像Solid Explorer一样达到至少5MB / s的速度。

3 个答案:

答案 0 :(得分:2)

在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&#39;执照。但是,哦,好吧,似乎很多Android应用程序开发人员都忽略了他们使用的库的许可证。他们甚至没有恰当地相信他们使用的开源库。

答案 1 :(得分:0)

您是否尝试过:require = { baseUrl: '/assets/js', paths: { 'intl-tel-input': '/assets/vendor/intl-tel-input/build/js/intlTelInput.min', }, shim: { 'intl-tel-input': { deps: ['libphonenumber-utils'] }, } };

就我而言(虽然是Java),它对慢速连接很有帮助。默认情况下为jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "true");

对我来说唯一的问题是,我不确定该财产是否会破坏&#34;其他工作正常的事情......

答案 2 :(得分:0)

有一个大缓冲区大小读取的补丁:

从自述文件内部:

  

这个补丁增加了两个可以改善读写的SMB   表现相当。不幸的是,它并不是很清楚   所有实现都正确支持命令。请注意   除了这个补丁'和'需要添加0xFFFF'   SmbTransport.java:doRecv:~437显示为:

     

int size = Encdec.dec_uint16be(BUF,2)&amp; 0xFFFF的;

     

尽管已在1.2.7中进行了此更改。

不确定这是否适用于Android,但解决方案可能类似。