Android 10 分区存储

Android 各版本适配(更新到Android15) Android 各版本适配(更新到API14) 阅读详情

背景

以前,Android 开发者习惯在根目录建一个自己应用的文件夹,用于存放应用的数据。这样会导致用户卸载后,应用数据不会随之删除。导致手机文件特别混乱,长期占用空间,而且容易泄露用户隐私。

其实 Android 早就提供了 getCacheDir()、getFilesDir()、getExternalFilesDir()、getExternalCacheDir() 等 API 供开发者使用,但是开发者为了方便,没有去用。

为了解决这个问题,从 Android 10 开始,Google 添加了一个新特性 Scoped Storage,我们称之为分区存储,也可以称为沙盒。

在 Android 10 上,仍然可以通过以下两种手段避开分区存储:

  1. targetSdkVersion 设成 29 以下
  2. 在 manifest 中设置 android:requestLegacyExternalStorage=“true”

在 Android 11 上,requestLegacyExternalStorage 会失效,没有效果。但是又增加了 preserveLegacyExternalStorage 属性,对于覆盖安装的应用还能继续用,但是新应用不能用。

至于 targetSdkVersion,上传到 Google Play 的应用,Google 要求必须设成 30 及以上。

分区存储目录

  1. 沙盒目录
    通过 getExternalFilesDir() 等获取到的目录,随着 App 卸载会被删除。
    不过可以在 manifest 中设置 android:hasFragileUserData=“true” 让用户选择是否删除。

  2. 公共目录
    DCIM、Photos、Images、Videos、Audio、Downloads 等目录, App 卸载后会保留。

访问公共目录

重点说下公共目录,沙盒目录就不详细介绍了,沙盒目录可以通过系统提供的接口直接获取,可以直接通过路径读写,也不需要定义任何读写权限,很简单。

访问公共目录需要通过 MediaStore 或者 Storage Access Framework(以下简称 SAF)。媒体文件(图片,音频,视频)能通过 MediaStore 和 SAF 两种方式访问,非媒体文件只能通过 SAF 访问。

MediaStore

关于 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 读写权限,MediaStore 访问应用自身存放到公共目录下的文件不需要申请权限(但是如果应用卸载后重装,之前保存的文件将不属于本应用创建的文件),而如果要访问其他应用保存到公共目录下的文件则需要申请权限。

MediaStore 通过 Uri 操作文件。
各个目录的 Uri 如下:

类型UriUri 常量默认路径
Imagecontent://media/external/images/mediaMediaStore.Images.Media.EXTERNAL_CONTENT_URIPictures
Videocontent://media/external/video/mediaMediaStore.Video.Media.EXTERNAL_CONTENT_URIMovies
Audiocontent://media/external/audio/mediaMediaStore.Audio.Media.EXTERNAL_CONTENT_URIMusic
Downloadcontent://media/external/downloadsMediaStore.Downloads.EXTERNAL_CONTENT_URIDownload
Filecontent://media/external/MediaStore.Files.getContentUri(“external”)Documents
写文件
// 从 Assets 读取 Bitmap
Bitmap bitmap = null;
try {
    bitmap = BitmapFactory.decodeStream(getAssets().open("test.jpg"));
} catch (IOException e) {
    e.printStackTrace();
}

if (bitmap == null) return;

// 获取保存文件的 Uri
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
Uri insertUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

// 保存图片到 Pictures 目录下
if (insertUri != null) {
    OutputStream os = null;
    try {
        os = contentResolver.openOutputStream(insertUri);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        try {
            if (os != null) {
                os.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

上面的例子直接把图片保存到 Pictures 根目录,如果要在 Pictures 下创建子目录,需要用到 RELATIVE_PATH(Android 版本 >= 10)。

修改上面的例子,把子目录添加进 ContentValues:

ContentValues values = new ContentValues();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    // 指定子目录,否则保存到对应媒体类型文件夹根目录
    values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES +"/test");
}

还可以向 ContentValues 中添加其他信息,如:文件名,MIME 等
继续修改上面的例子:

ContentValues values = new ContentValues();
// 获取保存文件的 Uri
values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
// 指定保存的文件名,如果不设置,则系统会取当前的时间戳作为文件名
values.put(MediaStore.Images.Media.DISPLAY_NAME, "test_" + System.currentTimeMillis() + ".png");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    // 指定子目录,否则保存到对应媒体类型文件夹根目录
    values.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/test");
}

删除自己应用创建的文件

获取到对应的 Uri 之后 contentResolver.delete(uri,null,null) 即可。

查询自己应用创建的文件
// 查询
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        new String[]{
                MediaStore.Images.Media._ID,
                MediaStore.Images.Media.WIDTH,
                MediaStore.Images.Media.HEIGHT
        },
        MediaStore.Images.Media._ID + " > ? ", new String[]{"100"},
        MediaStore.Images.Media._ID + " DESC"
);

// 得到所有的 Uri
List<Uri> filesUris = new ArrayList<>();
while (cursor.moveToNext()) {
    int index = cursor.getColumnIndex(MediaStore.Images.Media._ID);
    Uri uri = ContentUris.withAppendedId(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getLong(index)
    );
    filesUris.add(uri);
}
cursor.close();

// 通过 Uri 获取具体内容并显示到界面上
ParcelFileDescriptor pfd = null;
try {
    pfd = contentResolver.openFileDescriptor(filesUris.get(0), "r");
    if (pfd != null) {
        Bitmap bitmap = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
        ((ImageView) findViewById(R.id.image)).setImageBitmap(bitmap);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (pfd != null) {
        try {
            pfd.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

查询其他应用创建的文件

如上文所诉,访问自己应用创建的文件不需要 READ_EXTERNAL_STORAGE 权限。以上代码获取到的 filesUris 只包含本应用之前创建的文件。
如果需要连其他应用的文件一起获取,则申请下 READ_EXTERNAL_STORAGE 权限即可。

修改其他应用创建的文件

同理,需要申请 WRITE_EXTERNAL_STORAGE 权限。
但是,即便申请了 WRITE_EXTERNAL_STORAGE 权限之后,还是会报如下异常:

android.app.RecoverableSecurityException: xxx has no access to content://media/external/images/media/100

这是因为还需要向用户申请修改的权限。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    try {
        delete();
    } catch (RecoverableSecurityException e) {
        e.printStackTrace();
        // 弹出对话框,向用户申请修改其他应用文件的权限
        requestConfirmDialog(e);
    }
}

private void delete() {
    Uri uri = Uri.parse("content://media/external/images/media/100");
    getContentResolver().delete(uri, null, null);
}

@RequiresApi(api = Build.VERSION_CODES.Q)
private void requestConfirmDialog(RecoverableSecurityException e) {
    try {
        startIntentSenderForResult(
                e.getUserAction().getActionIntent().getIntentSender()
                , 0, null, 0, 0, 0, null);
    } catch (IntentSender.SendIntentException ex) {
        ex.printStackTrace();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK){
        delete();
    }
}

将文件下载到 Download 目录
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

    private void downloadApkAndInstall(String downloadUrl, String apkName) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            // 使用原始方式
        } else {
            new Thread(() -> {
                BufferedInputStream bis = null;
                BufferedOutputStream bos = null;
                try {
                    URL url = new URL(downloadUrl);
                    URLConnection urlConnection = url.openConnection();
                    InputStream is = urlConnection.getInputStream();
                    bis = new BufferedInputStream(is);
                    ContentValues values = new ContentValues();
                    values.put(MediaStore.MediaColumns.DISPLAY_NAME, apkName);
                    values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
                    ContentResolver contentResolver = getContentResolver();
                    Uri uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
                    OutputStream os = contentResolver.openOutputStream(uri);
                    bos = new BufferedOutputStream(os);
                    byte[] buffer = new byte[1024];
                    int bytes = bis.read(buffer);
                    while (bytes >= 0) {
                        bos.write(buffer, 0, bytes);
                        bos.flush();
                        bytes = bis.read(buffer);
                    }
                    runOnUiThread(() -> installAPK(uri));
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (bis != null) bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        if (bos != null) bos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    private void installAPK(Uri uri) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        startActivity(intent);
    }

SAF

SAF 在 Android 4.4 就支持了。
SAF 通过系统提供的标准化 UI 浏览和修改手机中的文件,如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CJDiZ0mg-1669726526592)(//upload-images.jianshu.io/upload_images/1758334-d446069a881a7b58.png?imageMogr2/auto-orient/strip|imageView2/2/w/240/format/webp)]

ACTION_CREATE_DOCUMENT 创建文件
    private void createFile() {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_TITLE, "test_create.png");
        startActivityForResult(intent, WRITE_REQUEST_CODE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data == null || resultCode != RESULT_OK) return;
        if (requestCode == WRITE_REQUEST_CODE) {
            Log.d("tianjf", "write uri : " + data.getData());
        }
    }

运行之后,会启动标准文件管理器 UI 保存文件。
写文件不需要申请写权限。

ACTION_OPEN_DOCUMENT 读文件

因为有可能读取其他应用创建的文件,所以需要申请读权限。

    protected void readFiles() {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        startActivityForResult(intent, READ_REQUEST_CODE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data == null || resultCode != RESULT_OK) return;
        if (requestCode == READ_REQUEST_CODE) {
            Log.d("tianjf", "read uri : " + data.getData());
            process(data.getData());
        }
    }

    private void process(Uri uri) {
        String[] selectionArgs = new String[]{DocumentsContract.getDocumentId(uri).split(":")[1]};
        Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, MediaStore.Images.Media._ID + "=?",
                selectionArgs, null);
        if (null != cursor) {
            if (cursor.moveToFirst()) {
                int index = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                if (index > -1) {
                    String path = cursor.getString(index);
                    Log.d("tianjf", "onActivityResult path=" + path + ";id=" + selectionArgs[0]);
                }
            }
            cursor.close();
        }
    }

ACTION_OPEN_DOCUMENT_TREE 读取文件夹
    protected void readFolder() {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        startActivityForResult(intent, READ_FOLDER_REQUEST_CODE);
    }

    // 选取文件夹然后在文件夹中创建子文件夹和文件
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data == null || resultCode != RESULT_OK) return;
        if (requestCode == READ_FOLDER_REQUEST_CODE) {
            Log.d("tianjf", "read folder uri : " + data.getData());
            DocumentFile selectedFolder = DocumentFile.fromTreeUri(this, data.getData());
            DocumentFile newFolder = selectedFolder.createDirectory("newFolder");
            DocumentFile newFile = newFolder.createFile("text/plain", "test.txt");
            try {
                getContentResolver().openOutputStream(newFile.getUri()).write("Hello".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

原文作者:teletian
链接:https://www.jianshu.com/p/026b8dd9f79e

Android 10 分区存储完全解析 Android 10分区存储完全解析一、Android 存储目录1.1 内部存储1.2 外部存储1.2.1 外部私有存储1.2.2 外部公共存储1.3 使用Api 获取存储目录二、Android 10 分区存储机制2.1 原则2.2 分区存储概览2.2.1 外部共享文件的访问2.2.2 外部私有文件的访问2.2.3 内部存储文件的访问2.2.4 其他受影响的变更2.2.5 存储特性Android版本差异三、分区存储适配方案3.1 兼容模式3.2 分区存储方案3.2.1 文件迁移3.2.2 文件访问兼容行适配 阅读详情

相关推荐

Android10及以上分区存储适配

android适配基本是每一次发布新版本都需要做的,从android6开始的动态权限申请、android7的下载安装适配,android8的通知、Toast适配,android9的https适配等等一系列的变化,从android10开始Google为了加强用户隐私(android有隐私吗?)提出了分区存储 分区存储: 对于以 Android 10 及更高版本为目标平台的应用,其访问权限范围限定为外部存储,即分区存储。此类应用可以查看外部存储设备内以下类型的文件,无需请求任何与存储相关的用户权限,说直白点

chengxuyuanchaochao的博客 892

android:requestLegacyExternalStorage解析

在Android使用fuse文件系统开始,Android针对外置存储支持了独立的沙箱存储空间, 一般通过Context.getExternalFilesDir() Api获取,该空间内的数据为应用独有,并且不需要申请任何权限即可使用。但是当时并没有限制应用读写非沙箱内的数据。但是从Android Q开始,出于数据隐私问题,Android 希望禁止应用程序操作非沙箱内的数据。 但是为了过度,Android提供了requestLegacyExternalStorage机制,来帮助应用使用原来的机制继续读写存储卡

冯旭的博客 1万+

Android-10分区存储介绍及百度APP适配实践

【Android 详细知识点思维脑图(技能树)】我个人是做Android开发,已经有十来年了,目前在某创业公司任职CTO兼系统架构师。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。

egrhef的博客 844

requestLegacyExternalStorage

工程 采用的sdk 为 29 , 第三方库 sdk为 28 , 测试机为android12 适配androidQ或者改低库sdk到28 关于分区存储,在Android10就已经推行了, 是应用对于文件的读写只能在沙盒环境,也就是属于自己应用的目录里面读写。其他媒体文件可以通过MediaStore进行访问。 但是在android10的时候,Google还是为开发者考虑。在targetSdkVersion = 29应用中,设置android:requestLegacyExternalStorage=.

介亭的博客 1万+

Android 10(Q)/11(R) 分区存储适配

作者:连续三届村草 Android 10(Q)/11® 分区存储适配 大部分应用都会请求 ( READ_EXTERNAL_STORAGE ) ( WRITE_EXTERNAL_STORAGE ) 存储权限,来做一些诸如在 SD 卡中存储文件或者读取多媒体文件等常规操作。这些应用可能会在磁盘中存储大量文件,即使应用被卸载了还会依然存在。另外,这些应用还可能会读取其他应用的一些敏感文件数据。 为此,Google 终于下定决心在 Android 10 中引入了分区存储,对权限进行场景的细分,按需索取,并在 A.

1 4579

总结系列-Android10适配(2)-分区存储

上篇介绍了Android10的部分适配总结,其中存储适配采用的为兼容模式,本篇单独介绍正常分区存储适配. Google于2019年9月3日发布了Android10 release版本,为了更好的保护用户数据并限制设备冗余文件增加,Android 10版本变更了设备外部存储访问方式,外部存储新特性称为分区存储(ScopedStorage),分区存储遵循以下三个原则对外部存储文件访问方式重新设计,便于用户更好的管理外部存储文件. (本篇主要总结,具体样例代码较多,参见末尾链接) 文件...

风离紫竹zhangqiang的博客 2213

Android 10分区存储权限变更及适配

一、前言 在Android 10中引入了分区储存功能,在外部存储设备中为每个应用提供了一个“隔离存储沙盒”。其他应用无法直接访问应用的沙盒文件。由于文件是应用的私有文件,不再需要任何权限即可访问和保存自己的文件。此变更并有助于减少应用所需的权限数量,同时保证用户文件的隐私性。 目标版本targetSdkVersion设置为28或更低版本以下时,我们对外部存储空间的读写访问需要READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE权限。 目标版本targetSdkVer

weixin_42046829的博客 6082

Android-10分区存储介绍及百度APP适配实践,Android开发教程

文章会持续更新的。绝对干货!!!GitHubAndroid进阶学习全套手册关于实战,我想每一个做开发的都有话要说,对于小白而言,缺乏实战经验是通病,那么除了在实际工作过程当中,我们如何去更了解实战方面的内容呢?实际上,我们很有必要去看一些实战相关的电子书。

m0_60607675的博客 753

安卓应用开发中 Android 10+ 分区存储问题详解

从 Android 10(API 29)开始,Google 引入了**分区存储(Scoped Storage)**机制,强制限制应用对外部存储的访问方式。以往通过 WRITE_EXTERNAL_STORAGE 权限直接读写文件路径(如 /sdcard/xxx.txt)的方式不再被允许,应用只能访问自己专属的目录(getExternalFilesDir 等)或通过 MediaStore、Storage Access Framework(SAF) 访问媒体文件。如果应用仍使用旧的直接路径访问方式,会在 Andr

深山技术宅的博客 1276

Android 10 存储模型->requestLegacyExternalStorage

在Android使用fuse文件系统开始,Android针对外置存储支持了独立的沙箱存储空间, 一般通过Context.getExternalFilesDir() Api获取,该空间内的数据为应用独有,并且不需要申请任何权限即可使用。但是当时并没有限制应用读写非沙箱内的数据。但是从Android Q开始,出于数据隐私问题,Android 希望禁止应用程序操作非沙箱内的数据。 但是为了过度,Android提供了requestLegacyExternalStorage机制,来帮助应用使用原来的机制继续读写存储卡

woai110120130的专栏 3万+

MATLAB安装

Matlab 2016a 安装包及破解教程百度云分享链接: 链接:https://pan.baidu.com/s/1i6BgD8p       密码:17gg   Matlab安装教程: 1、下载文件,得到R2016a_win64.part1.rar、R2016a_win64.part2.rar两部分安装文件和Matlab 2016a Win64 Crack破解文件。 2、解压安装文件(解...

qq_36734094的博客 17万+

Android 10分区存储

Android 10分区存储介绍及百度APP适配实践

shiningdreamercaihua的博客 1869

从零搭建ROS机械臂仿真环境:Ubuntu 20.04+Noetic下配置睿尔曼RM65的完整流程

本文详细介绍了在Ubuntu 20.04系统中,基于ROS Noetic搭建睿尔曼RM65机械臂的完整仿真环境。从环境准备、工作空间创建到MoveIt!配置与Gazebo仿真环境集成,提供了完整的流程和优化建议,帮助开发者高效实现机械臂仿真与调试。

v6b7n8m9q0的博客 934

Android 10 分区存储适配实战指南

本文是Android 10分区存储的实战适配指南。针对App升级后文件访问崩溃问题,详细解读了分区存储的核心规则与存储结构变化,并提供了从兼容模式、文件迁移到核心API(MediaStore与SAF)使用的完整解决方案,帮助开发者高效完成适配,保障用户数据安全。

weixin_29291185的博客 797

基于Simulink的前馈解耦SVPWM整流器仿真

本文提出了一种基于Simulink的前馈解耦SVPWM整流器仿真方案,针对传统双闭环控制存在的耦合严重、电压利用率低等问题进行优化。通过前馈补偿dq轴耦合项(ωLiq和ωLid)结合SVPWM调制算法,实现了电流跟踪误差<3%、电压利用率达0.99、THD<3%的性能指标。文章详细阐述了系统架构设计,包括前馈解耦原理推导、SVPWM算法实现步骤,并提供了完整的Simulink建模方法。仿真结果表明,该方案在动态响应速度(25ms)和直流电压纹波(1.1%)方面显著优于传统SPWM控制。同时给出了

MHD0815的博客 164

Oracle数据库安装及配置(Oracle19c)

Windows 10安装Oracle 19c教程

weixin_69200200的博客 2万+

Android 10分区存储介绍及百度APP适配实践

背景 丨1. 分区存储背景介绍 Google于2019年9月3日发布了Android10 release版本,为了更好的保护用户数据并限制设备冗余文件增加,Android 10版本变更了设备外部存储访问方式,外部存储新特性称为分区存储(ScopedStorage),分区存储遵循以下三个原则对外部存储文件访问方式重新设计,便于用户更好的管理外部存储文件 1.1 文件更好的归属: 系统...

weixin_29237635的博客 1252

BRep实战指南:从理论到文件格式的全面解析

本文全面解析BRep(边界表示法)从基础概念到文件格式的实战应用。详细介绍了BRep的数学定义、工业应用场景,以及STEP、IGES等主流文件格式的对比与使用技巧,帮助读者掌握三维建模核心技术并优化性能。

weixin_29235923的博客 410

轻松适配Android 10 Scoped Storage 分区存储

Android 10(API 级别 29)引入了多项功能和行为变更,目的是更好地保护用户的隐私权。其中最重要的变化之一就是存储访问权限。 Android 10中,Google针对外部存储引入了一个新特性,它的名字叫:Scoped Storage,Google官方对它的翻译为分区存储,我们也可以把它叫做作用域存储,至于为什么? 本文中,我们还是将它翻译为分区存储。好了,我要开始提问了! 问题一、...

HurryYu的博客 4322

Transformers 实战修炼与源码剖析专栏大纲

本专栏以 Hugging Face Transformers 为主线,围绕“能用、会调、敢上线、懂源码”四个目标展开。内容不把理论堆成公式墙,而是用真实或拟真的业务场景驱动:客服分类、合同抽取、知识库问答、模型微调、推理服务、监控告警、源码扩展等。采用“业务痛点 → 三人剧本对话 → 代码实战 → 总结思考”的四段式结构,让读者在动手完成一个个小项目的过程中,逐步理解 Tokenizer、Model、Pipeline、Trainer、Generation、PEFT、Accelerate、Serving等概念

davidwang456的专栏 926

innovus:NRDB-2276 special net route layer与NanoRouteMode route layer冲突问题解决方法

NanoRouteMode中设置绕线层次2-6,但是被动到的special net有8-11的preferred route layer,这个层次可能是create_route_type+set_ccopt_property -net_type 定义的。二者绕线层次范围有冲突,导致在调整过这条net后再绕线就会提示失败。然后再下route_design 等route命令去绕别的net。我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?

m0_61544122的博客 1105

android分区大小限制,Android10 分区存储的适配规则

存储权限Android Q 仍然使用 READ_EXTRNAL_STORAGE 和 WRITE_EXTRNAL_STORAGE 作为存储相关运行时权限 但现在即使获取了这些权限,访问外部存储也受到了限制,只能访问自身目录下的文件和公共体内的文件内部存储 外部存储内部存储外部存储备注英文名称Internal storageExternal storage版本变更不变4.4之前,外部存储仅仅代表SD卡...

weixin_31733409的博客 846

【Go语言实战】(2) Gin+Vue 电子商城

618来!!不用纠结去哪里剁手了!直接自己安排一个商场不香吗??

面向生活编程 4827
上一篇: 推特证明求职的尽头是被裁?Android工程师们小心了
下一篇: Android 一种点赞动画的实现
不秃头de程序猿
博客等级 码龄5年 4089粉丝 1478原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值