`
java_cofi
  • 浏览: 49071 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Android开发——DiskLruCache用法详解以及工作原理深度解析

阅读更多

概述
LruCache在加载大图、多图时解决了内存泄露的问题,但是另外一个问题随之而来:图片从内存移除后,用户又要重新加载已经移除的图片时,只能从网络上重新加载一次,显然非常耗时,这是照片墙应用最常用的功能。Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证)。只可惜,Android Doc中并没有对DiskLruCache的用法给出详细的说明,而网上关于DiskLruCache的资料也少之又少,因此今天我准备专门写一篇博客来详细讲解DiskLruCache的用法,以及分析它的工作原理,这应该也是目前网上关于DiskLruCache最详细的资料了。

    那么我们先来看一下有哪些应用程序已经使用了DiskLruCache技术。在我所接触的应用范围里,Dropbox、Twitter、网易新闻等都是使用DiskLruCache来进行硬盘缓存的,其中Dropbox和Twitter大多数人应该都没用过,那么我们就从大家最熟悉的网易新闻开始着手分析,来对DiskLruCache有一个最初的认识吧。
     初探
     相信所有人都知道,网易新闻中的数据都是从网络上获取的,包括了很多的新闻内容和新闻图片,如下图所示:
     但是不知道大家有没有发现,这些内容和图片在从网络上获取到之后都会存入到本地缓存中,因此即使手机在没有网络的情况下依然能够加载出以前浏览过的新闻。而使用的缓存技术不用多说,自然是DiskLruCache了,那么首先第一个问题,这些数据都被缓存在了手机的什么位置呢? 其实DiskLruCache并没有限制数据的缓存位置,可以自由地进行设定,但是通常情况下多数应用程序都会将缓存的位置选择为 /sdcard/Android/data/<application package>/cache 这个路径。选择在这个位置有两点好处:第一,这是存储在SD卡上的,因此即使缓存再多的数据也不会对手机的内置存储空间有任何影响,只要SD卡空间足够就行。第二,这个路径被Android系统认定为应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉,这样就不会出现删除程序之后手机上还有很多残留数据的问题。 那么这里还是以网易新闻为例,它的客户端的包名是com.netease.newsreader.activity,因此数据缓存地址就应该是 /sdcard/Android/data/com.netease.newsreader.activity/cache ,我们进入到这个目录中看一下,结果如下图所示:

     可以看到有很多个文件夹,因为网易新闻对多种类型的数据都进行了缓存,这里简单起见我们只分析图片缓存就好,所以进入到bitmap文件夹当中。然后你将会看到一堆文件名很长的文件,这些文件命名没有任何规则,完全看不懂是什么意思,但如果你一直向下滚动,将会看到一个名为journal的文件,如下图所示:
     那么这些文件到底都是什么呢?看到这里相信有些朋友已经是一头雾水了,这里我简单解释一下。上面那些文件名很长的文件就是一张张缓存的图片,每个文件都对应着一张图片,而journal文件是DiskLruCache的一个日志文件,程序对每张图片的操作记录都存放在这个文件中,基本上看到journal这个文件就标志着该程序使用DiskLruCache技术了。
    下载
     好了,对DiskLruCache有了最初的认识之后,下面我们来学习一下DiskLruCache的用法吧。由于DiskLruCache并不是由Google官方编写的,所以这个类并没有被包含在Android API当中,我们需要将这个类从网上下载下来,然后手动添加到项目当中。DiskLruCache的源码在Github上托管,地址如下:
https://github.com/JakeWharton/DiskLruCache下载好了源码之后,只需要在项目中新建一个libcore.io包,然后将DiskLruCache.java文件复制到这个包中即可。
     打开缓存
     这样的话我们就把准备工作做好了,下面看一下DiskLruCache到底该如何使用。首先你要知道,DiskLruCache是不能new出实例的,如果我们要创建一个DiskLruCache的实例,则需要调用它的open()方法,接口如下所示:
1
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) ;
open()方法接收四个参数,第一个参数指定的是数据的缓存地址,第二个参数指定当前应用程序的版本号,第三个参数指定同一个key可以对应多少个缓存文件,基本都是传1,第四个参数指定最多可以缓存多少字节的数据。
     其中缓存地址前面已经说过了,通常都会存放在 /sdcard/Android/data/<application package>/cache 这个路径下面,但同时我们又需要考虑如果这个手机没有SD卡,或者SD正好被移除了的情况,因此比较优秀的程序都会专门写一个方法来获取缓存地址,如下所示:
1
public File getDiskCacheDir(Context context, String uniqueName) {
2
    String cachePath;
3
    if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
4
            || !Environment.isExternalStorageRemovable()) {
5
        cachePath = context.getExternalCacheDir().getPath();
6
    } else {
7
        cachePath = context.getCacheDir().getPath();
8
    }
9
    return new File(cachePath + File.separator + uniqueName);
10
}
     可以看到,当SD卡存在或者SD卡不可被移除的时候,就调用getExternalCacheDir()方法来获取缓存路径,否则就调用getCacheDir()方法来获取缓存路径。前者获取到的就是 /sdcard/Android/data/<application package>/cache 这个路径,而后者获取到的是 /data/data/<application package>/cache 这个路径。
接着又将获取到的路径和一个uniqueName进行拼接,作为最终的缓存路径返回。那么这个uniqueName又是什么呢?其实这就是为了对不同类型的数据进行区分而设定的一个唯一值,比如说在网易新闻缓存路径下看到的bitmap、object等文件夹。 接着是应用程序版本号,我们可以使用如下代码简单地获取到当前应用程序的版本号:
1
public int getAppVersion(Context context) {
2
    try {
3
        PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
4
        return info.versionCode;
5
    } catch (NameNotFoundException e) {
6
        e.printStackTrace();
7
    }
8
    return 1;
9
}
     需要注意的是,每当版本号改变,缓存路径下存储的所有数据都会被清除掉,因为DiskLruCache认为当应用程序有版本更新的时候,所有的数据都应该从网上重新获取。
后面两个参数就没什么需要解释的了,第三个参数传1,第四个参数通常传入10M的大小就够了,这个可以根据自身的情况进行调节。 因此,一个非常标准的open()方法就可以这样写:
1
DiskLruCache mDiskLruCache = null;
2
try {
3
    File cacheDir = getDiskCacheDir(context, "bitmap");
4
    if (!cacheDir.exists()) {
5
        cacheDir.mkdirs();
6
    }
7
    mDiskLruCache = DiskLruCache.open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
8
} catch (IOException e) {
9
    e.printStackTrace();
10
}
     首先调用getDiskCacheDir()方法获取到缓存地址的路径,然后判断一下该路径是否存在,如果不存在就创建一下。接着调用DiskLruCache的open()方法来创建实例,并把四个参数传入即可。
有了DiskLruCache的实例之后,我们就可以对缓存的数据进行操作了,操作类型主要包括写入、访问、移除等,我们一个个进行学习。
     写入缓存
     先来看写入,比如说现在有一张图片,地址是http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg,那么为了将这张图片下载下来,就可以这样写:
1
private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
2
    HttpURLConnection urlConnection = null;
3
    BufferedOutputStream out = null;
4
    BufferedInputStream in = null;
5
    try {
6
        final URL url = new URL(urlString);
7
        urlConnection = (HttpURLConnection) url.openConnection();
8
        in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
9
        out = new BufferedOutputStream(outputStream, 8 * 1024);
10
        int b;
11
        while ((b = in.read()) != -1) {
12
            out.write(b);
13
        }
14
        return true;
15
    } catch (final IOException e) {
16
        e.printStackTrace();
17
    } finally {
18
        if (urlConnection != null) {
19
            urlConnection.disconnect();
20
        }
21
        try {
22
            if (out != null) {
23
                out.close();
24
            }
25
            if (in != null) {
26
                in.close();
27
            }
28
        } catch (final IOException e) {
29
            e.printStackTrace();
30
        }
31
    }
32
    return false;
33
}
     这段代码相当基础,相信大家都看得懂,就是访问urlString中传入的网址,并通过outputStream写入到本地。有了这个方法之后,下面我们就可以使用DiskLruCache来进行写入了,写入的操作是借助DiskLruCache.Editor这个类完成的。类似地,这个类也是不能new的,需要调用DiskLruCache的edit()方法来获取实例,接口如下所示:
1
public Editor edit(String key) throws IOException
可以看到,edit()方法接收一个参数key,这个key将会成为缓存文件的文件名,并且必须要和图片的URL是一一对应的。那么怎样才能让key和图片的URL能够一一对应呢?直接使用URL来作为key?不太合适,因为图片URL中可能包含一些特殊字符,这些字符有可能在命名文件时是不合法的。其实最简单的做法就是将图片的URL进行MD5编码,编码后的字符串肯定是唯一的,并且只会包含0-F这样的字符,完全符合文件的命名规则。
那么我们就写一个方法用来将字符串进行MD5编码,代码如下所示:

1
public String hashKeyForDisk(String key) {
2
    String cacheKey;
3
    try {
4
        final MessageDigest mDigest = MessageDigest.getInstance("MD5");
5
        mDigest.update(key.getBytes());
6
        cacheKey = bytesToHexString(mDigest.digest());
7
    } catch (NoSuchAlgorithmException e) {
8
        cacheKey = String.valueOf(key.hashCode());
9
    }
10
    return cacheKey;
11
}
12

13
private String bytesToHexString(byte[] bytes) {
14
    StringBuilder sb = new StringBuilder();
15
    for (int i = 0; i < bytes.length; i++) {
16
        String hex = Integer.toHexString(0xFF & bytes[i]);
17
        if (hex.length() == 1) {
18
            sb.append('0');
19
        }
20
        sb.append(hex);
21
    }
22
    return sb.toString();
23
}
代码很简单,现在我们只需要调用一下hashKeyForDisk()方法,并把图片的URL传入到这个方法中,就可以得到对应的key了。
因此,现在就可以这样写来得到一个DiskLruCache.Editor的实例:

1
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
2
String key = hashKeyForDisk(imageUrl);
3
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
有了DiskLruCache.Editor的实例之后,我们可以调用它的newOutputStream()方法来创建一个输出流,然后把它传入到downloadUrlToStream()中就能实现下载并写入缓存的功能了。注意newOutputStream()方法接收一个index参数,由于前面在设置valueCount的时候指定的是1,所以这里index传0就可以了。在写入操作执行完之后,我们还需要调用一下commit()方法进行提交才能使写入生效,调用abort()方法的话则表示放弃此次写入。
因此,一次完整写入操作的代码如下所示:

1
new Thread(new Runnable() {
2
    @Override
3
    public void run() {
4
        try {
5
            String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
6
            String key = hashKeyForDisk(imageUrl);
7
            DiskLruCache.Editor editor = mDiskLruCache.edit(key);
8
            if (editor != null) {
9
                OutputStream outputStream = editor.newOutputStream(0);
10
                if (downloadUrlToStream(imageUrl, outputStream)) {
11
                    editor.commit();
12
                } else {
13
                    editor.abort();
14
                }
15
            }
16
            mDiskLruCache.flush();
17
        } catch (IOException e) {
18
            e.printStackTrace();
19
        }
20
    }
21
}).start();
由于这里调用了downloadUrlToStream()方法来从网络上下载图片,所以一定要确保这段代码是在子线程当中执行的。注意在代码的最后我还调用了一下flush()方法,这个方法并不是每次写入都必须要调用的,但在这里却不可缺少,我会在后面说明它的作用。
现在的话缓存应该是已经成功写入了,我们进入到SD卡上的缓存目录里看一下,如下图所示:

     可以看到,这里有一个文件名很长的文件,和一个journal文件,那个文件名很长的文件自然就是缓存的图片了,因为是使用了MD5编码来进行命名的。

读取缓存
     缓存已经写入成功之后,接下来我们就该学习一下如何读取了。读取的方法要比写入简单一些,主要是借助DiskLruCache的get()方法实现的,接口如下所示:

1
public synchronized Snapshot get(String key) throws IOException
很明显,get()方法要求传入一个key来获取到相应的缓存数据,而这个key毫无疑问就是将图片URL进行MD5编码后的值了,因此读取缓存数据的代码就可以这样写:

1
String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
2
String key = hashKeyForDisk(imageUrl);
3
DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
     很奇怪的是,这里获取到的是一个DiskLruCache.Snapshot对象,这个对象我们该怎么利用呢?很简单,只需要调用它的getInputStream()方法就可以得到缓存文件的输入流了。同样地,getInputStream()方法也需要传一个index参数,这里传入0就好。有了文件的输入流之后,想要把缓存图片显示到界面上就轻而易举了。所以,一段完整的读取缓存,并将图片加载到界面上的代码如下所示:
1
try {
2
    String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";
3
    String key = hashKeyForDisk(imageUrl);
4
    DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
5
    if (snapShot != null) {
6
        InputStream is = snapShot.getInputStream(0);
7
        Bitmap bitmap = BitmapFactory.decodeStream(is);
8
        mImage.setImageBitmap(bitmap);
9
    }
10
} catch (IOException e) {
11
    e.printStackTrace();
12
}
     我们使用了BitmapFactory的decodeStream()方法将文件流解析成Bitmap对象,然后把它设置到ImageView当中。如果运行一下程序,将会看到如下效果:
OK,图片已经成功显示出来了。注意这是我们从本地缓存中加载的,而不是从网络上加载的,因此即使在你手机没有联网的情况下,这张图片仍然可以显示出来。
     移除缓存
     学习完了写入缓存和读取缓存的方法之后,最难的两个操作你就都已经掌握了,那么接下来要学习的移除缓存对你来说也一定非常轻松了。移除缓存主要是借助DiskLruCache的remove()方法实现的,接口如下所示:
1
public synchronized boolean remove(String key) throws IOException
相信你已经相当熟悉了,remove()方法中要求传入一个key,然后会删除这个key对应的缓存图片,示例代码如下:

1
try {
2
    String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";  
3
    String key = hashKeyForDisk(imageUrl);  
4
    mDiskLruCache.remove(key);
5
} catch (IOException e) {
6
    e.printStackTrace();
7
}
     用法虽然简单,但是你要知道,这个方法我们并不应该经常去调用它。因为你完全不需要担心缓存的数据过多从而占用SD卡太多空间的问题,DiskLruCache会根据我们在调用open()方法时设定的缓存最大值来自动删除多余的缓存。只有你确定某个key对应的缓存内容已经过期,需要从网络获取最新数据的时候才应该调用remove()方法来移除缓存。
    
     其它API
     除了写入缓存、读取缓存、移除缓存之外,DiskLruCache还提供了另外一些比较常用的API,我们简单学习一下。 1. size() 这个方法会返回当前缓存路径下所有缓存数据的总字节数,以byte为单位,如果应用程序中需要在界面上显示当前缓存数据的总大小,就可以通过调用这个方法计算出来。比如网易新闻中就有这样一个功能,如下图所示:
2.flush() 这个方法用于将内存中的操作记录同步到日志文件(也就是journal文件)当中。这个方法非常重要,因为DiskLruCache能够正常工作的前提就是要依赖于journal文件中的内容。前面在讲解写入缓存操作的时候我有调用过一次这个方法,但其实并不是每次写入缓存都要调用一次flush()方法的,频繁地调用并不会带来任何好处,只会额外增加同步journal文件的时间。比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了。 3.close() 这个方法用于将DiskLruCache关闭掉,是和open()方法对应的一个方法。关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法,通常只应该在Activity的onDestroy()方法中去调用close()方法。
4.delete()

这个方法用于将所有的缓存数据全部删除,比如说网易新闻中的那个手动清理缓存功能,其实只需要调用一下DiskLruCache的delete()方法就可以实现了。

解读journal
前面已经提到过,DiskLruCache能够正常工作的前提就是要依赖于journal文件中的内容,因此,能够读懂journal文件对于我们理解DiskLruCache的工作原理有着非常重要的作用。那么journal文件中的内容到底是什么样的呢?我们来打开瞧一瞧吧,如下图所示:


由于现在只缓存了一张图片,所以journal中并没有几行日志,我们一行行进行分析。第一行是个固定的字符串“libcore.io.DiskLruCache”,标志着我们使用的是DiskLruCache技术。第二行是DiskLruCache的版本号,这个值是恒为1的。第三行是应用程序的版本号,我们在open()方法里传入的版本号是什么这里就会显示什么。第四行是valueCount,这个值也是在open()方法中传入的,通常情况下都为1。第五行是一个空行。前五行也被称为journal文件的头,这部分内容还是比较好理解的,但是接下来的部分就要稍微动点脑筋了。

第六行是以一个DIRTY前缀开始的,后面紧跟着缓存图片的key。通常我们看到DIRTY这个字样都不代表着什么好事情,意味着这是一条脏数据。没错,每当我们调用一次DiskLruCache的edit()方法时,都会向journal文件中写入一条DIRTY记录,表示我们正准备写入一条缓存数据,但不知结果如何。然后调用commit()方法表示写入缓存成功,这时会向journal中写入一条CLEAN记录,意味着这条“脏”数据被“洗干净了”,调用abort()方法表示写入缓存失败,这时会向journal中写入一条REMOVE记录。也就是说,每一行DIRTY的key,后面都应该有一行对应的CLEAN或者REMOVE的记录,否则这条数据就是“脏”的,会被自动删除掉。

如果你足够细心的话应该还会注意到,第七行的那条记录,除了CLEAN前缀和key之外,后面还有一个152313,这是什么意思呢?其实,DiskLruCache会在每一行CLEAN记录的最后加上该条缓存数据的大小,以字节为单位。152313也就是我们缓存的那张图片的字节数了,换算出来大概是148.74K,和缓存图片刚刚好一样大,如下图所示:


前面我们所学的size()方法可以获取到当前缓存路径下所有缓存数据的总字节数,其实它的工作原理就是把journal文件中所有CLEAN记录的字节数相加,求出的总合再把它返回而已。

除了DIRTY、CLEAN、REMOVE之外,还有一种前缀是READ的记录,这个就非常简单了,每当我们调用get()方法去读取一条缓存数据时,就会向journal文件中写入一条READ记录。因此,像网易新闻这种图片和数据量都非常大的程序,journal文件中就可能会有大量的READ记录。

那么你可能会担心了,如果我不停频繁操作的话,就会不断地向journal文件中写入数据,那这样journal文件岂不是会越来越大?这倒不必担心,DiskLruCache中使用了一个redundantOpCount变量来记录用户操作的次数,每执行一次写入、读取或移除缓存的操作,这个变量值都会加1,当变量值达到2000的时候就会触发重构journal的事件,这时会自动把journal中一些多余的、不必要的记录全部清除掉,保证journal文件的大小始终保持在一个合理的范围内。

好了,这样的话我们就算是把DiskLruCache的用法以及简要的工作原理分析完了。至于DiskLruCache的源码还是比较简单的, 限于篇幅原因就不在这里展开了,感兴趣的朋友可以自己去摸索。下一篇文章中,我会带着大家通过一个项目实战的方式来更加深入地理解DiskLruCache的用法。感兴趣的朋友请继续阅读 Android照片墙完整版,完美结合LruCache和DiskLruCache 。

 

转自 http://www.mobile-open.com/2014/3104.html

 

分享到:
评论

相关推荐

    停车场管理系统c语言.docx

    问题描述: 停车场内只有一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在停车场的最北端),若车场内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入; 当停车场内某辆车要离开时,在它之后开入的车辆必须先退出车场为它让路,待该辆车开出大门外,其它车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。试为停车场编制按上述要求进行管理的模拟程序。 1.基本要求 (1)以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。 (2)每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码及到达或离去的时刻,对每一组输入数据进行操作后的输出数据为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车离去;则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。 (3)栈以顺序结构实现,队列以链表实现。 2.重点难点 重点:针对停车场问题的特点,利

    精选毕设项目-人民好公仆小程序(生活+便民+政务).zip

    精选毕设项目-人民好公仆小程序(生活+便民+政务)

    精选毕设项目-相册;处理用户信息.zip

    精选毕设项目-相册;处理用户信息

    精选毕设项目-喵喵小说.zip

    精选毕设项目-喵喵小说

    精选毕设项目-图片预览带后端.zip

    精选毕设项目-图片预览带后端

    精选项目-爱靓女带后台.zip

    精选项目-爱靓女带后台

    法院综合安全监管平台解决方案PPT(53页).pptx

    在科技与司法的交响曲中,智慧法院应运而生,成为新时代司法服务的新篇章。它不仅仅是一个概念,更是对法院传统工作模式的一次深刻变革。智慧法院通过移动信息化技术,为法院系统注入了强大的生命力,有效缓解了案多人少的矛盾,让司法服务更加高效、便捷。 立案、调解、审判,每一个阶段都融入了科技的智慧。在立案阶段,智慧法院利用区块链技术实现可信存证,确保了电子合同的合法性和安全性,让交易双方的身份真实性、交易安全性得到了有力见证。这不仅极大地缩短了立案时间,还为后续审判工作奠定了坚实的基础。在调解阶段,多元调解服务平台借助人工智能、自然语言处理等前沿技术,实现了矛盾纠纷的快速化解。无论是矛盾类型的多元化,还是化解主体的多元化,智慧法院都能提供一站式、全方位的服务,让纠纷解决更加高效、和谐。而在审判阶段,智能立案、智能送达、智能庭审、智能判决等一系列智能化手段的应用,更是让审判活动变得更加智能化、集约化。这不仅提高了审判效率,还确保了审判质量的稳步提升。 更为引人注目的是,智慧法院还构建了一套完善的执行体系。移动执行指挥云平台的建设,让执行工作变得更加精准、高效。执行指挥中心和信息管理中心的一体化应用,实现了信息的实时传输和交换,为执行工作提供了强有力的支撑。而执行指挥车的配备,更是让执行现场通讯信号得到了有力保障,应急通讯能力得到了显著提升。这一系列创新举措的实施,不仅让执行难问题得到了有效解决,还为构建诚信社会、保障金融法治化营商环境提供了有力支撑。智慧法院的出现,让司法服务更加贴近民心,让公平正义的阳光更加温暖人心。

    西门子1200与3台台达DTK温控器通讯程序 功能:实现西门子1200 PLC对3台台达DTK温控器进行485通讯控制,在触摸屏上设定温度,读取温度 器件:西门子12

    西门子1200与3台台达DTK温控器通讯程序 功能:实现西门子1200 PLC对3台台达DTK温控器进行485通讯控制,在触摸屏上设定温度,读取温度 器件:西门子1200 1214DC DC DC.昆仑通态TPC7062Ti ,西门子KTP700 Basic PN,台达DTK 4848V12温控器。 说明:的是程序,带详细注释程序,西门子触摸屏程序,PLC设置和温控器设置,接线说明书。 #SIEMENS 西门子

    机械设计电阻绕线焊线一体机sw18全套技术资料100%好用.zip

    机械设计电阻绕线焊线一体机sw18全套技术资料100%好用.zip

    VB6编写的上位机采集2路温度 并形成曲线图 还可查看历史数据

    VB6编写的上位机源码,可实时显示曲线图,带有数据库,可以进行历史数据的保存 及 查看历史采集数据。

    精选毕设项目-新浪读书.zip

    精选毕设项目-新浪读书

    jQuery+Slick插件实现游戏人物轮播展示切换特效源码.zip

    jQuery+Slick插件实现游戏人物轮播展示切换特效源码是一款通过背景图片的切换来显示不同的人物效果,轮播效果通过slick幻灯片插件来制作。效果非常棒,有需要的朋友可以直接下载使用,适应各大网站

    精选毕设项目-地图查找附件.zip

    精选毕设项目-地图查找附件

    (蛐蛐voc数据)农作物病虫害识别目标检测数据集,VOC格式,蛐蛐数据集,纯手动标注,用来进行目标检测代码训练的数据

    (蛐蛐voc数据)农作物病虫害识别目标检测数据集,VOC格式,蛐蛐数据集,纯手动标注,用来进行目标检测代码训练的数据。

    MATLAB Simulink仿真模型 双馈风机并网频率控制仿真模型,利用下垂控制与惯性控制结合的综合惯性控制,实现电力系统的频率稳定,两台同步发电机组,具体参数可自行调节,频率波形比较可利用matl

    MATLAB Simulink仿真模型 双馈风机并网频率控制仿真模型,利用下垂控制与惯性控制结合的综合惯性控制,实现电力系统的频率稳定,两台同步发电机组,具体参数可自行调节,频率波形比较可利用matlab工作区画出。

    科研项目结题报告的撰写指南:结构、内容与注意事项

    一、结题报告的类型及主要结构 结题报告是一种专门用于科研课题结题验收的实用性报告类文体,也叫研究报告。它是研究者在课题研究结束后对科研课题研究过程和研究成果进行客观、全面、实事求是的描述,是课题研究所有材料中最主要的材料,也是科研课题结题验收的主要依据。   一篇规范、合格的结题报告,需要回答好3个问题:一是“为什么要选择这项课题进行研究?”二是“这项课题是怎样进行研究的?”三是“课题研究取得哪些研究成果?”  基本结构大致包括以下部分: 第一个问题 “为什么要选择这项课题进行研究?”  1.课题提出的背景;2.课题研究的意义(包括理论意义和现实意义,这个部分也可以合并归入“课题提出的背景”部分);第二个问题“这项课题是怎样进行研究的?”3.文献综述;4.课题研究的理论依据;5.课题研究的目标;6.课题研究的主要内容;7.课题研究的对象;8.课题研究的方法;9. 课题研究的主要过程(研究的步骤);   除了第9部分外,从第1到第8部分在填报课题立项申报表、在制定课题研究方案、在开题报告中,都有要求,内容基本相同。到了撰写结题报告时,只须稍作适当修改就可以了。而第9部分,则需要通过对

    1+X网络安全应急响应之应急准备:构建高效安全的应急响应体系

    内容概要:本文档重点讲述了网络安全应急响应的各项准备工作,涵盖了‘1+X’网络安全应急响应的职业技能等级证书概述、应急响应的基础知识、应急响应组织的建立、风险评估与改进、应急响应预案的制定以及详细的应急响应计划处置样例。文中详细介绍了各级职业技能的要求和任务,尤其关注如何未雨绸缪,制定完善的应急预案以应对潜在的网络安全风险;同时也探讨了如何在网络安全事件发生时,采取及时有效的应急处置措施。 适合人群:从事或有兴趣进入网络安全领域的从业人员,尤其是准备考取‘1+X’网络安全应急响应职业技能等级证书的相关人员。 使用场景及目标:帮助读者了解网络安全应急响应的基本概念及其在整个国家安全框架中的重要地位;指导读者学会如何建立健全高效的应急响应组织结构,如何进行全面的风险评估以及如何编制切实可行的应急预案;通过实例剖析,增强读者应对突发网络安全事件的能力。文档的目标在于提升读者在不同层面的专业技能,包括但不限于系统备份、日志分析、安全漏洞修复等方面的能力。 阅读建议:此文档结构清晰,内容详尽,非常适合有一定基础的技术从业者参考学习。建议读者逐章节深入了解,特别是关注自身岗位对应的技能细分类别。此外,结合实例深入理解和练习如何进行应急处置是非常有价值的,有助于提升自身的实战能力。

    电动汽车动力系统匹配计算模型:输入整车参数及性能要求,一键生成驱动系统的扭矩功率峰值转速等参数 2、整车动力经济性计算模型:包含NEDC WLTC CLTC工况,输入整车参数可生成工况电耗、百公里电

    电动汽车动力系统匹配计算模型:输入整车参数及性能要求,一键生成驱动系统的扭矩功率峰值转速等参数。 2、整车动力经济性计算模型:包含NEDC WLTC CLTC工况,输入整车参数可生成工况电耗、百公里电耗、匀速工况续航、百公里电耗等信息。 实际项目中使用的计算仿真模型. 两个模型打包

    chromedriver-linux64_122.0.6254.0.zip

    chromedriver-linux64_122.0.6254.0

    SRS构型七自由度冗余机械臂运动学建模全套matlab代码 代码主要功能: 1. 基于臂角参数化方法求解机械臂在给定末端位姿和臂角下的关节角度; 2. 求解机械臂在给定末端位姿下的有效臂角范围

    SRS构型七自由度冗余机械臂运动学建模全套matlab代码 代码主要功能: [1]. 基于臂角参数化方法求解机械臂在给定末端位姿和臂角下的关节角度; [2]. 求解机械臂在给定末端位姿下的有效臂角范围,有效即在该区间内机械臂关节角度不会超出关节限位; [3]. 以避关节限位为目标在有效臂角区间内进行最优臂角的选取,进而获取机械臂在给定末端位姿下的最优关节角度。 购前须知: 1. 代码均为个人手写,主要包含运动学建模全套代码; 2. 代码已经包含必要的注释; 包含原理推导文档,不包含绘图脚本以及urdf;

Global site tag (gtag.js) - Google Analytics