精华内容
下载资源
问答
  • 现在我们知道了,数据库存储位置了,你以为这就是我写这篇博客的目的?继续往下看吧,嘿嘿。 如果我不想再手机系统内存中保存数据库,而是想将我的数据库放在手机sd卡中,那应该怎么做呢。 首先,我在...

    转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/46467495

    我们都知道,android为了操作数据库,一般是继承SQLiteOpenHelper类,并实现他的三个函数。

    如下所示:

    package jz.his.db;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;
    import android.database.sqlite.SQLiteOpenHelper;
    
    public class MessageDataBase extends SQLiteOpenHelper {
    
    	public MessageDataBase(Context context, String name, CursorFactory factory,
    			int version) {
    		super(context, name, factory, version);
    	}
    
    	@Override
    	public void onCreate(SQLiteDatabase db) {
    		db.execSQL("create table lgx_table(_id integer primary key autoincrement ," +
    				"name varchar(20),content varchar(40),time varchar(20) ,head varchar(20),isCheck byte)");
    	}
    
    	@Override
    	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    	}
    
    }
    
    </pre><p>可以看到创建了一个名为lgx_table的表,里面有一id,name,content等列。</p><p></p>然后在Activity里,通过getWritableDatabase或者getReadableDatabase()方法来实例化一个SQLiteDatabase<p></p><p></p><pre name="code" class="java">MessageDataBase	messageDataBase = new MessageDataBase(context, "lgx", null, 1);
    		SQLiteDatabase database = messageDataBase.getWritableDatabase();


    我们可以看到,创建了一个名字为“lgx”的数据库。


    这里提出一个问题,通过以上的步骤后,数据库保存在哪里了呢?


    数据库保存在data/data/[your packageName]/databses,

    1.如果是模拟器,直接通过Eclipse下,通过这样的步骤去看  DBMS--->File Explorer-->data---->data--->your packageName


    
    

    网上很多介绍,我这里不介绍。

    2.如果是真机,首先这个真机是root过了,下载一个Root Explorer。我的测试机是华为荣耀3c。

    当我们执行完了以上的步骤后,进入data/data/jz.his.jzhis/databases/会看到这样的情景。

    其实lgx就是我们刚刚创建的数据库,lgx-journal是数据库日志。

    现在我们知道了,数据库存储的位置了,你以为这就是我写这篇博客的目的?继续往下看吧,嘿嘿。

    如果我不想再手机系统内存中保存数据库,而是想将我的数据库放在手机sd卡中,那应该怎么做呢。

    首先,我在res/raw中放一个现成的数据库,待会在代码里,将它拷入手机sd卡中。

    看下面的代码:

    package com.example.province;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;
    import android.database.sqlite.SQLiteException;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.os.Environment;
    
    public class CopyOfCityInfoDataSupport2 {
    	private static CopyOfCityInfoDataSupport2 cityInfoDataSupport;
    	/**
    	 * 数据库在手机里的路径
    	 */
    	private static String DATABASE_PATH = Environment
    			.getExternalStorageDirectory() + "/aaaaa/";
    	/**
    	 * 数据库的名称
    	 */
    	public static final String dbName = "mzk_db";
    	private SQLiteDatabase mSDB;
    
    	public static CopyOfCityInfoDataSupport2 getInstance(Context context) {
    		initDataBase(context);
    		if (cityInfoDataSupport == null) {
    			cityInfoDataSupport = new CopyOfCityInfoDataSupport2();
    		}
    		return cityInfoDataSupport;
    
    	}
    
    	/**
    	 * 初试化数据库
    	 */
    	private static void initDataBase(Context context) {
    		boolean dbExist = checkDataBase();
    		if (dbExist) {
    
    		} else {
    			// 如果不存在,则将raw里的数据存入手机sd卡
    			copyDataBase(context);
    		}
    	}
    
    	/**
    	 * 复制数据库到手机指定文件夹下
    	 * 
    	 * @throws IOException
    	 */
    	private static void copyDataBase(Context context) {
    		String databaseFilenames = DATABASE_PATH + dbName;
    		File dir = new File(DATABASE_PATH);
    		FileOutputStream os = null;
    		InputStream is = null;
    		// 判断文件夹是否存在,不存在就创建一个
    		if (!dir.exists()) {
    			dir.mkdirs();
    		}
    		try {
    			// 得到数据库的输出流
    			os = new FileOutputStream(databaseFilenames);
    			// 得到数据文件的输入流
    			is = context.getResources().openRawResource(R.raw.mzk_db);
    			byte[] buffer = new byte[8192];
    			int count = 0;
    			while ((count = is.read(buffer)) != -1) {
    				os.write(buffer, 0, count);
    				os.flush();
    			}
    			// 之所以不在这里初始化,是因为这边是静态的方法,而mSDB并没有设置为静态的,也不推荐设为静态的
    			// mSDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH +
    			// dbName, null);
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				os.close();
    				is.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    
    		}
    
    	}
    
    	/**
    	 * 判断数据库是否存在
    	 * 
    	 * @return
    	 */
    	private static boolean checkDataBase() {
    		SQLiteDatabase checkDB = null;
    		String databaseFilename = DATABASE_PATH + dbName;
    		// 要自己加上try catch方法
    		try {
    			// 返回最新的数据库
    			checkDB = SQLiteDatabase.openDatabase(databaseFilename, null,
    					SQLiteDatabase.OPEN_READONLY);
    		} catch (SQLiteException e) {
    			// TODO: handle exception
    		}
    
    		if (checkDB != null) {
    			checkDB.close();
    		}
    		// 如果checkDB为null,则没有数据库,返回false
    		return checkDB == null ? false : true;
    	}
    
    	/**
    	 * 查询所有省份的信息
    	 * 
    	 * @return 省份信息
    	 */
    	public ArrayList<City> queryProvince() {
    		// 创建数据库的实例
    		mSDB = SQLiteDatabase
    				.openOrCreateDatabase(DATABASE_PATH + dbName, null);
    		ArrayList<City> list = new ArrayList<City>();
    		String sql = "select * from fs_province";
    		Cursor cursor = mSDB.rawQuery(sql, null);
    		while (cursor.moveToNext()) {
    			City city = new City();
    			String id = cursor.getString(cursor.getColumnIndex("ProvinceID"));
    			String name = cursor.getString(cursor
    					.getColumnIndex("ProvinceName"));
    			city.setName(name);
    			city.setId(id);
    			list.add(city);
    		}
    		if (cursor != null) {
    			cursor.close();
    		}
    		return list;
    	}
    
    
    	public void closeDataBase() {
    		if (mSDB != null) {
    			mSDB.close();
    		}
    	}
    }
    


    我们看到,如果将数据库写到手机sd卡中,都不需要SQLiteOpenHelper类了,而是直接通过

    mSDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH + dbName, null);就可以获得数据库的实例了。


    但是这个方法有个缺点,就是不能进行数据库的升级了。显然这样是非常不好的。

    那么如果我们还想用SQLiteOpenHelper,又将其写到sd卡中,又该怎么做呢。

    下面的这段代码是有错误的,你只需要注意看51行,正是因为下面的代码,我才研究了onCreate方法到底什么时候执行。

    package jz.his.db;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    
    import jz.his.jzhis.R;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteException;
    import android.database.sqlite.SQLiteOpenHelper;
    import android.os.Environment;
    import android.util.Log;
    
    
    
    public class CityInfoDataSupport extends SQLiteOpenHelper
    {
        private final static String TAG = "CityInfoDataSupport";
        public static final String dbName = "cityego";
        // 数据库在手机里的路径
        private static String DATABASE_PATH = Environment
    			.getExternalStorageDirectory().getAbsolutePath()+"/com.bcinfo.pwzs/";
        private static int version = 1;
        private final String GEOCODING_TABLE_NAME = "GEOCODING";
        private SQLiteDatabase mSDB = getReadableDatabase();
        private static CityInfoDataSupport mDataSupport;
        Context context;
    
        public static CityInfoDataSupport getInstance(Context context)
        {
            initDatabse(context);
            
            if (mDataSupport == null)
            {
                mDataSupport = new CityInfoDataSupport(context);
            }
            return mDataSupport;
        }
    
        CityInfoDataSupport(Context context)
        {
        	
            super(context, DATABASE_PATH+dbName, null, version);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db)
        {
            executeAssetsSQL(db, "geocoding_create.sql");
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
        {
            String sql = "drop table if exits " + GEOCODING_TABLE_NAME;
            db.execSQL(sql);
            onCreate(db);
        }
    
        private void loadSql(SQLiteDatabase db, String schemaName)
        {
            InputStream inputS;
            try
            {
               inputS = context.getAssets().open(schemaName);
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputS));
                String sql = null;
                while ((sql = reader.readLine()) != null)
                {
                    db.execSQL(sql.replace(";", ""));
                }
                reader.close();
                reader = null;
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        /**
         * 读取数据库文件(.sql),并执行sql语句
         * */
        private void executeAssetsSQL(SQLiteDatabase db, String schemaName)
        {
            Log.e("DataSupport", "executeAssetsSQL");
            BufferedReader in = null;
            try
            {
                in = new BufferedReader(new InputStreamReader(context.getAssets().open(schemaName)));
                String line;
                String buffer = "";
                while ((line = in.readLine()) != null)
                {
                    buffer += line;
                    if (line.trim().endsWith(";"))
                    {
                        db.execSQL(buffer.replace(";", ""));
                        buffer = "";
                    }
                }
            }
            catch (IOException e)
            {
                Log.e("db-error", e.toString());
            }
            finally
            {
                try
                {
                    if (in != null)
                        in.close();
                }
                catch (IOException e)
                {
                    Log.e("db-error", e.toString());
                }
            }
        }
    
        public synchronized void insertCityInfo()
        {
            loadSql(mSDB, "geocoding_data.txt");
        }
    
        public synchronized List<City> queryDataById(String field, String id)
        {
            String sql = "";
            List<City> cityList = new ArrayList<City>();
            if (field.equals("grade"))
            {
                sql = "select * from  " + GEOCODING_TABLE_NAME + "  where grade = ? ";
            }
            else if (field.equals("parent"))
            {
                sql = "select * from  " + GEOCODING_TABLE_NAME + "  where parent = ? ";
            }
            String[] params = new String[]
            { id };
            Cursor c = mSDB.rawQuery(sql, params);
            while (c.moveToNext())
            {
                City city = new City();
                city.setGbCode(c.getString(c.getColumnIndex("gbcode")));
                city.setGbName(c.getString(c.getColumnIndex("gbname")));
                city.setGrade(c.getString(c.getColumnIndex("grade")));
                city.setLongitude(c.getString(c.getColumnIndex("longtitude")));
                city.setLatitude(c.getString(c.getColumnIndex("latitude")));
                city.setParent(c.getString(c.getColumnIndex("parent")));
                cityList.add(city);
            }
            if (c != null)
            {
                c.close();
            }
            return cityList;
        }
    
        public void deleteAppTempTraffic()
        {
            String sql = "delete from " + GEOCODING_TABLE_NAME;
            mSDB.execSQL(sql);
        }
    
        public static void initDatabse(Context cntext)
        {
            boolean dbExist = checkDataBase();
            //判断数据库是否存在 不存在就把raw里的数据库写入手机
            if (!dbExist)
            {
                try
                {
                    copyDataBase(cntext);
                }
                catch (IOException e)
                {
                    throw new Error("Error copying database");
                }
            }
        }
    
        /**
         * 判断数据库是否存在
         * @return false or true
         */
        public static boolean checkDataBase()
        {
            SQLiteDatabase checkDB = null;
            try
            {
                String databaseFilename = DATABASE_PATH + dbName;
                checkDB = SQLiteDatabase.openDatabase(databaseFilename, null, SQLiteDatabase.OPEN_READONLY);
            }
            catch (SQLiteException e)
            {
            }
            if (checkDB != null)
            {
                checkDB.close();
            }
            return checkDB != null ? true : false;
        }
    
        /**
         * 复制数据库到手机指定文件夹下
         * @throws IOException
         */
        public static void copyDataBase(Context context) throws IOException
        {
            String databaseFilenames = DATABASE_PATH + dbName;
            File dir = new File(DATABASE_PATH);
            FileOutputStream os = null;
            // 判断文件夹是否存在,不存在就新建一个
            if (!dir.exists())
            {
                dir.mkdirs();
            }
            try
            {
                // 得到数据库文件的写入流
                os = new FileOutputStream(databaseFilenames);
            }
            catch (FileNotFoundException e)
            {
                e.printStackTrace();
            }
            // 得到数据库文件的数据流
            InputStream is = context.getResources().openRawResource(R.raw.cityego);
            byte[] buffer = new byte[8192];
            int count = 0;
            try
            {
                while ((count = is.read(buffer)) > 0)
                {
                    os.write(buffer, 0, count);
                    os.flush();
                }
            }
            catch (IOException e)
            {
            }
            try
            {
                is.close();
                os.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    

    通过上面的这个代码,我的onCreate方法一直没有执行。最终经过我多次试验,我知道了问题所在,所以在这里进行总结。


    那么onCreate方法到底什么时候执行呢?

    SQLiteOpenHelper的onCreate方法一定是在getReadableDatabase方法之后的

    SQLiteDatabase mSDB = getReadableDatabase()这个方法首先检查手机中,是否有已经存在的数据库,如果没有,则执行onCreate方法,如果有,则不执行---->但是,这里有个前提是,你的supre(context, DATABASE_PATH+dbName, null, version),的第二个参数不能是已存在的数据库路径。

    我这里,将第二个参数,弄成了已存在的数据库文件,所以onCreate方法永远不会执行。


    那么当super(context, dbName, null, version);第二个参数正确和并且执行了getReadableDatabase这个方法,才会在系统内存有数据库。


    折磨了我一个下午啊啊啊啊。



    展开全文
  • Android 文件存储位置梳理

    千次阅读 2019-03-07 00:21:55
    所有的安卓设备都有外部存储和内部存储,这两个名称来源于安卓的早期设备,那个时候的设备内部存储确实是固定的,而外部存储确实是可以像U盘一样移动的。 在后来的设备中,很多中高端机器都将自己的机身存储扩展到...

          所有的安卓设备都有外部存储和内部存储,这两个名称来源于安卓的早期设备,那个时候的设备内部存储确实是固定的,而外部存储确实是可以像U盘一样移动的。

          在后来的设备中,很多中高端机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal" 和"外部external" 两部分,但其实都在手机内部。所以不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。最关键的是,我们都是通过相同的api来访问可移动的sdcard或者手机自带的存储(外部存储)。

         外部存储虽然概念上有点复杂,但也很好区分,你把手机连接电脑,能被电脑识别的部分就一定是外部存储。

         从逻辑意义上来说,data 目录就是就是就是手机的内部存储,而 mnt 或者 storage 目录下的sdcard目录就是外部存储。如果是手机内存的外部存储被称为机身外部存储,外置的SD卡则称之为外部存储。

    Android下有哪些文件目录

    在Android系统中,根据调用的系统API接口,有3种目录可以给我们写入文件:

    一,应用私有存储(内部存储)

       1,获取方式:

       Context.getFileDir():获取内置存储下的文件目录,可以用来保存不能公开给其他应用的一些敏感数据如用户个人信息。

       Context.getCacheDir():获取内置存储下的缓存目录,可以用来保存一些缓存文件如图片,当内置存储的空间不足时将系统自动被清除。

       2,绝对路径:

        Context.getFileDir():/data/data/应用包名/files/[6.0以下]

                           /data/user/0/应用包名/files/[6.0以上]=[Cocos2dx下的getWritablePath()]

        Context.getCacheDir():/data/data/应用包名/cache/[6.0以下]

                        /data/user/0/应用包名/cache/[6.0以上]

      3,写权限:不需要申请。

        这是手机的内置存储,没有root的过的手机是无法用文件管理器之类的工具查看的。而且这些数据也会随着用户卸载App而被一起删除。这两个目录其实就对应着设置->应用->你的App->存储空间下面的清除数据清楚缓存,如下图所示。

      

    二,应用扩展存储(内置的外部存储)

        1,获取方式:

            Context.getExternalFilesDir()获取内置外部存储上的文件目录。

            Context.getExternalCacheDir()获取内置外部存储上的缓存目录。

         2,绝对路径:

            Context.getExternalFilesDir()SDCard/Android/data/应用包名/files/

            Context.getExternalCacheDir()SDCard/Android/data/应用包名/cache/

          3,写权限:API < 19:需要申请;API >= 19:不需要申请。

               "android.permission.WRITE_EXTERNAL_STORAGE";

               "android.permission.READ_EXTERNAL_STORAGE"

               Also starting in API level 19, this permission is not required to read/write files in your application-specific directories returned by getExternalFilesDir(String) and getExternalCacheDir().

              Android 6.0以后系统,就不再需要用户授权了。

          同上面一样的,这里的文件会随着App卸载而被删除,也可以由用户手动在设置界面里面清除。既然是SD卡上的目录,那么是可以被其他的应用读取到的,所以这个目录下,不应该存放用户的敏感信息。

         清除缓存:删除缓存数据,即getCacheDir()与getExternalCacheDir()。
         清除数据:删除所有数据,即getFilesDir()、getCacheDir()、getExternalFilesDir(null)、getExternalCacheDir()。
     

    三,公共存储(SD卡外部存储)

         1,获取方式:

            Environment.getExternalStorageDirectory()

         2,绝对路径:SDCard/你设置的文件夹名字/

         3,写权限:需要申请。

         如果我们的App需要存储一些公共的文件,甚至希望下载下来的文件即使在我们的App被删除之后,还可以被其他App使用,那么就可以使用这个目录。这个目录是始终需要申请SD写入权限的。

     

     

    感谢原作者的辛勤劳作:

       https://www.cnblogs.com/slyfox/p/9584388.html

       http://unclechen.github.io/2016/03/06/Android6.0权限适配之SD卡写入/

       https://blog.csdn.net/ruancoder/article/details/54290807

    展开全文
  • android文件存储位置切换

    千次阅读 2015-01-12 13:27:20
    最近有个需求,助手的google卫星地图和OpenCycleMap下载的离线地图数据,要能够在内置存储和外置存储空间之间切换,因为离线瓦片数据非常大,很多户外用户希望将这些文件存储在外置TF卡上,不占用内置存储空间,所以...

     最近有个需求,助手的google卫星地图和OpenCycleMap下载的离线地图数据,要能够在内置存储和外置存储空间之间切换,因为离线瓦片数据非常大,很多户外用户希望将这些文件存储在外置TF卡上,不占用内置存储空间,所以把最近研究的整理了下,分享给大家。

      需要考虑和遇到的问题(主要是不同手机、不同系统的兼容性):

      1.这样获取手机所有挂载的存储器?

       Android是没有提供显式的接口的,首先肯定是要阅读系统设置应用“存储”部分的源码,看存储那里是通过什么方式获取的。最后找到StorageManager和StorageVolume这2个重要的类,然后通过反射获取StorageVolume[]列表。

      2.用什么标示一个存储器的唯一性?

       存储路径?不行(有些手机不插TF卡,内置存储路径是/storage/sdcard0,插上TF卡后,内置存储路径变成/storage/sdcard1,TF卡变成/storage/sdcard0)。

       存储卡名称?不行(可能会切换系统语言,导致名称匹配失败,名称的resId也不行,较低的系统版本StorageVolume没有mDescriptionId这一属性)。

       经过测试,发现使用mStorageId可以标示存储器的唯一性,存储器数量改变,每个存储器的id不会改变。

      3.如何获得存储器的名称?

       经测试,不同的手机主要有3种获取存储器名换的方法:getDescription()、getDescription(Context context)、先获得getDescriptionId()再通过resId获取名称。

      4.任务文件下载一半时,切换文件保存存储器,怎么处理?

       有2种方案:

       4.1 切换时,如果新的存储空间足够所有文件转移,先停止所有下载任务,将所有下载完和下载中的文件拷贝到新的存储空间,然后再更新下载数据库下载任务的存储路径,再恢复下载任务;

       4.2 切换时,先拷贝所有下载完成的文件到新的存储空间,下载任务继续下载,下载完成再移动到新的存储空间。

      5.在4.4系统上,第三方应用无法读取外置存储卡的问题。(参考“External Storage”)

       google为了在程序卸载时,能够完全彻底的将程序所有数据清理干净,应用将不能向2级存储区域写入文件。

       “The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.”

       要能够在4.4系统上TF卡写入文件,必须先root,具体方法可以google。

       所以4.4系统上,切换会导致文件转移和下载失败,用户如果要切换到TF卡,至少需要提醒用户,并最好给出4.4上root解决方法。

      以下是获取存储器的部分代码:

    public static class MyStorageVolume{
            public int mStorageId;
            public String mPath;
            public String mDescription;
            public boolean mPrimary;
            public boolean mRemovable;
            public boolean mEmulated;
            public int mMtpReserveSpace;
            public boolean mAllowMassStorage;
            public long mMaxFileSize;  //最大文件大小。(0表示无限制)
            public String mState;      //返回null
    
            public MyStorageVolume(Context context, Object reflectItem){
                try {
                    Method fmStorageId = reflectItem.getClass().getDeclaredMethod("getStorageId");
                    fmStorageId.setAccessible(true);
                    mStorageId = (Integer) fmStorageId.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fmPath = reflectItem.getClass().getDeclaredMethod("getPath");
                    fmPath.setAccessible(true);
                    mPath = (String) fmPath.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fmDescriptionId = reflectItem.getClass().getDeclaredMethod("getDescription");
                    fmDescriptionId.setAccessible(true);
                    mDescription = (String) fmDescriptionId.invoke(reflectItem);
                } catch (Exception e) {
                }
                if(mDescription == null || TextUtils.isEmpty(mDescription)){
                    try {
                        Method fmDescriptionId = reflectItem.getClass().getDeclaredMethod("getDescription");
                        fmDescriptionId.setAccessible(true);
                        mDescription = (String) fmDescriptionId.invoke(reflectItem, context);
                    } catch (Exception e) {
                    }
                }
                if(mDescription == null || TextUtils.isEmpty(mDescription)){
                    try {
                        Method fmDescriptionId = reflectItem.getClass().getDeclaredMethod("getDescriptionId");
                        fmDescriptionId.setAccessible(true);
                        int mDescriptionId = (Integer) fmDescriptionId.invoke(reflectItem);
                        if(mDescriptionId != 0){
                            mDescription = context.getResources().getString(mDescriptionId);
                        }
                    } catch (Exception e) {
                    }
                }
    
                try {
                    Method fmPrimary = reflectItem.getClass().getDeclaredMethod("isPrimary");
                    fmPrimary.setAccessible(true);
                    mPrimary = (Boolean) fmPrimary.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fisRemovable = reflectItem.getClass().getDeclaredMethod("isRemovable");
                    fisRemovable.setAccessible(true);
                    mRemovable = (Boolean) fisRemovable.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fisEmulated = reflectItem.getClass().getDeclaredMethod("isEmulated");
                    fisEmulated.setAccessible(true);
                    mEmulated = (Boolean) fisEmulated.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fmMtpReserveSpace = reflectItem.getClass().getDeclaredMethod("getMtpReserveSpace");
                    fmMtpReserveSpace.setAccessible(true);
                    mMtpReserveSpace = (Integer) fmMtpReserveSpace.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fAllowMassStorage = reflectItem.getClass().getDeclaredMethod("allowMassStorage");
                    fAllowMassStorage.setAccessible(true);
                    mAllowMassStorage = (Boolean) fAllowMassStorage.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fMaxFileSize = reflectItem.getClass().getDeclaredMethod("getMaxFileSize");
                    fMaxFileSize.setAccessible(true);
                    mMaxFileSize = (Long) fMaxFileSize.invoke(reflectItem);
                } catch (Exception e) {
                }
    
                try {
                    Method fState = reflectItem.getClass().getDeclaredMethod("getState");
                    fState.setAccessible(true);
                    mState = (String) fState.invoke(reflectItem);
                } catch (Exception e) {
                }
            }
    
            /**
             * 获取Volume挂载状态, 例如Environment.MEDIA_MOUNTED
             */
            public String getVolumeState(Context context){
                return StorageVolumeUtil.getVolumeState(context, mPath);
            }
    
            public boolean isMounted(Context context){
                return getVolumeState(context).equals(Environment.MEDIA_MOUNTED);
            }
    
            public String getDescription(){
                return mDescription;
            }
    
            /**
             * 获取存储设备的唯一标识
             */
            public String getUniqueFlag(){
                return "" + mStorageId;
            }
    
            /*public boolean isUsbStorage(){
                return mDescriptionId == android.R.string.storage_usb;
            }*/
    
            /**
             * 获取目录可用空间大小
             */
            public long getAvailableSize(){
                return StorageVolumeUtil.getAvailableSize(mPath);
            }
    
            /**
             * 获取目录总存储空间
             */
            public long getTotalSize(){
                return StorageVolumeUtil.getTotalSize(mPath);
            }
    
            @Override
            public String toString() {
                return "MyStorageVolume{" +
                        "\nmStorageId=" + mStorageId +
                        "\n, mPath='" + mPath + '\'' +
                        "\n, mDescription=" + mDescription +
                        "\n, mPrimary=" + mPrimary +
                        "\n, mRemovable=" + mRemovable +
                        "\n, mEmulated=" + mEmulated +
                        "\n, mMtpReserveSpace=" + mMtpReserveSpace +
                        "\n, mAllowMassStorage=" + mAllowMassStorage +
                        "\n, mMaxFileSize=" + mMaxFileSize +
                        "\n, mState='" + mState + '\'' +
                        '}' + "\n";
            }
        }
    
    存储信息MyStorageVolume

    public static List<MyStorageVolume> getVolumeList(Context context){
            List<MyStorageVolume> svList = new ArrayList<MyStorageVolume>(3);
            StorageManager mStorageManager = (StorageManager)context
                    .getSystemService(Activity.STORAGE_SERVICE);
            try {
                Method mMethodGetPaths = mStorageManager.getClass().getMethod("getVolumeList");
                Object[] list = (Object[]) mMethodGetPaths.invoke(mStorageManager);
                for(Object item : list){
                    svList.add(new MyStorageVolume(context, item));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return svList;
        }
    
    获取所有存储器

    github上的测试例子:

    https://github.com/John-Chen/BlogSamples/tree/master/StorageTest

      

    如果还有什么地方没有考虑到的,欢迎讨论。  

    其他精彩文章文章

    android学习笔记(41)android选项菜单和子菜单(SubMenu )

    android学习笔记(40)Notification的功能与用法

    android学习笔记(42)android使用监听器来监听菜单事件

    android学习笔记(43)android创建单选菜单和复选菜单

     jQuery教程(12)-ajax操作之基于请求加载数据

     jQuery教程(13)-ajax操作之追加 HTML

    更多关于android开发文章


    展开全文
  • Android中的文件存储位置分析

    千次阅读 2017-01-09 17:26:19
    应用开发过程中,避免不了需要使用到文件存储。Android在不同的系统版本中,对存储空间的使用限制会有所不同。如在6.0以上版本,对于外置存储空间的使用,需要动态申请权限,而6.0以下则不需要。不同的存储路径同样...
    应用开发过程中,避免不了需要使用到文件存储。Android在不同的系统版本中,对存储空间的使用限制会有所不同。如在6.0以上版本,对于外置存储空间的使用,需要动态申请权限,而6.0以下则不需要。不同的存储路径同样也会有区别。如内置存储空间无需权限申请可直接使用,而外置存储空间则可能会需要相应的权限。

    在存储文件或缓存数据时,我们需要尽量做到以下几点:
    (1).不要随意占用用户的内置存储。
    (2).不要随意在SD卡上新建目录,应该放置自己应用包名对应的扩展存储目录下,这样卸载App时可以被自动清除。
    (3).对占用的磁盘空间有上限,并按照一定的策略进行清除。

    文件存储的位置

    一般情况下,在Android系统中,有以下3种目录提供给开发者用来存储文件。

    1.应用程序私有存储空间
    该存储空间在内置存储中,无需申请权限即可使用。
    context.getFilesDir();
    描述:获取内置存储下的文件目录,可以用来保存不能公开给其他应用的一些敏感数据如用户个人信息。
    路径:在6.0以下版本中为/data/data/<package_name>/files/,6.0以上版本中为/data/user/0/<package_name>/files。

    context.getCacheDir();
    描述:获取内置存储下的缓存目录,可以用来保存一些缓存文件如图片,当内置存储的空间不足时将被系统自动清除。
    路径:在6.0以下版本中为/data/data/<package_name>/cache/,6.0以上版本中为/data/user/0/<package_name>/cache。

    在开发中,尽量不要占用该存储空间,当检测到手机未安装SDCard时再考虑使用。由于是在手机内置存储中,如果手机未获取root权限,那么文件浏览器是无法访问的。当应用程序被卸载时,这里的数据会一起被删除。

    2.应用程序扩展存储空间
    该存储空间在外置存储中,当API<19(android4.4)时,需要申请权限;当API>=19时,无需申请权限。
    context.getExternalFilesDir(String type);
    描述:获取SDCard上的文件目录。参数type可为空,此时获取的是根目录。
    路径:<sdcard_path>/Android/data/<package_name>/files/

    context.getExternalCacheDir();
    描述:获取SDCard上的缓存目录。
    路径:<sdcard_path>/Android/data/<package_name>/cache/

    如图所示:


    由于SDCard可以被所有的应用程序读取到,所以在这里不要存放用户敏感数据。如果仅仅是简单的缓存任务,如图片的缓存,我们可以选择使用该路径。这里的文件同样会随着应用程序的卸载而被删除。

    3.公共存储空间
    该存储空间在外置存储中,必须要申请权限才能使用。
    Environment.getExternalStorageDirectory();
    描述:获取SDCard根目录。
    路径: <sdcard_path>/

    有时候我们需要存储一些公共文件,并且希望这些文件在应用程序被删除后依旧存在,如用户下载的视频、音乐等,可以使用该目录。


    上述3种存储目录中,应用程序的私有存储空间和扩展存储空间(即1和2),可以由用户手动清除。在系统设置中,找到应用程序的存储管理,可以看到如下界面:


    清除缓存:删除缓存数据,即getCacheDir()与getExternalCacheDir()。
    清除数据:删除所有数据,即getFilesDir()、getCacheDir()、getExternalFilesDir(null)、getExternalCacheDir()。


    存储权限的申请

    在Android6.0之前的系统版本中,只要在清单文件中申请了下面两个权限,就可以在SDCard上进行文件的读写操作了。
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    而在6.0之后的版本中,由于动态权限的引入,需要在使用时动态去申请。
    private static final int REQUESTCODE_STORAGE = 1;
    
    public void checkPermission() {
        int permission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUESTCODE_STORAGE);
        } else {
            // your code
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        if (requestCode == REQUESTCODE_STORAGE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // your code
            }
        }
    }


    展开全文
  • 而且上面二个目录分别对应 设置->应用->应用详情里面的”清除数据“与”清除缓存“选项 如果要保存下载的内容,就不要放在以上目录下 -----------------------------------------------...
  • Android Studio修改AVD默认存储位置

    千次阅读 2018-12-11 16:52:50
    在进行操作之前,首先要了解一些名词及其作用,防止概念糊涂! SDK:    software development kit的简写, 软件开发...重启之后,打开Android Studio,下载一个AVD,看到这样的信息就说明成功了    
  • Android存储、上传、下载

    千次阅读 2017-12-06 15:03:51
    参考文章1、彻底理解android中的内部存储与外部存储2、谷歌官方文档参考1、 需求在android开发中常用的存储、上传、下载,之前反反复复写过很多遍,现在进行一些整理,方便后面直接搬运代码。尤其是在android7.0及...
  • 转自百度文库 安卓手机安装软件提示存储空间不足的解决方法    1.手机机身容量不足,而SD存储卡容量充足。  这种情况下,主要是机身容量满了,...还可以设置软件安装的位置,可以设定在安装在SD卡的,这样就不会
  • 很多android手机的内置存储空间不足,而相机等各类软件默认存储路径一般都是内置存储,经常用一阵子空间就不够了。有很多使用外置存储来扩展内置存储的方法,我提两个我用过的方法,抛砖引玉,给大家一个启发和参考...
  • 保存至本地存储空间时, 我们并不像保存至外置存储卡那么方便, 直接用一个Environment.getExternalStorageDirectory().getAbsolutePath()就搞掂. 保存至本地中还需要提前获知这个路径, 而这个路径根据不同的手机有的...
  • 在项目中需求把数据存储在本地,这样可以减少网络请求得次数。优化了用户交互。 看了H5+得文档后,首先我们得确定把文件存储在那个目录下。 文档有四个目录,我选择得是用PUBLIC_DOCUMENTS目录,把文件存放在这个...
  • Android手机缓存的位置

    千次阅读 2015-12-10 11:20:42
    比较老的手机,有一个手机内部存储,还有一个SD卡存储,就是分别对应这两种存储位置,因为以前的SD卡是可以扩展的,即可拆卸的,所以可以用是否可拆卸作为内外存储的分类标准。 但是现在最新的设备,比如小米、...
  •  首先明确,不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。最关键的是,我们都是通过相同的api来访问可移动的sdcard或者手机自带的存储(外部存储)。 外部存储虽然概念上有点复杂,但也很好...
  • 手机位置相关知识——HLR和VLR

    千次阅读 2014-09-23 17:56:03
    HLR(home location register)保存的是用户的基本信息,如你的SIM的卡号、手机号码、签约信息等,和动态信息,如当前的位置、是否已经关机等;VLR(visiting location register)保存的是用户的动态信息和状态信息,...
  • 最近在家办公,需要远程链接内网调试,but 公司的 vpn 账号只能单设备登录,只好...我按照电脑端 Charles 的提示,手机设置了代理 ip 和端口,然后手机浏览器搜索 chls.pro/ssl , 然后下载好了charles-proxy-ssl-p...
  • Android 文件外/内部存储的获取各种存储目录路径

    万次阅读 多人点赞 2018-06-12 14:51:50
    前言 对于任何一个应用来说,无论是PC端应用还是Android应用,存储肯定是必不可少的。对于很多做Android开发的同学来说,可能认为文件存储很简单,调用一些诸如getFilesDir,getExternalStorageDirectory方法行了,...
  • 支付宝小程序获取手机号码跟微信小程序的不一样,所以获取的流程也有很多的不同,所以第一步并不是直接写代码。 流程如下: 一、登录支付宝小程序开发管理平台 ->开发中心->小程序应用->选择你的小程序...
  • charles_https charles版本:v4.1.4 解决方法: 检查是否设置了锁屏密码,需要设置锁屏密码,并重启手机。再次访问chls.pro/ssl下载安装证书。 【已验证】 输入你的锁屏密码即可 。 ...
  • 谷歌Android手机默认只能把软件安装在手机内存里,使本来就不大的手机内存显得捉襟见肘。假如你也是个手机软件狂人,喜欢尝试各样新奇有趣的APK软件、APK游戏的朋友,面对越来越少的手机内存空间,不得不对已经安装...
  • OSS 存储服务,抓取系统logcat [包括异常]通过广播自动上传服务器
  • 彻底理解android中的内部存储与外部存储

    万次阅读 多人点赞 2015-12-12 10:05:34
    我们先来考虑这样一个问题:打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据,那么当我们点击清除缓存的时候清除的是哪里的数据?当我们点击清除数据的时候...
  • 1、封装下载文件的工具类 package com.ywb.tuyue.download; import android.content.Context; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import ...
  • 2、手机和电脑在同一个局域网内 2、设置 1.fiddler&amp;amp;amp;gt;Tools&amp;amp;amp;gt;Fiddler Options&amp;amp;amp;gt;Connections 勾选Allow remote computers to connect。 2.记住这里的端口号...
  • 第三章 存储

    千次阅读 2020-04-11 21:18:06
    SharedPreferences 用户偏好设置1.1)简介——Android最简单数据存储方式1.2)基本使用1.3)工具类——对SharedPreferences功能进行封装1.4)数据的存储位置与格式1.5)存取复杂类型数据1.6)设置数据文件的访问权限...
  • 手机软件工作原理

    千次阅读 2012-05-29 14:27:10
    手机软件工作原理(1) 手机的雏形十分类似于对讲机,最早出现在20世纪40年代,曾在第二次世界大战用于军事通话,是后来的“大哥大”的前身。哪个时候还没有手机软件的概念,手机上也没有任何增值的服务。...
  • 这些东西都是源自自己的需求,因为有一台小车,小车的多媒体系统是安卓的(联网),就自然装上了这个神器,关于位置和轨迹的想法一直没有间断,在这之前,有另一套旧的轨迹记录方案发表在酷安(酷安一点都不好用),...
  • 【Unity】unity3d 获取手机地理位置

    千次阅读 2016-11-30 11:03:18
    怎么用unity3d 获取手机地理位置呢?unity的某些场景中,如果需要定位地理位置的话,但是unity却没有提供相应的接口。对于安卓(这里举例,IOS暂没研究)这个时候只能用java写个获取地理位置的方法,然后与unity交互...
  • 1、环境准备 ...2、手机和电脑在同一个局域网内 2、设置 1.fiddler&amp;amp;amp;amp;gt;Tools&amp;amp;amp;amp;gt;Fiddler Options&amp;amp;amp;amp;gt;Co
  • 教程:建立自己的私有云存储

    千次阅读 2013-08-26 09:54:07
    现在更流行的词应该叫“云存储”,像用的比较多国外的有Dropbox、SkyDrive,国内也有百度云网盘、sina微盘、腾讯微云网盘等等,我们可以用这些网盘在不同的设备上来存储/获取数据,如PC、智能手机、平板电脑等等,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,692
精华内容 14,676
关键字:

如何设置下载存储位置手机